00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00142
00143 CrossSections::~CrossSections()
00144 {
00145
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
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"