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 <TopoDS_Shape.hxx>
00027 # include <TopoDS_Face.hxx>
00028 # include <TopoDS.hxx>
00029 # include <BRepAdaptor_Surface.hxx>
00030 #endif
00031
00032 #include <Base/Writer.h>
00033 #include <Base/Reader.h>
00034 #include <Base/Tools.h>
00035
00036 #include <Mod/Part/App/Geometry.h>
00037
00038 #include <vector>
00039
00040 #include "SketchObject.h"
00041 #include "SketchObjectPy.h"
00042 #include "Sketch.h"
00043
00044 using namespace Sketcher;
00045 using namespace Base;
00046
00047
00048 PROPERTY_SOURCE(Sketcher::SketchObject, Part::Part2DObject)
00049
00050
00051 SketchObject::SketchObject()
00052 {
00053 ADD_PROPERTY_TYPE(Geometry, (0) ,"Sketch",(App::PropertyType)(App::Prop_None),"Sketch geometry");
00054 ADD_PROPERTY_TYPE(Constraints, (0) ,"Sketch",(App::PropertyType)(App::Prop_None),"Sketch constraints");
00055 ADD_PROPERTY_TYPE(ExternalConstraints,(0,0),"Sketch",(App::PropertyType)(App::Prop_None),"Sketch external constraints");
00056 }
00057
00058 App::DocumentObjectExecReturn *SketchObject::execute(void)
00059 {
00060
00061 Part::Feature *part = static_cast<Part::Feature*>(Support.getValue());
00062 if (part && part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
00063 {
00064 Base::Placement ObjectPos = part->Placement.getValue();
00065 const std::vector<std::string> &sub = Support.getSubValues();
00066 assert(sub.size()==1);
00067
00068 const Part::TopoShape &shape = part->Shape.getShape();
00069 if (shape._Shape.IsNull())
00070 return new App::DocumentObjectExecReturn("Support shape is empty!");
00071 TopoDS_Shape sh = shape.getSubShape(sub[0].c_str());
00072 const TopoDS_Face &face = TopoDS::Face(sh);
00073 assert(!face.IsNull());
00074
00075 BRepAdaptor_Surface adapt(face);
00076 if (adapt.GetType() != GeomAbs_Plane)
00077 return new App::DocumentObjectExecReturn("Sketch has no planar support!");
00078
00079
00080 Base::Placement placement = Part2DObject::positionBySupport(face,ObjectPos);
00081 Placement.setValue(placement);
00082 }
00083
00084
00085 Sketch sketch;
00086 int dofs = sketch.setUpSketch(Geometry.getValues(), Constraints.getValues());
00087 if (dofs < 0) {
00088 std::string msg="Over-constrained sketch\n";
00089 appendConflictMsg(sketch.getConflicting(), msg);
00090 return new App::DocumentObjectExecReturn(msg.c_str(),this);
00091 }
00092 if (sketch.hasConflicts()) {
00093 std::string msg="Sketch with conflicting constraints\n";
00094 appendConflictMsg(sketch.getConflicting(), msg);
00095 return new App::DocumentObjectExecReturn(msg.c_str(),this);
00096 }
00097
00098
00099 if (sketch.solve() != 0)
00100 return new App::DocumentObjectExecReturn("Solving the sketch failed",this);
00101
00102 std::vector<Part::Geometry *> geomlist = sketch.getGeometry();
00103 Geometry.setValues(geomlist);
00104 for (std::vector<Part::Geometry *>::iterator it = geomlist.begin(); it != geomlist.end(); ++it)
00105 if (*it) delete *it;
00106
00107 Shape.setValue(sketch.toShape());
00108
00109 return App::DocumentObject::StdReturn;
00110 }
00111
00112 int SketchObject::hasConflicts(void) const
00113 {
00114
00115 Sketch sketch;
00116 int dofs = sketch.setUpSketch(Geometry.getValues(), Constraints.getValues());
00117 if (dofs < 0)
00118 return -2;
00119 if (sketch.hasConflicts())
00120 return -1;
00121
00122 return 0;
00123 }
00124
00125 int SketchObject::setDatum(int ConstrId, double Datum)
00126 {
00127
00128 const std::vector<Constraint *> &vals = this->Constraints.getValues();
00129 if (ConstrId < 0 || ConstrId >= (int)vals.size())
00130 return -1;
00131 ConstraintType type = vals[ConstrId]->Type;
00132 if (type != Distance &&
00133 type != DistanceX &&
00134 type != DistanceY &&
00135 type != Radius &&
00136 type != Angle)
00137 return -1;
00138
00139 if ((type == Distance || type == Radius) && Datum <= 0)
00140 return (Datum == 0) ? -5 : -4;
00141
00142
00143 std::vector<Constraint *> newVals(vals);
00144
00145 Constraint *constNew = vals[ConstrId]->clone();
00146 constNew->Value = Datum;
00147 newVals[ConstrId] = constNew;
00148 this->Constraints.setValues(newVals);
00149 delete constNew;
00150
00151
00152 Sketch sketch;
00153 int dofs = sketch.setUpSketch(Geometry.getValues(), Constraints.getValues());
00154 int err=0;
00155 if (dofs < 0)
00156 err = -3;
00157 else if (sketch.hasConflicts())
00158 err = -3;
00159 else if (sketch.solve() != 0)
00160 err = -2;
00161
00162 if (err == 0) {
00163
00164 std::vector<Part::Geometry *> geomlist = sketch.getGeometry();
00165 Geometry.setValues(geomlist);
00166 for (std::vector<Part::Geometry *>::iterator it = geomlist.begin(); it != geomlist.end(); ++it)
00167 if (*it) delete *it;
00168 }
00169 else
00170 this->Constraints.setValues(vals);
00171
00172 return err;
00173 }
00174
00175 int SketchObject::movePoint(int geoIndex, PointPos PosId, const Base::Vector3d& toPoint, bool relative)
00176 {
00177 Sketch sketch;
00178 int dofs = sketch.setUpSketch(Geometry.getValues(), Constraints.getValues());
00179 if (dofs < 0)
00180 return -1;
00181 if (sketch.hasConflicts())
00182 return -1;
00183
00184
00185 int ret = sketch.movePoint(geoIndex, PosId, toPoint, relative);
00186 if (ret == 0) {
00187 std::vector<Part::Geometry *> geomlist = sketch.getGeometry();
00188 Geometry.setValues(geomlist);
00189 for (std::vector<Part::Geometry *>::iterator it = geomlist.begin(); it != geomlist.end(); ++it) {
00190 if (*it) delete *it;
00191 }
00192 }
00193
00194 return ret;
00195 }
00196
00197 Base::Vector3d SketchObject::getPoint(int geoIndex, PointPos PosId)
00198 {
00199 const std::vector< Part::Geometry * > &geomlist = this->Geometry.getValues();
00200 assert(geoIndex < (int)geomlist.size());
00201 Part::Geometry *geo = geomlist[geoIndex];
00202 if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
00203 const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment*>(geo);
00204 if (PosId == start)
00205 return lineSeg->getStartPoint();
00206 else if (PosId == end)
00207 return lineSeg->getEndPoint();
00208 } else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) {
00209 const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle*>(geo);
00210 if (PosId == mid)
00211 return circle->getCenter();
00212 } else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
00213 const Part::GeomArcOfCircle *aoc = dynamic_cast<const Part::GeomArcOfCircle*>(geo);
00214 if (PosId == start)
00215 return aoc->getStartPoint();
00216 else if (PosId == end)
00217 return aoc->getEndPoint();
00218 else if (PosId == mid)
00219 return aoc->getCenter();
00220 }
00221
00222 return Base::Vector3d();
00223 }
00224
00225 int SketchObject::addGeometry(const std::vector<Part::Geometry *> &geoList)
00226 {
00227 return -1;
00228 }
00229
00230 int SketchObject::addGeometry(const Part::Geometry *geo)
00231 {
00232 const std::vector< Part::Geometry * > &vals = Geometry.getValues();
00233
00234 std::vector< Part::Geometry * > newVals(vals);
00235 Part::Geometry *geoNew = geo->clone();
00236 newVals.push_back(geoNew);
00237 Geometry.setValues(newVals);
00238 Constraints.acceptGeometry(Geometry.getValues());
00239 delete geoNew;
00240 rebuildVertexIndex();
00241 return Geometry.getSize()-1;
00242 }
00243
00244 int SketchObject::delGeometry(int GeoNbr)
00245 {
00246 const std::vector< Part::Geometry * > &vals = this->Geometry.getValues();
00247 if (GeoNbr < 0 || GeoNbr >= (int)vals.size())
00248 return -1;
00249
00250 std::vector< Part::Geometry * > newVals(vals);
00251 newVals.erase(newVals.begin()+GeoNbr);
00252
00253 const std::vector< Constraint * > &constraints = this->Constraints.getValues();
00254 std::vector< Constraint * > newConstraints(0);
00255 for (std::vector<Constraint *>::const_iterator it = constraints.begin();
00256 it != constraints.end(); ++it) {
00257 if ((*it)->First != GeoNbr && (*it)->Second != GeoNbr) {
00258 Constraint *copiedConstr = (*it)->clone();
00259 if (copiedConstr->First > GeoNbr)
00260 copiedConstr->First -= 1;
00261 if (copiedConstr->Second > GeoNbr)
00262 copiedConstr->Second -= 1;
00263 newConstraints.push_back(copiedConstr);
00264 }
00265 }
00266
00267 this->Geometry.setValues(newVals);
00268 this->Constraints.setValues(newConstraints);
00269 this->Constraints.acceptGeometry(this->Geometry.getValues());
00270 rebuildVertexIndex();
00271 return 0;
00272 }
00273
00274 int SketchObject::toggleConstruction(int GeoNbr)
00275 {
00276 const std::vector< Part::Geometry * > &vals = this->Geometry.getValues();
00277 if (GeoNbr < 0 || GeoNbr >= (int)vals.size())
00278 return -1;
00279
00280 std::vector< Part::Geometry * > newVals(vals);
00281
00282 Part::Geometry *geoNew = newVals[GeoNbr]->clone();
00283 geoNew->Construction = !geoNew->Construction;
00284 newVals[GeoNbr]=geoNew;
00285
00286 this->Geometry.setValues(newVals);
00287 this->Constraints.acceptGeometry(this->Geometry.getValues());
00288 return 0;
00289 }
00290
00291 int SketchObject::addConstraints(const std::vector<Constraint *> &ConstraintList)
00292 {
00293 return -1;
00294 }
00295
00296 int SketchObject::addConstraint(const Constraint *constraint)
00297 {
00298 const std::vector< Constraint * > &vals = this->Constraints.getValues();
00299
00300 std::vector< Constraint * > newVals(vals);
00301 Constraint *constNew = constraint->clone();
00302 newVals.push_back(constNew);
00303 this->Constraints.setValues(newVals);
00304 delete constNew;
00305 return this->Constraints.getSize()-1;
00306 }
00307
00308 int SketchObject::delConstraint(int ConstrId)
00309 {
00310 const std::vector< Constraint * > &vals = this->Constraints.getValues();
00311 if (ConstrId < 0 || ConstrId >= (int)vals.size())
00312 return -1;
00313
00314 std::vector< Constraint * > newVals(vals);
00315 newVals.erase(newVals.begin()+ConstrId);
00316 this->Constraints.setValues(newVals);
00317 return 0;
00318 }
00319
00320 int SketchObject::delConstraintOnPoint(int VertexId, bool onlyCoincident)
00321 {
00322 int GeoId;
00323 PointPos PosId;
00324 getGeoVertexIndex(VertexId, GeoId, PosId);
00325 return delConstraintOnPoint(GeoId, PosId, onlyCoincident);
00326 }
00327
00328 int SketchObject::delConstraintOnPoint(int GeoId, PointPos PosId, bool onlyCoincident)
00329 {
00330 const std::vector<Constraint *> &vals = this->Constraints.getValues();
00331
00332
00333 int replaceGeoId=-1;
00334 PointPos replacePosId=Sketcher::none;
00335 if (!onlyCoincident) {
00336 for (std::vector<Constraint *>::const_iterator it = vals.begin(); it != vals.end(); ++it) {
00337 if ((*it)->Type == Sketcher::Coincident) {
00338 if ((*it)->First == GeoId && (*it)->FirstPos == PosId) {
00339 replaceGeoId = (*it)->Second;
00340 replacePosId = (*it)->SecondPos;
00341 break;
00342 }
00343 else if ((*it)->Second == GeoId && (*it)->SecondPos == PosId) {
00344 replaceGeoId = (*it)->First;
00345 replacePosId = (*it)->FirstPos;
00346 break;
00347 }
00348 }
00349 }
00350 }
00351
00352
00353 std::vector<Constraint *> newVals(0);
00354 for (std::vector<Constraint *>::const_iterator it = vals.begin(); it != vals.end(); ++it) {
00355 if ((*it)->Type == Sketcher::Coincident) {
00356 if ((*it)->First == GeoId && (*it)->FirstPos == PosId) {
00357 if (replaceGeoId != -1 &&
00358 (replaceGeoId != (*it)->Second || replacePosId != (*it)->SecondPos)) {
00359 (*it)->First = replaceGeoId;
00360 (*it)->FirstPos = replacePosId;
00361 }
00362 else
00363 continue;
00364 }
00365 else if ((*it)->Second == GeoId && (*it)->SecondPos == PosId) {
00366 if (replaceGeoId != -1 &&
00367 (replaceGeoId != (*it)->First || replacePosId != (*it)->FirstPos)) {
00368 (*it)->Second = replaceGeoId;
00369 (*it)->SecondPos = replacePosId;
00370 }
00371 else
00372 continue;
00373 }
00374 }
00375 else if (!onlyCoincident) {
00376 if ((*it)->Type == Sketcher::Distance ||
00377 (*it)->Type == Sketcher::DistanceX || (*it)->Type == Sketcher::DistanceY) {
00378 if ((*it)->First == GeoId && (*it)->FirstPos == none &&
00379 (PosId == start || PosId ==end)) {
00380
00381
00382 continue;
00383 }
00384 else if ((*it)->First == GeoId && (*it)->FirstPos == PosId) {
00385 if (replaceGeoId != -1) {
00386 (*it)->First = replaceGeoId;
00387 (*it)->FirstPos = replacePosId;
00388 }
00389 else
00390 continue;
00391 }
00392 else if ((*it)->Second == GeoId && (*it)->SecondPos == PosId) {
00393 if (replaceGeoId != -1) {
00394 (*it)->Second = replaceGeoId;
00395 (*it)->SecondPos = replacePosId;
00396 }
00397 else
00398 continue;
00399 }
00400 }
00401 else if ((*it)->Type == Sketcher::PointOnObject) {
00402 if ((*it)->First == GeoId && (*it)->FirstPos == PosId) {
00403 if (replaceGeoId != -1) {
00404 (*it)->First = replaceGeoId;
00405 (*it)->FirstPos = replacePosId;
00406 }
00407 else
00408 continue;
00409 }
00410 }
00411 else if ((*it)->Type == Sketcher::Tangent) {
00412 if (((*it)->First == GeoId && (*it)->FirstPos == PosId) ||
00413 ((*it)->Second == GeoId && (*it)->SecondPos == PosId)) {
00414
00415
00416 continue;
00417 }
00418 }
00419 else if ((*it)->Type == Sketcher::Symmetric) {
00420 if (((*it)->First == GeoId && (*it)->FirstPos == PosId) ||
00421 ((*it)->Second == GeoId && (*it)->SecondPos == PosId)) {
00422 continue;
00423 }
00424 }
00425 }
00426 newVals.push_back(*it);
00427 }
00428 if (newVals.size() < vals.size()) {
00429 this->Constraints.setValues(newVals);
00430 return 0;
00431 }
00432
00433 return -1;
00434 }
00435
00436 int SketchObject::transferConstraints(int fromGeoId, PointPos fromPosId, int toGeoId, PointPos toPosId)
00437 {
00438 const std::vector<Constraint *> &vals = this->Constraints.getValues();
00439 std::vector<Constraint *> newVals(vals);
00440 for (int i=0; i < int(newVals.size()); i++) {
00441 if (vals[i]->First == fromGeoId && vals[i]->FirstPos == fromPosId) {
00442 Constraint *constNew = newVals[i]->clone();
00443 constNew->First = toGeoId;
00444 constNew->FirstPos = toPosId;
00445 newVals[i] = constNew;
00446 } else if (vals[i]->Second == fromGeoId && vals[i]->SecondPos == fromPosId) {
00447 Constraint *constNew = newVals[i]->clone();
00448 constNew->Second = toGeoId;
00449 constNew->SecondPos = toPosId;
00450 newVals[i] = constNew;
00451 }
00452 }
00453 this->Constraints.setValues(newVals);
00454 return 0;
00455 }
00456
00457 int SketchObject::fillet(int GeoId, PointPos PosId, double radius, bool trim)
00458 {
00459 const std::vector<Part::Geometry *> &geomlist = this->Geometry.getValues();
00460 assert(GeoId < int(geomlist.size()));
00461
00462 std::vector<int> GeoIdList;
00463 std::vector<PointPos> PosIdList;
00464 getCoincidentPoints(GeoId, PosId, GeoIdList, PosIdList);
00465
00466
00467 if (GeoIdList.size() == 2) {
00468 Part::Geometry *geo1 = geomlist[GeoIdList[0]];
00469 Part::Geometry *geo2 = geomlist[GeoIdList[1]];
00470 if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() &&
00471 geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId() ) {
00472 const Part::GeomLineSegment *lineSeg1 = dynamic_cast<const Part::GeomLineSegment*>(geo1);
00473 const Part::GeomLineSegment *lineSeg2 = dynamic_cast<const Part::GeomLineSegment*>(geo2);
00474
00475 Base::Vector3d midPnt1 = (lineSeg1->getStartPoint() + lineSeg1->getEndPoint()) / 2 ;
00476 Base::Vector3d midPnt2 = (lineSeg2->getStartPoint() + lineSeg2->getEndPoint()) / 2 ;
00477 return fillet(GeoIdList[0], GeoIdList[1], midPnt1, midPnt2, radius, trim);
00478 }
00479 }
00480
00481 return -1;
00482 }
00483
00484 int SketchObject::fillet(int GeoId1, int GeoId2,
00485 const Base::Vector3d& refPnt1, const Base::Vector3d& refPnt2,
00486 double radius, bool trim)
00487 {
00488 const std::vector<Part::Geometry *> &geomlist = this->Geometry.getValues();
00489 assert(GeoId1 < int(geomlist.size()));
00490 assert(GeoId2 < int(geomlist.size()));
00491 Part::Geometry *geo1 = geomlist[GeoId1];
00492 Part::Geometry *geo2 = geomlist[GeoId2];
00493 if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() &&
00494 geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId() ) {
00495 const Part::GeomLineSegment *lineSeg1 = dynamic_cast<const Part::GeomLineSegment*>(geo1);
00496 const Part::GeomLineSegment *lineSeg2 = dynamic_cast<const Part::GeomLineSegment*>(geo2);
00497
00498 Base::Vector3d filletCenter;
00499 if (!Part::findFilletCenter(lineSeg1, lineSeg2, radius, refPnt1, refPnt2, filletCenter))
00500 return -1;
00501 Base::Vector3d dir1 = lineSeg1->getEndPoint() - lineSeg1->getStartPoint();
00502 Base::Vector3d dir2 = lineSeg2->getEndPoint() - lineSeg2->getStartPoint();
00503
00504
00505 Base::Vector3d intersection, dist1, dist2;
00506
00507
00508 int filletId;
00509 Part::GeomArcOfCircle *arc = Part::createFilletGeometry(lineSeg1, lineSeg2, filletCenter, radius);
00510 if (arc) {
00511
00512 if (!find2DLinesIntersection(lineSeg1, lineSeg2, intersection)) {
00513 delete arc;
00514 return -1;
00515 }
00516 dist1.ProjToLine(arc->getStartPoint()-intersection, dir1);
00517 dist2.ProjToLine(arc->getStartPoint()-intersection, dir2);
00518 Part::Geometry *newgeo = dynamic_cast<Part::Geometry* >(arc);
00519 filletId = addGeometry(newgeo);
00520 if (filletId < 0) {
00521 delete arc;
00522 return -1;
00523 }
00524 }
00525 else
00526 return -1;
00527
00528 if (trim) {
00529 PointPos PosId1 = (filletCenter-intersection)*dir1 > 0 ? start : end;
00530 PointPos PosId2 = (filletCenter-intersection)*dir2 > 0 ? start : end;
00531
00532 delConstraintOnPoint(GeoId1, PosId1, false);
00533 delConstraintOnPoint(GeoId2, PosId2, false);
00534 Sketcher::Constraint *tangent1 = new Sketcher::Constraint();
00535 Sketcher::Constraint *tangent2 = new Sketcher::Constraint();
00536
00537 tangent1->Type = Sketcher::Tangent;
00538 tangent1->First = GeoId1;
00539 tangent1->FirstPos = PosId1;
00540 tangent1->Second = filletId;
00541
00542 tangent2->Type = Sketcher::Tangent;
00543 tangent2->First = GeoId2;
00544 tangent2->FirstPos = PosId2;
00545 tangent2->Second = filletId;
00546
00547 if (dist1.Length() < dist2.Length()) {
00548 tangent1->SecondPos = start;
00549 tangent2->SecondPos = end;
00550 movePoint(GeoId1, PosId1, arc->getStartPoint());
00551 movePoint(GeoId2, PosId2, arc->getEndPoint());
00552 }
00553 else {
00554 tangent1->SecondPos = end;
00555 tangent2->SecondPos = start;
00556 movePoint(GeoId1, PosId1, arc->getEndPoint());
00557 movePoint(GeoId2, PosId2, arc->getStartPoint());
00558 }
00559
00560 addConstraint(tangent1);
00561 addConstraint(tangent2);
00562 delete tangent1;
00563 delete tangent2;
00564 }
00565 delete arc;
00566 return 0;
00567 }
00568 return -1;
00569 }
00570
00571 int SketchObject::trim(int GeoId, const Base::Vector3d& point)
00572 {
00573 const std::vector<Part::Geometry *> &geomlist = this->Geometry.getValues();
00574 const std::vector<Constraint *> &constraints = this->Constraints.getValues();
00575
00576 assert(GeoId < int(geomlist.size()));
00577
00578 int GeoId1=-1, GeoId2=-1;
00579 Base::Vector3d point1, point2;
00580 Part2DObject::seekTrimPoints(geomlist, GeoId, point, GeoId1, point1, GeoId2, point2);
00581 if (GeoId1 < 0 && GeoId2 >= 0) {
00582 std::swap(GeoId1,GeoId2);
00583 std::swap(point1,point2);
00584 }
00585
00586 Part::Geometry *geo = geomlist[GeoId];
00587 if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
00588 const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment*>(geo);
00589 Base::Vector3d startPnt = lineSeg->getStartPoint();
00590 Base::Vector3d endPnt = lineSeg->getEndPoint();
00591 Base::Vector3d dir = (endPnt - startPnt).Normalize();
00592 double length = (endPnt - startPnt)*dir;
00593 double x0 = (point - startPnt)*dir;
00594 if (GeoId1 >= 0 && GeoId2 >= 0) {
00595 double x1 = (point1 - startPnt)*dir;
00596 double x2 = (point2 - startPnt)*dir;
00597 if (x1 > x2) {
00598 std::swap(GeoId1,GeoId2);
00599 std::swap(point1,point2);
00600 std::swap(x1,x2);
00601 }
00602 if (x1 >= 0.001*length && x2 <= 0.999*length) {
00603 if (x1 < x0 && x2 > x0) {
00604 int newGeoId = addGeometry(geo);
00605
00606 transferConstraints(GeoId, end, newGeoId, end);
00607
00608 movePoint(GeoId, end, point1);
00609 movePoint(newGeoId, start, point2);
00610
00611 PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none;
00612 ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject;
00613 for (std::vector<Constraint *>::const_iterator it=constraints.begin();
00614 it != constraints.end(); ++it) {
00615 Constraint *constr = *(it);
00616 if (secondPos1 == Sketcher::none && (constr->First == GeoId1 && constr->Second == GeoId)) {
00617 constrType1= Sketcher::Coincident;
00618 secondPos1 = constr->FirstPos;
00619 } else if (secondPos2 == Sketcher::none && (constr->First == GeoId2 && constr->Second == GeoId)) {
00620 constrType2 = Sketcher::Coincident;
00621 secondPos2 = constr->FirstPos;
00622 }
00623 }
00624
00625
00626 Sketcher::Constraint *newConstr = new Sketcher::Constraint();
00627 newConstr->Type = constrType1;
00628 newConstr->First = GeoId;
00629 newConstr->FirstPos = end;
00630 newConstr->Second = GeoId1;
00631
00632 if (constrType1 == Sketcher::Coincident) {
00633 newConstr->SecondPos = secondPos1;
00634 delConstraintOnPoint(GeoId1, secondPos1, false);
00635 }
00636
00637 addConstraint(newConstr);
00638
00639
00640 newConstr->SecondPos = Sketcher::none;
00641
00642 newConstr->Type = constrType2;
00643 newConstr->First = newGeoId;
00644 newConstr->FirstPos = start;
00645 newConstr->Second = GeoId2;
00646
00647 if (constrType2 == Sketcher::Coincident) {
00648 newConstr->SecondPos = secondPos2;
00649 delConstraintOnPoint(GeoId2, secondPos2, false);
00650 }
00651
00652 addConstraint(newConstr);
00653
00654
00655 newConstr->SecondPos = Sketcher::none;
00656
00657
00658 newConstr->Type = Sketcher::Tangent;
00659 newConstr->First = GeoId;
00660 newConstr->FirstPos = none;
00661 newConstr->Second = newGeoId;
00662 addConstraint(newConstr);
00663
00664 delete newConstr;
00665 return 0;
00666 }
00667 } else if (x1 < 0.001*length) {
00668 std::swap(GeoId1,GeoId2);
00669 std::swap(point1,point2);
00670 } else if (x2 > 0.999*length) {
00671 }
00672 else
00673 return -1;
00674 }
00675
00676 if (GeoId1 >= 0) {
00677 double x1 = (point1 - startPnt)*dir;
00678 if (x1 >= 0.001*length && x1 <= 0.999*length) {
00679
00680 ConstraintType constrType = Sketcher::PointOnObject;
00681 PointPos secondPos = Sketcher::none;
00682 for (std::vector<Constraint *>::const_iterator it=constraints.begin();
00683 it != constraints.end(); ++it) {
00684 Constraint *constr = *(it);
00685 if ((constr->First == GeoId1 && constr->Second == GeoId)) {
00686 constrType = Sketcher::Coincident;
00687 secondPos = constr->FirstPos;
00688 delConstraintOnPoint(GeoId1, constr->FirstPos, false);
00689 break;
00690 }
00691 }
00692
00693 if (x1 > x0) {
00694 delConstraintOnPoint(GeoId, start, false);
00695 movePoint(GeoId, start, point1);
00696
00697
00698 Sketcher::Constraint *newConstr = new Sketcher::Constraint();
00699 newConstr->Type = constrType;
00700 newConstr->First = GeoId;
00701 newConstr->FirstPos = start;
00702 newConstr->Second = GeoId1;
00703
00704 if (constrType == Sketcher::Coincident)
00705 newConstr->SecondPos = secondPos;
00706
00707 addConstraint(newConstr);
00708 delete newConstr;
00709 return 0;
00710 }
00711 else if (x1 < x0) {
00712 delConstraintOnPoint(GeoId, end, false);
00713 movePoint(GeoId, end, point1);
00714 Sketcher::Constraint *newConstr = new Sketcher::Constraint();
00715 newConstr->Type = constrType;
00716 newConstr->First = GeoId;
00717 newConstr->FirstPos = end;
00718 newConstr->Second = GeoId1;
00719
00720 if (constrType == Sketcher::Coincident)
00721 newConstr->SecondPos = secondPos;
00722
00723 addConstraint(newConstr);
00724 delete newConstr;
00725 return 0;
00726 }
00727 }
00728 }
00729 } else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) {
00730 const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle*>(geo);
00731 Base::Vector3d center = circle->getCenter();
00732 double theta0 = Base::fmod(atan2(point.y - center.y,point.x - center.x), 2.f*M_PI);
00733 if (GeoId1 >= 0 && GeoId2 >= 0) {
00734 double theta1 = Base::fmod(atan2(point1.y - center.y, point1.x - center.x), 2.f*M_PI);
00735 double theta2 = Base::fmod(atan2(point2.y - center.y, point2.x - center.x), 2.f*M_PI);
00736 if (Base::fmod(theta1 - theta0, 2.f*M_PI) > Base::fmod(theta2 - theta0, 2.f*M_PI)) {
00737 std::swap(GeoId1,GeoId2);
00738 std::swap(point1,point2);
00739 std::swap(theta1,theta2);
00740 }
00741 if (theta1 == theta0 || theta1 == theta2)
00742 return -1;
00743 else if (theta1 > theta2)
00744 theta2 += 2.f*M_PI;
00745
00746
00747
00748
00749 Part::GeomArcOfCircle *geoNew = new Part::GeomArcOfCircle();
00750 geoNew->setCenter(center);
00751 geoNew->setRadius(circle->getRadius());
00752 geoNew->setRange(theta1, theta2);
00753
00754 std::vector< Part::Geometry * > newVals(geomlist);
00755 newVals[GeoId] = geoNew;
00756 Geometry.setValues(newVals);
00757 Constraints.acceptGeometry(Geometry.getValues());
00758 delete geoNew;
00759 rebuildVertexIndex();
00760
00761 PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none;
00762 ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject;
00763 for (std::vector<Constraint *>::const_iterator it=constraints.begin();
00764 it != constraints.end(); ++it) {
00765 Constraint *constr = *(it);
00766 if (secondPos1 == Sketcher::none && (constr->First == GeoId1 && constr->Second == GeoId)) {
00767 constrType1= Sketcher::Coincident;
00768 secondPos1 = constr->FirstPos;
00769 } else if(secondPos2 == Sketcher::none && (constr->First == GeoId2 && constr->Second == GeoId)) {
00770 constrType2 = Sketcher::Coincident;
00771 secondPos2 = constr->FirstPos;
00772 }
00773 }
00774
00775
00776 Sketcher::Constraint *newConstr = new Sketcher::Constraint();
00777 newConstr->Type = constrType1;
00778 newConstr->First = GeoId;
00779 newConstr->FirstPos = start;
00780 newConstr->Second = GeoId1;
00781
00782 if (constrType1 == Sketcher::Coincident) {
00783 newConstr->SecondPos = secondPos1;
00784 delConstraintOnPoint(GeoId1, secondPos1, false);
00785 }
00786
00787 addConstraint(newConstr);
00788
00789
00790 newConstr->SecondPos = Sketcher::none;
00791
00792
00793 newConstr->First = GeoId;
00794 newConstr->FirstPos = end;
00795 newConstr->Second = GeoId2;
00796
00797 if (constrType2 == Sketcher::Coincident) {
00798 newConstr->SecondPos = secondPos2;
00799 delConstraintOnPoint(GeoId2, secondPos2, false);
00800 }
00801
00802 addConstraint(newConstr);
00803
00804 delete newConstr;
00805
00806 return 0;
00807 }
00808
00809 } else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
00810 const Part::GeomArcOfCircle *aoc = dynamic_cast<const Part::GeomArcOfCircle*>(geo);
00811 Base::Vector3d center = aoc->getCenter();
00812 double startAngle, endAngle;
00813 aoc->getRange(startAngle, endAngle);
00814 double dir = (startAngle < endAngle) ? 1 : -1;
00815 double arcLength = (endAngle - startAngle)*dir;
00816 double theta0 = Base::fmod(atan2(point.y - center.y, point.x - center.x) - startAngle, 2.f*M_PI);
00817 if (GeoId1 >= 0 && GeoId2 >= 0) {
00818 double theta1 = Base::fmod(atan2(point1.y - center.y, point1.x - center.x) - startAngle, 2.f*M_PI) * dir;
00819 double theta2 = Base::fmod(atan2(point2.y - center.y, point2.x - center.x) - startAngle, 2.f*M_PI) * dir;
00820 if (theta1 > theta2) {
00821 std::swap(GeoId1,GeoId2);
00822 std::swap(point1,point2);
00823 std::swap(theta1,theta2);
00824 }
00825 if (theta1 >= 0.001*arcLength && theta2 <= 0.999*arcLength) {
00826
00827 if (theta1 < theta0 && theta2 > theta0) {
00828 int newGeoId = addGeometry(geo);
00829
00830 transferConstraints(GeoId, end, newGeoId, end);
00831
00832 Part::GeomArcOfCircle *aoc1 = dynamic_cast<Part::GeomArcOfCircle*>(geomlist[GeoId]);
00833 Part::GeomArcOfCircle *aoc2 = dynamic_cast<Part::GeomArcOfCircle*>(geomlist[newGeoId]);
00834 aoc1->setRange(startAngle, startAngle + theta1);
00835 aoc2->setRange(startAngle + theta2, endAngle);
00836
00837
00838 Sketcher::Constraint *newConstr = new Sketcher::Constraint();
00839
00840
00841 newConstr->Type = Sketcher::Equal;
00842 newConstr->First = GeoId;
00843 newConstr->Second = newGeoId;
00844 addConstraint(newConstr);
00845
00846 PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none;
00847 ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject;
00848
00849 for (std::vector<Constraint *>::const_iterator it=constraints.begin();
00850 it != constraints.end(); ++it) {
00851 Constraint *constr = *(it);
00852 if (secondPos1 == Sketcher::none &&
00853 (constr->First == GeoId1 && constr->Second == GeoId)) {
00854 constrType1= Sketcher::Coincident;
00855 secondPos1 = constr->FirstPos;
00856 } else if (secondPos2 == Sketcher::none &&
00857 (constr->First == GeoId2 && constr->Second == GeoId)) {
00858 constrType2 = Sketcher::Coincident;
00859 secondPos2 = constr->FirstPos;
00860 }
00861 }
00862
00863 newConstr->Type = constrType1;
00864 newConstr->First = GeoId;
00865 newConstr->FirstPos = end;
00866 newConstr->Second = GeoId1;
00867
00868 if (constrType1 == Sketcher::Coincident) {
00869 newConstr->SecondPos = secondPos1;
00870 delConstraintOnPoint(GeoId1, secondPos1, false);
00871 }
00872
00873 addConstraint(newConstr);
00874
00875
00876 newConstr->SecondPos = Sketcher::none;
00877
00878 newConstr->Type = constrType2;
00879 newConstr->First = newGeoId;
00880 newConstr->FirstPos = start;
00881 newConstr->Second = GeoId2;
00882
00883 if (constrType2 == Sketcher::Coincident) {
00884 newConstr->SecondPos = secondPos2;
00885 delConstraintOnPoint(GeoId2, secondPos2, false);
00886 }
00887
00888 addConstraint(newConstr);
00889
00890 newConstr->Type = Sketcher::Coincident;
00891 newConstr->First = GeoId;
00892 newConstr->FirstPos = Sketcher::mid;
00893 newConstr->Second = newGeoId;
00894 newConstr->SecondPos = Sketcher::mid;
00895 addConstraint(newConstr);
00896
00897 delete newConstr;
00898
00899 return 0;
00900 } else
00901 return -1;
00902 } else if (theta1 < 0.001*arcLength) {
00903 std::swap(GeoId1,GeoId2);
00904 std::swap(point1,point2);
00905 } else if (theta2 > 0.999*arcLength) {
00906 }
00907 else
00908 return -1;
00909 }
00910
00911 if (GeoId1 >= 0) {
00912
00913 ConstraintType constrType = Sketcher::PointOnObject;
00914 PointPos secondPos = Sketcher::none;
00915 for (std::vector<Constraint *>::const_iterator it=constraints.begin();
00916 it != constraints.end(); ++it) {
00917 Constraint *constr = *(it);
00918 if ((constr->First == GeoId1 && constr->Second == GeoId)) {
00919 constrType = Sketcher::Coincident;
00920 secondPos = constr->FirstPos;
00921 delConstraintOnPoint(GeoId1, constr->FirstPos, false);
00922 break;
00923 }
00924 }
00925
00926 double theta1 = Base::fmod(atan2(point1.y - center.y, point1.x - center.x) - startAngle, 2.f*M_PI) * dir;
00927 if (theta1 >= 0.001*arcLength && theta1 <= 0.999*arcLength) {
00928 if (theta1 > theta0) {
00929 delConstraintOnPoint(GeoId, start, false);
00930 Part::GeomArcOfCircle *aoc1 = dynamic_cast<Part::GeomArcOfCircle*>(geomlist[GeoId]);
00931 aoc1->setRange(startAngle + theta1, endAngle);
00932
00933 Sketcher::Constraint *newConstr = new Sketcher::Constraint();
00934 newConstr->Type = constrType;
00935 newConstr->First = GeoId;
00936 newConstr->FirstPos = start;
00937 newConstr->Second = GeoId1;
00938
00939 if (constrType == Sketcher::Coincident)
00940 newConstr->SecondPos = secondPos;
00941
00942 addConstraint(newConstr);
00943 delete newConstr;
00944 return 0;
00945 }
00946 else {
00947 delConstraintOnPoint(GeoId, end, false);
00948 Part::GeomArcOfCircle *aoc1 = dynamic_cast<Part::GeomArcOfCircle*>(geomlist[GeoId]);
00949 aoc1->setRange(startAngle, startAngle + theta1);
00950 Sketcher::Constraint *newConstr = new Sketcher::Constraint();
00951 newConstr->Type = constrType;
00952 newConstr->First = GeoId;
00953 newConstr->FirstPos = end;
00954 newConstr->Second = GeoId1;
00955
00956 if (constrType == Sketcher::Coincident)
00957 newConstr->SecondPos = secondPos;
00958
00959 addConstraint(newConstr);
00960 delete newConstr;
00961 return 0;
00962 }
00963 }
00964 }
00965 }
00966
00967 return -1;
00968 }
00969
00970 int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName)
00971 {
00972
00973 assert(Support.getValue() == Obj);
00974
00975
00976 std::vector<DocumentObject*> Objects = ExternalConstraints.getValues();
00977 std::vector<std::string> SubElements = ExternalConstraints.getSubValues();
00978
00979
00980 Objects.push_back(Obj);
00981 SubElements.push_back(std::string(SubName));
00982
00983
00984 ExternalConstraints.setValues(Objects,SubElements);
00985
00986 return ExternalConstraints.getValues().size()-1;
00987 }
00988
00989 int SketchObject::delExternal(int ConstrId)
00990 {
00991
00992 return 0;
00993
00994 }
00995
00996 std::vector<Part::Geometry *> getExternalGeometry(void)
00997 {
00998 std::vector<Part::Geometry *> ExtGeos;
00999
01000
01001 ExtGeos.push_back(new Part::GeomPoint(Base::Vector3d(0,0,0)));
01002
01003
01004 ExtGeos.push_back(new Part::GeomLine(Base::Vector3d(0,0,0),Base::Vector3d(1,0,0)));
01005 ExtGeos.push_back(new Part::GeomLine(Base::Vector3d(0,0,0),Base::Vector3d(0,1,0)));
01006
01007
01008 return ExtGeos;
01009 }
01010
01011
01012 void SketchObject::rebuildVertexIndex(void)
01013 {
01014 VertexId2GeoId.resize(0);
01015 VertexId2PosId.resize(0);
01016 int i=0;
01017 const std::vector< Part::Geometry * > &geometry = this->Geometry.getValues();
01018 for (std::vector< Part::Geometry * >::const_iterator it = geometry.begin();
01019 it != geometry.end(); ++it,i++) {
01020 if ((*it)->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
01021 VertexId2GeoId.push_back(i);
01022 VertexId2PosId.push_back(start);
01023 VertexId2GeoId.push_back(i);
01024 VertexId2PosId.push_back(end);
01025 } else if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) {
01026 VertexId2GeoId.push_back(i);
01027 VertexId2PosId.push_back(mid);
01028 } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
01029 VertexId2GeoId.push_back(i);
01030 VertexId2PosId.push_back(mid);
01031 VertexId2GeoId.push_back(i);
01032 VertexId2PosId.push_back(start);
01033 VertexId2GeoId.push_back(i);
01034 VertexId2PosId.push_back(end);
01035 }
01036 }
01037 }
01038
01039 void SketchObject::getCoincidentPoints(int GeoId, PointPos PosId, std::vector<int> &GeoIdList,
01040 std::vector<PointPos> &PosIdList)
01041 {
01042 const std::vector<Constraint *> &constraints = this->Constraints.getValues();
01043
01044 GeoIdList.clear();
01045 PosIdList.clear();
01046 GeoIdList.push_back(GeoId);
01047 PosIdList.push_back(PosId);
01048 for (std::vector<Constraint *>::const_iterator it=constraints.begin();
01049 it != constraints.end(); ++it) {
01050 if ((*it)->Type == Sketcher::Coincident) {
01051 if ((*it)->First == GeoId && (*it)->FirstPos == PosId) {
01052 GeoIdList.push_back((*it)->Second);
01053 PosIdList.push_back((*it)->SecondPos);
01054 }
01055 else if ((*it)->Second == GeoId && (*it)->SecondPos == PosId) {
01056 GeoIdList.push_back((*it)->First);
01057 PosIdList.push_back((*it)->FirstPos);
01058 }
01059 }
01060 }
01061 if (GeoIdList.size() == 1) {
01062 GeoIdList.clear();
01063 PosIdList.clear();
01064 }
01065 }
01066
01067 void SketchObject::getCoincidentPoints(int VertexId, std::vector<int> &GeoIdList,
01068 std::vector<PointPos> &PosIdList)
01069 {
01070 int GeoId;
01071 PointPos PosId;
01072 getGeoVertexIndex(VertexId, GeoId, PosId);
01073 getCoincidentPoints(GeoId, PosId, GeoIdList, PosIdList);
01074 }
01075
01076 void SketchObject::appendConflictMsg(const std::vector<int> &conflicting, std::string &msg)
01077 {
01078 std::stringstream ss;
01079 if (msg.length() > 0)
01080 ss << msg;
01081 if (conflicting.size() > 0) {
01082 ss << "Please remove at least one of the constraints (" << conflicting[0];
01083 for (unsigned int i=1; i < conflicting.size(); i++)
01084 ss << ", " << conflicting[i];
01085 ss << ")\n";
01086 }
01087 msg = ss.str();
01088 }
01089
01090 PyObject *SketchObject::getPyObject(void)
01091 {
01092 if (PythonObject.is(Py::_None())) {
01093
01094 PythonObject = Py::Object(new SketchObjectPy(this),true);
01095 }
01096 return Py::new_reference_to(PythonObject);
01097 }
01098
01099 unsigned int SketchObject::getMemSize(void) const
01100 {
01101 return 0;
01102 }
01103
01104 void SketchObject::Save(Writer &writer) const
01105 {
01106
01107 Part::Part2DObject::Save(writer);
01108 }
01109
01110 void SketchObject::Restore(XMLReader &reader)
01111 {
01112
01113 Part::Part2DObject::Restore(reader);
01114 Constraints.acceptGeometry(Geometry.getValues());
01115 rebuildVertexIndex();
01116 }
01117
01118 void SketchObject::onChanged(const App::Property* prop)
01119 {
01120 if (prop == &Geometry || prop == &Constraints)
01121 Constraints.checkGeometry(Geometry.getValues());
01122 Part::Part2DObject::onChanged(prop);
01123 }
01124
01125 void SketchObject::getGeoVertexIndex(int VertexId, int &GeoId, PointPos &PosId)
01126 {
01127 if (VertexId < 0 || VertexId >= (int)VertexId2GeoId.size()) {
01128 GeoId = -1;
01129 PosId = none;
01130 return;
01131 }
01132 GeoId = VertexId2GeoId[VertexId];
01133 PosId = VertexId2PosId[VertexId];
01134 }
01135
01136
01137
01138 namespace App {
01140 PROPERTY_SOURCE_TEMPLATE(Sketcher::SketchObjectPython, Sketcher::SketchObject)
01141 template<> const char* Sketcher::SketchObjectPython::getViewProviderName(void) const {
01142 return "SketcherGui::ViewProviderPython";
01143 }
01145
01146
01147 template class SketcherExport FeaturePythonT<Sketcher::SketchObject>;
01148 }