CrossSections.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2010 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <Standard_math.hxx>
00027 # include <BRep_Builder.hxx>
00028 # include <BRepAlgoAPI_Section.hxx>
00029 # include <BRepBuilderAPI_MakeWire.hxx>
00030 # include <TopoDS.hxx>
00031 # include <TopoDS_Compound.hxx>
00032 # include <TopExp_Explorer.hxx>
00033 # include <gp_Pln.hxx>
00034 # include <cfloat>
00035 # include <QFuture>
00036 # include <QFutureWatcher>
00037 # include <QtConcurrentMap>
00038 # include <boost/bind.hpp>
00039 # include <Inventor/nodes/SoBaseColor.h>
00040 # include <Inventor/nodes/SoCoordinate3.h>
00041 # include <Inventor/nodes/SoDrawStyle.h>
00042 # include <Inventor/nodes/SoFaceSet.h>
00043 # include <Inventor/nodes/SoLineSet.h>
00044 # include <Inventor/nodes/SoSeparator.h>
00045 #endif
00046 
00047 #include "ui_CrossSections.h"
00048 #include "CrossSections.h"
00049 #include <Mod/Part/App/PartFeature.h>
00050 #include <Mod/Part/App/CrossSection.h>
00051 #include <Gui/BitmapFactory.h>
00052 #include <Gui/ViewProvider.h>
00053 #include <Gui/Application.h>
00054 #include <Gui/Document.h>
00055 #include <Gui/View3DInventor.h>
00056 #include <Gui/View3DInventorViewer.h>
00057 #include <Base/Sequencer.h>
00058 
00059 using namespace PartGui;
00060 #undef CS_FUTURE // multi-threading causes some problems
00061 
00062 namespace PartGui {
00063 class ViewProviderCrossSections : public Gui::ViewProvider
00064 {
00065 public:
00066     ViewProviderCrossSections()
00067     {
00068         coords = new SoCoordinate3();
00069         coords->ref();
00070         planes = new SoLineSet();
00071         planes->ref();
00072         SoBaseColor* color = new SoBaseColor();
00073         color->rgb.setValue(1.0f, 0.447059f, 0.337255f);
00074         SoDrawStyle* style = new SoDrawStyle();
00075         style->lineWidth.setValue(2.0f);
00076         this->pcRoot->addChild(color);
00077         this->pcRoot->addChild(style);
00078         this->pcRoot->addChild(coords);
00079         this->pcRoot->addChild(planes);
00080     }
00081     ~ViewProviderCrossSections()
00082     {
00083         coords->unref();
00084         planes->unref();
00085     }
00086     void updateData(const App::Property*)
00087     {
00088     }
00089     const char* getDefaultDisplayMode() const
00090     {
00091         return "";
00092     }
00093     std::vector<std::string> getDisplayModes(void) const
00094     {
00095         return std::vector<std::string>();
00096     }
00097     void setCoords(const std::vector<Base::Vector3f>& v)
00098     {
00099         coords->point.setNum(v.size());
00100         SbVec3f* p = coords->point.startEditing();
00101         for (unsigned int i=0; i<v.size(); i++) {
00102             const Base::Vector3f& pt = v[i];
00103             p[i].setValue(pt.x,pt.y,pt.z);
00104         }
00105         coords->point.finishEditing();
00106         unsigned int count = v.size()/5;
00107         planes->numVertices.setNum(count);
00108         int32_t* l = planes->numVertices.startEditing();
00109         for (unsigned int i=0; i<count; i++) {
00110             l[i] = 5;
00111         }
00112         planes->numVertices.finishEditing();
00113     }
00114 
00115 private:
00116     SoCoordinate3* coords;
00117     SoLineSet* planes;
00118 };
00119 }
00120 
00121 CrossSections::CrossSections(const Base::BoundBox3d& bb, QWidget* parent, Qt::WFlags fl)
00122   : QDialog(parent, fl), bbox(bb)
00123 {
00124     ui = new Ui_CrossSections();
00125     ui->setupUi(this);
00126     ui->position->setRange(-DBL_MAX, DBL_MAX);
00127     vp = new ViewProviderCrossSections();
00128 
00129     Base::Vector3d c = bbox.CalcCenter();
00130     calcPlane(CrossSections::XY, c.z);
00131     ui->position->setValue(c.z);
00132 
00133     Gui::Document* doc = Gui::Application::Instance->activeDocument();
00134     view = qobject_cast<Gui::View3DInventor*>(doc->getActiveView());
00135     if (view) {
00136         view->getViewer()->addViewProvider(vp);
00137     }
00138 }
00139 
00140 /*  
00141  *  Destroys the object and frees any allocated resources
00142  */
00143 CrossSections::~CrossSections()
00144 {
00145     // no need to delete child widgets, Qt does it all for us
00146     delete ui;
00147     if (view) {
00148         view->getViewer()->removeViewProvider(vp);
00149     }
00150     delete vp;
00151 }
00152 
00153 CrossSections::Plane CrossSections::plane() const
00154 {
00155     if (ui->xyPlane->isChecked())
00156         return CrossSections::XY;
00157     else if (ui->xzPlane->isChecked())
00158         return CrossSections::XZ;
00159     else
00160         return CrossSections::YZ;
00161 }
00162 
00163 void CrossSections::changeEvent(QEvent *e)
00164 {
00165     if (e->type() == QEvent::LanguageChange) {
00166         ui->retranslateUi(this);
00167     }
00168     else {
00169         QDialog::changeEvent(e);
00170     }
00171 }
00172 
00173 void CrossSections::accept()
00174 {
00175     apply();
00176     QDialog::accept();
00177 }
00178 
00179 void CrossSections::apply()
00180 {
00181     std::vector<App::DocumentObject*> obj = Gui::Selection().
00182         getObjectsOfType(Part::Feature::getClassTypeId());
00183 
00184     std::vector<double> d;
00185     if (ui->sectionsBox->isChecked())
00186         d = getPlanes();
00187     else
00188         d.push_back(ui->position->value());
00189     double a=0,b=0,c=0;
00190     switch (plane()) {
00191         case CrossSections::XY:
00192             c = 1.0;
00193             break;
00194         case CrossSections::XZ:
00195             b = 1.0;
00196             break;
00197         case CrossSections::YZ:
00198             a = 1.0;
00199             break;
00200     }
00201 
00202 #ifdef CS_FUTURE
00203     Standard::SetReentrant(Standard_True);
00204     for (std::vector<App::DocumentObject*>::iterator it = obj.begin(); it != obj.end(); ++it) {
00205         Part::CrossSection cs(a,b,c,static_cast<Part::Feature*>(*it)->Shape.getValue());
00206         QFuture< std::list<TopoDS_Wire> > future = QtConcurrent::mapped
00207             (d, boost::bind(&Part::CrossSection::section, &cs, _1));
00208         future.waitForFinished();
00209         QFuture< std::list<TopoDS_Wire> >::const_iterator ft;
00210         TopoDS_Compound comp;
00211         BRep_Builder builder;
00212         builder.MakeCompound(comp);
00213 
00214         for (ft = future.begin(); ft != future.end(); ++ft) {
00215             const std::list<TopoDS_Wire>& w = *ft;
00216             for (std::list<TopoDS_Wire>::const_iterator wt = w.begin(); wt != w.end(); ++wt) {
00217                 if (!wt->IsNull())
00218                     builder.Add(comp, *wt);
00219             }
00220         }
00221 
00222         App::Document* doc = (*it)->getDocument();
00223         std::string s = (*it)->getNameInDocument();
00224         s += "_cs";
00225         Part::Feature* section = static_cast<Part::Feature*>
00226             (doc->addObject("Part::Feature",s.c_str()));
00227         section->Shape.setValue(comp);
00228         section->purgeTouched();
00229     }
00230 #else
00231     Gui::Application* app = Gui::Application::Instance;
00232     Base::SequencerLauncher seq("Cross-sections...", obj.size() * (d.size() +1));
00233     app->runPythonCode("import Part\n");
00234     app->runPythonCode("from FreeCAD import Base\n");
00235     for (std::vector<App::DocumentObject*>::iterator it = obj.begin(); it != obj.end(); ++it) {
00236         App::Document* doc = (*it)->getDocument();
00237         std::string s = (*it)->getNameInDocument();
00238         s += "_cs";
00239         app->runPythonCode(QString::fromAscii(
00240             "wires=list()\n"
00241             "shape=FreeCAD.getDocument(\"%1\").%2.Shape\n")
00242             .arg(QLatin1String(doc->getName()))
00243             .arg(QLatin1String((*it)->getNameInDocument())).toAscii());
00244 
00245         for (std::vector<double>::iterator jt = d.begin(); jt != d.end(); ++jt) {
00246             app->runPythonCode(QString::fromAscii(
00247                 "for i in shape.slice(Base.Vector(%1,%2,%3),%4):\n"
00248                 "    wires.append(i)\n"
00249                 ).arg(a).arg(b).arg(c).arg(*jt).toAscii());
00250             seq.next();
00251         }
00252 
00253         app->runPythonCode(QString::fromAscii(
00254             "comp=Part.Compound(wires)\n"
00255             "slice=FreeCAD.getDocument(\"%1\").addObject(\"Part::Feature\",\"%2\")\n"
00256             "slice.Shape=comp\n"
00257             "slice.purgeTouched()\n"
00258             "del slice,comp,wires,shape")
00259             .arg(QLatin1String(doc->getName()))
00260             .arg(QLatin1String(s.c_str())).toAscii());
00261 
00262         seq.next();
00263     }
00264 #endif
00265 }
00266 
00267 void CrossSections::on_xyPlane_clicked()
00268 {
00269     Base::Vector3d c = bbox.CalcCenter();
00270     ui->position->setValue(c.z);
00271     if (!ui->sectionsBox->isChecked()) {
00272         calcPlane(CrossSections::XY, c.z);
00273     }
00274     else {
00275         double dist = bbox.LengthZ() / ui->countSections->value();
00276         if (!ui->checkBothSides->isChecked())
00277             dist *= 0.5f;
00278         ui->distance->setValue(dist);
00279         calcPlanes(CrossSections::XY);
00280     }
00281 }
00282 
00283 void CrossSections::on_xzPlane_clicked()
00284 {
00285     Base::Vector3d c = bbox.CalcCenter();
00286     ui->position->setValue(c.y);
00287     if (!ui->sectionsBox->isChecked()) {
00288         calcPlane(CrossSections::XZ, c.y);
00289     }
00290     else {
00291         double dist = bbox.LengthY() / ui->countSections->value();
00292         if (!ui->checkBothSides->isChecked())
00293             dist *= 0.5f;
00294         ui->distance->setValue(dist);
00295         calcPlanes(CrossSections::XZ);
00296     }
00297 }
00298 
00299 void CrossSections::on_yzPlane_clicked()
00300 {
00301     Base::Vector3d c = bbox.CalcCenter();
00302     ui->position->setValue(c.x);
00303     if (!ui->sectionsBox->isChecked()) {
00304         calcPlane(CrossSections::YZ, c.x);
00305     }
00306     else {
00307         double dist = bbox.LengthX() / ui->countSections->value();
00308         if (!ui->checkBothSides->isChecked())
00309             dist *= 0.5f;
00310         ui->distance->setValue(dist);
00311         calcPlanes(CrossSections::YZ);
00312     }
00313 }
00314 
00315 void CrossSections::on_position_valueChanged(double v)
00316 {
00317     if (!ui->sectionsBox->isChecked()) {
00318         calcPlane(plane(), v);
00319     }
00320     else {
00321         calcPlanes(plane());
00322     }
00323 }
00324 
00325 void CrossSections::on_sectionsBox_toggled(bool b)
00326 {
00327     if (b) {
00328         on_countSections_valueChanged(ui->countSections->value());
00329     }
00330     else {
00331         CrossSections::Plane type = plane();
00332         Base::Vector3d c = bbox.CalcCenter();
00333         double value;
00334         switch (type) {
00335             case CrossSections::XY:
00336                 value = c.z;
00337                 break;
00338             case CrossSections::XZ:
00339                 value = c.y;
00340                 break;
00341             case CrossSections::YZ:
00342                 value = c.x;
00343                 break;
00344         }
00345 
00346         ui->position->setValue(value);
00347         calcPlane(type, value);
00348     }
00349 }
00350 
00351 void CrossSections::on_checkBothSides_toggled(bool b)
00352 {
00353     double d = ui->distance->value();
00354     d = b ? 2.0 * d : 0.5 * d;
00355     ui->distance->setValue(d);
00356     calcPlanes(plane());
00357 }
00358 
00359 void CrossSections::on_countSections_valueChanged(int v)
00360 {
00361     CrossSections::Plane type = plane();
00362     double dist;
00363     switch (type) {
00364         case CrossSections::XY:
00365             dist = bbox.LengthZ() / v;
00366             break;
00367         case CrossSections::XZ:
00368             dist = bbox.LengthY() / v;
00369             break;
00370         case CrossSections::YZ:
00371             dist = bbox.LengthX() / v;
00372             break;
00373     }
00374     if (!ui->checkBothSides->isChecked())
00375         dist *= 0.5f;
00376     ui->distance->setValue(dist);
00377     calcPlanes(type);
00378 }
00379 
00380 void CrossSections::on_distance_valueChanged(double)
00381 {
00382     calcPlanes(plane());
00383 }
00384 
00385 void CrossSections::calcPlane(Plane type, double pos)
00386 {
00387     double bound[4];
00388     switch (type) {
00389         case XY:
00390             bound[0] = bbox.MinX;
00391             bound[1] = bbox.MaxX;
00392             bound[2] = bbox.MinY;
00393             bound[3] = bbox.MaxY;
00394             break;
00395         case XZ:
00396             bound[0] = bbox.MinX;
00397             bound[1] = bbox.MaxX;
00398             bound[2] = bbox.MinZ;
00399             bound[3] = bbox.MaxZ;
00400             break;
00401         case YZ:
00402             bound[0] = bbox.MinY;
00403             bound[1] = bbox.MaxY;
00404             bound[2] = bbox.MinZ;
00405             bound[3] = bbox.MaxZ;
00406             break;
00407     }
00408 
00409     std::vector<double> d;
00410     d.push_back(pos);
00411     makePlanes(type, d, bound);
00412 }
00413 
00414 void CrossSections::calcPlanes(Plane type)
00415 {
00416     double bound[4];
00417     switch (type) {
00418         case XY:
00419             bound[0] = bbox.MinX;
00420             bound[1] = bbox.MaxX;
00421             bound[2] = bbox.MinY;
00422             bound[3] = bbox.MaxY;
00423             break;
00424         case XZ:
00425             bound[0] = bbox.MinX;
00426             bound[1] = bbox.MaxX;
00427             bound[2] = bbox.MinZ;
00428             bound[3] = bbox.MaxZ;
00429             break;
00430         case YZ:
00431             bound[0] = bbox.MinY;
00432             bound[1] = bbox.MaxY;
00433             bound[2] = bbox.MinZ;
00434             bound[3] = bbox.MaxZ;
00435             break;
00436     }
00437 
00438     std::vector<double> d = getPlanes();
00439     makePlanes(type, d, bound);
00440 }
00441 
00442 std::vector<double> CrossSections::getPlanes() const
00443 {
00444     int count = ui->countSections->value();
00445     double pos = ui->position->value();
00446     double stp = ui->distance->value();
00447     bool both = ui->checkBothSides->isChecked();
00448 
00449     std::vector<double> d;
00450     if (both) {
00451         double start = pos-0.5f*(count-1)*stp;
00452         for (int i=0; i<count; i++) {
00453             d.push_back(start+i*stp);
00454         }
00455     }
00456     else {
00457         for (int i=0; i<count; i++) {
00458             d.push_back(pos+i*stp);
00459         }
00460     }
00461     return d;
00462 }
00463 
00464 void CrossSections::makePlanes(Plane type, const std::vector<double>& d, double bound[4])
00465 {
00466     std::vector<Base::Vector3f> points;
00467     for (std::vector<double>::const_iterator it = d.begin(); it != d.end(); ++it) {
00468         Base::Vector3f v[4];
00469         switch (type) {
00470             case XY:
00471                 v[0].Set(bound[0],bound[2],*it);
00472                 v[1].Set(bound[1],bound[2],*it);
00473                 v[2].Set(bound[1],bound[3],*it);
00474                 v[3].Set(bound[0],bound[3],*it);
00475                 break;
00476             case XZ:
00477                 v[0].Set(bound[0],*it,bound[2]);
00478                 v[1].Set(bound[1],*it,bound[2]);
00479                 v[2].Set(bound[1],*it,bound[3]);
00480                 v[3].Set(bound[0],*it,bound[3]);
00481                 break;
00482             case YZ:
00483                 v[0].Set(*it,bound[0],bound[2]);
00484                 v[1].Set(*it,bound[1],bound[2]);
00485                 v[2].Set(*it,bound[1],bound[3]);
00486                 v[3].Set(*it,bound[0],bound[3]);
00487                 break;
00488         }
00489 
00490         points.push_back(v[0]);
00491         points.push_back(v[1]);
00492         points.push_back(v[2]);
00493         points.push_back(v[3]);
00494         points.push_back(v[0]);
00495     }
00496     vp->setCoords(points);
00497 }
00498 
00499 // ---------------------------------------
00500 
00501 TaskCrossSections::TaskCrossSections(const Base::BoundBox3d& bb)
00502 {
00503     widget = new CrossSections(bb);
00504     taskbox = new Gui::TaskView::TaskBox(
00505         Gui::BitmapFactory().pixmap("Part_Section"),
00506         widget->windowTitle(), true, 0);
00507     taskbox->groupLayout()->addWidget(widget);
00508     Content.push_back(taskbox);
00509 }
00510 
00511 TaskCrossSections::~TaskCrossSections()
00512 {
00513     // automatically deleted in the sub-class
00514 }
00515 
00516 bool TaskCrossSections::accept()
00517 {
00518     widget->accept();
00519     return (widget->result() == QDialog::Accepted);
00520 }
00521 
00522 void TaskCrossSections::clicked(int id)
00523 {
00524     if (id == QDialogButtonBox::Apply) {
00525         widget->apply();
00526     }
00527 }
00528 
00529 #include "moc_CrossSections.cpp"

Generated on Wed Nov 23 19:00:04 2011 for FreeCAD by  doxygen 1.6.1