SketchObject.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) Jürgen Riegel          (juergen.riegel@web.de) 2008     *
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 <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     // recalculate support:
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         // get the selected sub shape (a Face)
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         // set sketch position
00080         Base::Placement placement = Part2DObject::positionBySupport(face,ObjectPos);
00081         Placement.setValue(placement);
00082     }
00083 
00084     // setup and diagnose the sketch
00085     Sketch sketch;
00086     int dofs = sketch.setUpSketch(Geometry.getValues(), Constraints.getValues());
00087     if (dofs < 0) { // over-constrained sketch
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()) { // conflicting constraints
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     // solve the sketch
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     // set up a sketch (including dofs counting and diagnosing of conflicts)
00115     Sketch sketch;
00116     int dofs = sketch.setUpSketch(Geometry.getValues(), Constraints.getValues());
00117     if (dofs < 0) // over-constrained sketch
00118         return -2;
00119     if (sketch.hasConflicts()) // conflicting constraints
00120         return -1;
00121 
00122     return 0;
00123 }
00124 
00125 int SketchObject::setDatum(int ConstrId, double Datum)
00126 {
00127     // set the changed value for the constraint
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     // copy the list
00143     std::vector<Constraint *> newVals(vals);
00144     // clone the changed Constraint
00145     Constraint *constNew = vals[ConstrId]->clone();
00146     constNew->Value = Datum;
00147     newVals[ConstrId] = constNew;
00148     this->Constraints.setValues(newVals);
00149     delete constNew;
00150 
00151     // set up a sketch (including dofs counting and diagnosing of conflicts)
00152     Sketch sketch;
00153     int dofs = sketch.setUpSketch(Geometry.getValues(), Constraints.getValues());
00154     int err=0;
00155     if (dofs < 0) // over-constrained sketch
00156         err = -3;
00157     else if (sketch.hasConflicts()) // conflicting constraints
00158         err = -3;
00159     else if (sketch.solve() != 0) // solving
00160         err = -2;
00161 
00162     if (err == 0) {
00163         // set the newly solved geometry
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) // over-constrained sketch
00180         return -1;
00181     if (sketch.hasConflicts()) // conflicting constraints
00182         return -1;
00183 
00184     // move the point and solve
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     // check if constraints can be redirected to some other point
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     // remove or redirect any constraints associated with the given point
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)) { // redirect this constraint
00359                     (*it)->First = replaceGeoId;
00360                     (*it)->FirstPos = replacePosId;
00361                 }
00362                 else
00363                     continue; // skip this constraint
00364             }
00365             else if ((*it)->Second == GeoId && (*it)->SecondPos == PosId) {
00366                 if (replaceGeoId != -1 &&
00367                     (replaceGeoId != (*it)->First || replacePosId != (*it)->FirstPos)) { // redirect this constraint
00368                     (*it)->Second = replaceGeoId;
00369                     (*it)->SecondPos = replacePosId;
00370                 }
00371                 else
00372                     continue; // skip this constraint
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                     // remove the constraint even if it is not directly associated
00381                     // with the given point
00382                     continue; // skip this constraint
00383                 }
00384                 else if ((*it)->First == GeoId && (*it)->FirstPos == PosId) {
00385                     if (replaceGeoId != -1) { // redirect this constraint
00386                         (*it)->First = replaceGeoId;
00387                         (*it)->FirstPos = replacePosId;
00388                     }
00389                     else
00390                         continue; // skip this constraint
00391                 }
00392                 else if ((*it)->Second == GeoId && (*it)->SecondPos == PosId) {
00393                     if (replaceGeoId != -1) { // redirect this constraint
00394                         (*it)->Second = replaceGeoId;
00395                         (*it)->SecondPos = replacePosId;
00396                     }
00397                     else
00398                         continue; // skip this constraint
00399                 }
00400             }
00401             else if ((*it)->Type == Sketcher::PointOnObject) {
00402                 if ((*it)->First == GeoId && (*it)->FirstPos == PosId) {
00403                     if (replaceGeoId != -1) { // redirect this constraint
00404                         (*it)->First = replaceGeoId;
00405                         (*it)->FirstPos = replacePosId;
00406                     }
00407                     else
00408                         continue; // skip this constraint
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                     // we could keep the tangency constraint by converting it
00415                     // to a simple one but it is not really worth
00416                     continue; // skip this constraint
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; // skip this constraint
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; // no such constraint
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     // Find the other geometry Id associated with the coincident point
00462     std::vector<int> GeoIdList;
00463     std::vector<PointPos> PosIdList;
00464     getCoincidentPoints(GeoId, PosId, GeoIdList, PosIdList);
00465 
00466     // only coincident points between two edges can be filleted
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         // the intersection point will and two distances will be necessary later for trimming the lines
00505         Base::Vector3d intersection, dist1, dist2;
00506 
00507         // create arc from known parameters and lines
00508         int filletId;
00509         Part::GeomArcOfCircle *arc = Part::createFilletGeometry(lineSeg1, lineSeg2, filletCenter, radius);
00510         if (arc) {
00511             // calculate intersection and distances before we invalidate lineSeg1 and lineSeg2
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                     // go through all constraints and replace the point (GeoId,end) with (newGeoId,end)
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                     // constrain the trimming points on the corresponding geometries
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                     // Reset the second pos
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                     // Reset the second pos
00655                     newConstr->SecondPos = Sketcher::none;
00656 
00657                     // new line segments colinear
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) { // drop the first intersection point
00668                 std::swap(GeoId1,GeoId2);
00669                 std::swap(point1,point2);
00670             } else if (x2 > 0.999*length) { // drop the second intersection point
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) { // trim line start
00694                     delConstraintOnPoint(GeoId, start, false);
00695                     movePoint(GeoId, start, point1);
00696 
00697                     // constrain the trimming point on the corresponding geometry
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) { // trim line end
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             // Trim Point between intersection points
00747 
00748             // Create a new arc to substitute Circle in geometry list and set parameters
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             // constrain the trimming points on the corresponding geometries
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             // Reset secondpos in case it was set previously
00790             newConstr->SecondPos = Sketcher::none;
00791 
00792             // Add Second Constraint
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; // this is always == 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); // x0
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; // x1
00819             double theta2 = Base::fmod(atan2(point2.y - center.y, point2.x - center.x) - startAngle, 2.f*M_PI) * dir; // x2
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                 // Trim Point between intersection points
00827                 if (theta1 < theta0 && theta2 > theta0) {
00828                     int newGeoId = addGeometry(geo);
00829                     // go through all constraints and replace the point (GeoId,end) with (newGeoId,end)
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                     // constrain the trimming points on the corresponding geometries
00838                     Sketcher::Constraint *newConstr = new Sketcher::Constraint();
00839 
00840                     // Build Constraints associated with new pair of arcs
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                     // Reset secondpos in case it was set previously
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) { // drop the second intersection point
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; // x1
00927             if (theta1 >= 0.001*arcLength && theta1 <= 0.999*arcLength) {
00928                 if (theta1 > theta0) { // trim arc start
00929                     delConstraintOnPoint(GeoId, start, false);
00930                     Part::GeomArcOfCircle *aoc1 = dynamic_cast<Part::GeomArcOfCircle*>(geomlist[GeoId]);
00931                     aoc1->setRange(startAngle + theta1, endAngle);
00932                     // constrain the trimming point on the corresponding geometry
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 { // trim arc end
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     // so far only externals to the support of the sketch
00973     assert(Support.getValue() == Obj);
00974 
00975     // get the actual lists of the externals
00976     std::vector<DocumentObject*> Objects     = ExternalConstraints.getValues();
00977     std::vector<std::string>     SubElements = ExternalConstraints.getSubValues();
00978 
00979     // add the new ones
00980     Objects.push_back(Obj);
00981     SubElements.push_back(std::string(SubName));
00982 
00983     // set the Link list.
00984     ExternalConstraints.setValues(Objects,SubElements);
00985 
00986     return ExternalConstraints.getValues().size()-1;
00987 }
00988 
00989 int SketchObject::delExternal(int ConstrId)
00990 {
00991     // FIXME: still to implement
00992     return 0;
00993 
00994 }
00995 
00996 std::vector<Part::Geometry *> getExternalGeometry(void)
00997 {
00998     std::vector<Part::Geometry *> ExtGeos;
00999 
01000     // add the root point (0,0) the the external geos(-1)
01001     ExtGeos.push_back(new Part::GeomPoint(Base::Vector3d(0,0,0)));
01002 
01003     // add the X,Y (V,H) axis (-2,-3)
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     // return the result set
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         // ref counter is set to 1
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     // save the father classes
01107     Part::Part2DObject::Save(writer);
01108 }
01109 
01110 void SketchObject::Restore(XMLReader &reader)
01111 {
01112     // read the father classes
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 // Python Sketcher feature ---------------------------------------------------------
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 // explicit template instantiation
01147 template class SketcherExport FeaturePythonT<Sketcher::SketchObject>;
01148 }

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