Sketch.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) Jürgen Riegel          (juergen.riegel@web.de) 2010     *
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 <BRep_Builder.hxx>
00027 # include <TopoDS_Compound.hxx>
00028 #endif
00029 
00030 #include <Base/Writer.h>
00031 #include <Base/Reader.h>
00032 #include <Base/Exception.h>
00033 #include <Base/TimeInfo.h>
00034 #include <Base/Console.h>
00035 
00036 #include <Base/VectorPy.h>
00037 
00038 #include <Mod/Part/App/Geometry.h>
00039 #include <Mod/Part/App/GeometryCurvePy.h>
00040 #include <Mod/Part/App/ArcOfCirclePy.h>
00041 #include <Mod/Part/App/CirclePy.h>
00042 #include <Mod/Part/App/EllipsePy.h>
00043 #include <Mod/Part/App/LinePy.h>
00044 
00045 #include <TopoDS.hxx>
00046 #include <TopoDS_Edge.hxx>
00047 #include <BRepBuilderAPI_MakeWire.hxx>
00048 
00049 #include "Sketch.h"
00050 #include "Constraint.h"
00051 #include <math.h>
00052 
00053 #include <iostream>
00054 
00055 
00056 using namespace Sketcher;
00057 using namespace Base;
00058 using namespace Part;
00059 
00060 TYPESYSTEM_SOURCE(Sketcher::Sketch, Base::Persistence)
00061 
00062 Sketch::Sketch()
00063 : GCSsys(), ConstraintsCounter(0), isInitMove(false)
00064 {
00066     //addPoint(Base::Vector3d());
00068     //Part::GeomLineSegment axis;
00069     //axis.setPoints(Base::Vector3d(0,0,0),Base::Vector3d(100,0,0));
00070     //addLineSegment(axis);
00071     //axis.setPoints(Base::Vector3d(0,0,0),Base::Vector3d(0,100,0));
00072     //addLineSegment(axis);
00073 
00074     // set them to construction elements
00075 
00076 }
00077 
00078 Sketch::~Sketch()
00079 {
00080     clear();
00081 }
00082 
00083 void Sketch::clear(void)
00084 {
00085     // clear all internal data sets
00086     Points.clear();
00087     Lines.clear();
00088     Arcs.clear();
00089     Circles.clear();
00090 
00091     // deleting the doubles allocated with new
00092     for (std::vector<double*>::iterator it = Parameters.begin(); it != Parameters.end(); ++it)
00093         if (*it) delete *it;
00094     Parameters.clear();
00095     for (std::vector<double*>::iterator it = FixParameters.begin(); it != FixParameters.end(); ++it)
00096         if (*it) delete *it;
00097     FixParameters.clear();
00098 
00099     // deleting the geometry copied into this sketch
00100     for (std::vector<GeoDef>::iterator it = Geoms.begin(); it != Geoms.end(); ++it)
00101         if (it->geo) delete it->geo;
00102     Geoms.clear();
00103 
00104     GCSsys.clear();
00105     isInitMove = false;
00106     ConstraintsCounter = 0;
00107     Conflicting.clear();
00108 }
00109 
00110 int Sketch::setUpSketch(const std::vector<Part::Geometry *> &GeoList, const std::vector<Constraint *> &ConstraintList,
00111                         bool withDiagnose)
00112 {
00113     clear();
00114 
00115     for (std::vector<Part::Geometry *>::const_iterator it = GeoList.begin(); it != GeoList.end(); ++it) {
00116         if ((*it)->getTypeId()== GeomLineSegment::getClassTypeId()) { // add a line
00117             const GeomLineSegment *lineSeg = dynamic_cast<const GeomLineSegment*>((*it));
00118             // create the definition struct for that geom
00119             addLineSegment(*lineSeg);
00120         } else if ((*it)->getTypeId()== GeomCircle::getClassTypeId()) {
00121             const GeomCircle *circle = dynamic_cast<const GeomCircle*>((*it));
00122             addCircle(*circle);
00123         } else if ((*it)->getTypeId()== GeomArcOfCircle::getClassTypeId()) {
00124             const GeomArcOfCircle *aoc = dynamic_cast<const GeomArcOfCircle*>((*it));
00125             addArc(*aoc);
00126         } else {
00127             Base::Exception("Sketch::setUpSketch(): Unknown or unsupported type added to a sketch");
00128         }
00129     }
00130 
00131     // The Geoms list might be empty after an undo/redo
00132     if (!Geoms.empty())
00133         addConstraints(ConstraintList);
00134 
00135     GCSsys.clearByTag(-1);
00136     GCSsys.clearByTag(-2);
00137     GCSsys.initSolution(Parameters);
00138 
00139     if (withDiagnose)
00140         return diagnose();
00141     else
00142         return 0;
00143 }
00144 
00145 const char* nameByType(Sketch::GeoType type)
00146 {
00147     switch (type) {
00148     case Sketch::Point:
00149         return "point";
00150     case Sketch::Line:
00151         return "line";
00152     case Sketch::Arc:
00153         return "arc";
00154     case Sketch::Circle:
00155         return "circle";
00156     case Sketch::Ellipse:
00157         return "ellipse";
00158     case Sketch::None:
00159     default:
00160         return "unknown";
00161     }
00162 }
00163 
00164 // Geometry adding ==========================================================
00165 
00166 int Sketch::addGeometry(const Part::Geometry *geo)
00167 {
00168     if (geo->getTypeId()== GeomLineSegment::getClassTypeId()) { // add a line
00169         const GeomLineSegment *lineSeg = dynamic_cast<const GeomLineSegment*>(geo);
00170         // create the definition struct for that geom
00171         return addLineSegment(*lineSeg);
00172     } else if (geo->getTypeId()== GeomCircle::getClassTypeId()) { // add a circle
00173         const GeomCircle *circle = dynamic_cast<const GeomCircle*>(geo);
00174         // create the definition struct for that geom
00175         return addCircle(*circle);
00176     } else if (geo->getTypeId()== GeomArcOfCircle::getClassTypeId()) { // add an arc
00177         const GeomArcOfCircle *aoc = dynamic_cast<const GeomArcOfCircle*>(geo);
00178         // create the definition struct for that geom
00179         return addArc(*aoc);
00180     } else {
00181         Base::Exception("Sketch::addGeometry(): Unknown or unsupported type added to a sketch");
00182         return 0;
00183     }
00184 }
00185 
00186 void Sketch::addGeometry(const std::vector<Part::Geometry *> &geo)
00187 {
00188     for (std::vector<Part::Geometry *>::const_iterator it = geo.begin();it!=geo.end();++it)
00189         addGeometry(*it);
00190 }
00191 
00192 int Sketch::addPoint(const Base::Vector3d &newPoint)
00193 {
00194     // create the definition struct for that geom
00195     GeoDef def;
00196     def.geo  = 0;
00197     def.type = Point;
00198     def.construction = false;
00199 
00200     // set the parameter for the solver
00201     int paramStartIndex = Parameters.size();
00202     Parameters.push_back(new double(newPoint.x));
00203     Parameters.push_back(new double(newPoint.y));
00204 
00205     // set the points for later constraints
00206     GCS::Point p1;
00207     p1.x = Parameters[paramStartIndex+0];
00208     p1.y = Parameters[paramStartIndex+1];
00209     def.startPointId = Points.size();
00210     Points.push_back(p1);
00211 
00212     // store complete set
00213     Geoms.push_back(def);
00214 
00215     // return the position of the newly added geometry
00216     return Geoms.size()-1;
00217 }
00218 
00219 int Sketch::addLine(const Part::GeomLineSegment &line)
00220 {
00221 
00222     // return the position of the newly added geometry
00223     return Geoms.size()-1;
00224 }
00225 
00226 int Sketch::addLineSegment(const Part::GeomLineSegment &lineSegment)
00227 {
00228     // create our own copy
00229     GeomLineSegment *lineSeg = static_cast<GeomLineSegment*>(lineSegment.clone());
00230     // create the definition struct for that geom
00231     GeoDef def;
00232     def.geo  = lineSeg;
00233     def.type = Line;
00234     def.construction = lineSeg->Construction;
00235 
00236     // get the points from the line
00237     Base::Vector3d start = lineSeg->getStartPoint();
00238     Base::Vector3d end   = lineSeg->getEndPoint();
00239 
00240     // the points for later constraints
00241     GCS::Point p1, p2;
00242 
00243     Parameters.push_back(new double(start.x));
00244     Parameters.push_back(new double(start.y));
00245     p1.x = Parameters[Parameters.size()-2];
00246     p1.y = Parameters[Parameters.size()-1];
00247 
00248     Parameters.push_back(new double(end.x));
00249     Parameters.push_back(new double(end.y));
00250     p2.x = Parameters[Parameters.size()-2];
00251     p2.y = Parameters[Parameters.size()-1];
00252 
00253     // add the points
00254     def.startPointId = Points.size();
00255     def.endPointId = Points.size()+1;
00256     Points.push_back(p1);
00257     Points.push_back(p2);
00258 
00259     // set the line for later constraints
00260     GCS::Line l;
00261     l.p1 = p1;
00262     l.p2 = p2;
00263     def.index = Lines.size();
00264     Lines.push_back(l);
00265 
00266     // store complete set
00267     Geoms.push_back(def);
00268 
00269     // return the position of the newly added geometry
00270     return Geoms.size()-1;
00271 }
00272 
00273 int Sketch::addArc(const Part::GeomArcOfCircle &circleSegment)
00274 {
00275     // create our own copy
00276     GeomArcOfCircle *aoc = static_cast<GeomArcOfCircle*>(circleSegment.clone());
00277     // create the definition struct for that geom
00278     GeoDef def;
00279     def.geo  = aoc;
00280     def.type = Arc;
00281     def.construction = aoc->Construction;
00282 
00283     Base::Vector3d center   = aoc->getCenter();
00284     Base::Vector3d startPnt = aoc->getStartPoint();
00285     Base::Vector3d endPnt   = aoc->getEndPoint();
00286     double radius           = aoc->getRadius();
00287     double startAngle, endAngle;
00288     aoc->getRange(startAngle, endAngle);
00289 
00290     GCS::Point p1, p2, p3;
00291 
00292     Parameters.push_back(new double(startPnt.x));
00293     Parameters.push_back(new double(startPnt.y));
00294     p1.x = Parameters[Parameters.size()-2];
00295     p1.y = Parameters[Parameters.size()-1];
00296 
00297     Parameters.push_back(new double(endPnt.x));
00298     Parameters.push_back(new double(endPnt.y));
00299     p2.x = Parameters[Parameters.size()-2];
00300     p2.y = Parameters[Parameters.size()-1];
00301 
00302     Parameters.push_back(new double(center.x));
00303     Parameters.push_back(new double(center.y));
00304     p3.x = Parameters[Parameters.size()-2];
00305     p3.y = Parameters[Parameters.size()-1];
00306 
00307     def.startPointId = Points.size();
00308     Points.push_back(p1);
00309     def.endPointId = Points.size();
00310     Points.push_back(p2);
00311     def.midPointId = Points.size();
00312     Points.push_back(p3);
00313 
00314     Parameters.push_back(new double(radius));
00315     double *r = Parameters[Parameters.size()-1];
00316     Parameters.push_back(new double(startAngle));
00317     double *a1 = Parameters[Parameters.size()-1];
00318     Parameters.push_back(new double(endAngle));
00319     double *a2 = Parameters[Parameters.size()-1];
00320 
00321     // set the arc for later constraints
00322     GCS::Arc a;
00323     a.start      = p1;
00324     a.end        = p2;
00325     a.center     = p3;
00326     a.rad        = r;
00327     a.startAngle = a1;
00328     a.endAngle   = a2;
00329     def.index = Arcs.size();
00330     Arcs.push_back(a);
00331 
00332     // store complete set
00333     Geoms.push_back(def);
00334 
00335     // arcs require an ArcRules constraint for the end points
00336     GCSsys.addConstraintArcRules(a);
00337 
00338     // return the position of the newly added geometry
00339     return Geoms.size()-1;
00340 }
00341 
00342 int Sketch::addCircle(const Part::GeomCircle &cir)
00343 {
00344     // create our own copy
00345     GeomCircle *circ = static_cast<GeomCircle*>(cir.clone());
00346     // create the definition struct for that geom
00347     GeoDef def;
00348     def.geo  = circ;
00349     def.type = Circle;
00350     def.construction = circ->Construction;
00351 
00352     Base::Vector3d center = circ->getCenter();
00353     double radius         = circ->getRadius();
00354 
00355     GCS::Point p1;
00356 
00357     Parameters.push_back(new double(center.x));
00358     Parameters.push_back(new double(center.y));
00359     p1.x = Parameters[Parameters.size()-2];
00360     p1.y = Parameters[Parameters.size()-1];
00361 
00362     Parameters.push_back(new double(radius));
00363 
00364     def.midPointId = Points.size();
00365     Points.push_back(p1);
00366 
00367     // add the radius parameter
00368     double *r = Parameters[Parameters.size()-1];
00369 
00370     // set the circle for later constraints
00371     GCS::Circle c;
00372     c.center = p1;
00373     c.rad    = r;
00374     def.index = Circles.size();
00375     Circles.push_back(c);
00376 
00377     // store complete set
00378     Geoms.push_back(def);
00379 
00380     // return the position of the newly added geometry
00381     return Geoms.size()-1;
00382 }
00383 
00384 int Sketch::addEllipse(const Part::GeomEllipse &ellipse)
00385 {
00386     // return the position of the newly added geometry
00387     return Geoms.size()-1;
00388 }
00389 
00390 std::vector<Part::Geometry *> Sketch::getGeometry(bool withConstrucionElements) const
00391 {
00392     std::vector<Part::Geometry *> temp(Geoms.size());
00393     int i=0;
00394     std::vector<GeoDef>::const_iterator it=Geoms.begin();
00395 
00396     for (;it!=Geoms.end();++it,i++)
00397         if (!it->construction || withConstrucionElements)
00398             temp[i] = it->geo->clone();
00399 
00400     return temp;
00401 }
00402 
00403 Py::Tuple Sketch::getPyGeometry(void) const
00404 {
00405     Py::Tuple tuple(Geoms.size());
00406     int i=0;
00407     std::vector<GeoDef>::const_iterator it=Geoms.begin();
00408 
00409     for (;it!=Geoms.end();++it,i++) {
00410         if (it->type == Line) {
00411             GeomLineSegment *lineSeg = dynamic_cast<GeomLineSegment*>(it->geo->clone());
00412             tuple[i] = Py::asObject(new LinePy(lineSeg));
00413         } else if (it->type == Arc) {
00414             GeomArcOfCircle *aoc = dynamic_cast<GeomArcOfCircle*>(it->geo->clone());
00415             tuple[i] = Py::asObject(new ArcOfCirclePy(aoc));
00416         } else if (it->type == Circle) {
00417             GeomCircle *circle = dynamic_cast<GeomCircle*>(it->geo->clone());
00418             tuple[i] = Py::asObject(new CirclePy(circle));
00419         } else if (it->type == Point) {
00420             Base::Vector3d temp(*(Points[Geoms[i].startPointId].x),*(Points[Geoms[i].startPointId].y),0);
00421             tuple[i] = Py::asObject(new VectorPy(temp));
00422         } else if (it->type == Ellipse) {
00423             GeomEllipse *ellipse = dynamic_cast<GeomEllipse*>(it->geo->clone());
00424             tuple[i] = Py::asObject(new EllipsePy(ellipse));
00425         } else {
00426             // not implemented type in the sketch!
00427         }
00428     }
00429     return tuple;
00430 }
00431 
00432 void Sketch::setConstruction(int geoId, bool isConstruction)
00433 {
00434     assert(geoId < int(Geoms.size()));
00435 
00436     Geoms[geoId].construction = isConstruction;
00437 }
00438 
00439 bool Sketch::getConstruction(int geoId) const
00440 {
00441     assert(geoId < int(Geoms.size()));
00442 
00443     return Geoms[geoId].construction;
00444 }
00445 
00446 // constraint adding ==========================================================
00447 
00448 int Sketch::addConstraint(const Constraint *constraint)
00449 {
00450     // constraints on nothing makes no sense
00451     assert(int(Geoms.size()) > 0);
00452     int rtn = -1;
00453     switch (constraint->Type) {
00454     case DistanceX:
00455         if (constraint->FirstPos == none) // horizontal length of a line
00456             rtn = addDistanceXConstraint(constraint->First,constraint->Value);
00457         else if (constraint->Second == Constraint::GeoUndef) // point on fixed x-coordinate
00458             rtn = addCoordinateXConstraint(constraint->First,constraint->FirstPos,constraint->Value);
00459         else if (constraint->SecondPos != none) // point to point horizontal distance
00460             rtn = addDistanceXConstraint(constraint->First,constraint->FirstPos,
00461                                          constraint->Second,constraint->SecondPos,constraint->Value);
00462         break;
00463     case DistanceY:
00464         if (constraint->FirstPos == none) // vertical length of a line
00465             rtn = addDistanceYConstraint(constraint->First,constraint->Value);
00466         else if (constraint->Second == Constraint::GeoUndef) // point on fixed y-coordinate
00467             rtn = addCoordinateYConstraint(constraint->First,constraint->FirstPos,constraint->Value);
00468         else if (constraint->SecondPos != none) // point to point vertical distance
00469             rtn = addDistanceYConstraint(constraint->First,constraint->FirstPos,
00470                                          constraint->Second,constraint->SecondPos,constraint->Value);
00471         break;
00472     case Horizontal:
00473         if (constraint->Second == Constraint::GeoUndef) // horizontal line
00474             rtn = addHorizontalConstraint(constraint->First);
00475         else // two points on the same horizontal line
00476             rtn = addHorizontalConstraint(constraint->First,constraint->FirstPos,
00477                                           constraint->Second,constraint->SecondPos);
00478         break;
00479     case Vertical:
00480         if (constraint->Second == Constraint::GeoUndef) // vertical line
00481             rtn = addVerticalConstraint(constraint->First);
00482         else // two points on the same vertical line
00483             rtn = addVerticalConstraint(constraint->First,constraint->FirstPos,
00484                                         constraint->Second,constraint->SecondPos);
00485         break;
00486     case Coincident:
00487         rtn = addPointCoincidentConstraint(constraint->First,constraint->FirstPos,constraint->Second,constraint->SecondPos);
00488         break;
00489     case PointOnObject:
00490         rtn = addPointOnObjectConstraint(constraint->First,constraint->FirstPos, constraint->Second);
00491         break;
00492     case Parallel:
00493         rtn = addParallelConstraint(constraint->First,constraint->Second);
00494         break;
00495     case Perpendicular:
00496         rtn = addPerpendicularConstraint(constraint->First,constraint->Second);
00497         break;
00498     case Tangent:
00499         if (constraint->SecondPos != none) // tangency at common point
00500             rtn = addTangentConstraint(constraint->First,constraint->FirstPos,
00501                                        constraint->Second,constraint->SecondPos);
00502         else if (constraint->Second != Constraint::GeoUndef) {
00503             if (constraint->FirstPos != none) // "First" is a tangency point
00504                 rtn = addTangentConstraint(constraint->First,constraint->FirstPos,
00505                                            constraint->Second);
00506             else // simple tangency
00507                 rtn = addTangentConstraint(constraint->First,constraint->Second);
00508         }
00509         break;
00510     case Distance:
00511         if (constraint->SecondPos != none) // point to point distance
00512             rtn = addDistanceConstraint(constraint->First,constraint->FirstPos,
00513                                         constraint->Second,constraint->SecondPos,
00514                                         constraint->Value);
00515         else if (constraint->Second != Constraint::GeoUndef) {
00516             if (constraint->FirstPos != none) // point to line distance
00517                 rtn = addDistanceConstraint(constraint->First,constraint->FirstPos,
00518                                             constraint->Second,constraint->Value);
00519             else // line to line distance (not implemented yet)
00520                 rtn = addDistanceConstraint(constraint->First,constraint->Second,constraint->Value);
00521         }
00522         else // line length
00523             rtn = addDistanceConstraint(constraint->First,constraint->Value);
00524         break;
00525     case Angle:
00526         if (constraint->SecondPos != none) // angle between two lines (with explicit start points)
00527             rtn = addAngleConstraint(constraint->First,constraint->FirstPos,
00528                                      constraint->Second,constraint->SecondPos,constraint->Value);
00529         else if (constraint->Second != Constraint::GeoUndef) // angle between two lines
00530             rtn = addAngleConstraint(constraint->First,constraint->Second,constraint->Value);
00531         else if (constraint->First != Constraint::GeoUndef) // orientation angle of a line
00532             rtn = addAngleConstraint(constraint->First,constraint->Value);
00533         break;
00534     case Radius:
00535         rtn = addRadiusConstraint(constraint->First, constraint->Value);
00536         break;
00537     case Equal:
00538         rtn = addEqualConstraint(constraint->First,constraint->Second);
00539         break;
00540     case Symmetric:
00541         rtn = addSymmetricConstraint(constraint->First,constraint->FirstPos,
00542                                      constraint->Second,constraint->SecondPos,constraint->Third);
00543         break;
00544     case None:
00545         break;
00546     }
00547     return rtn;
00548 }
00549 
00550 int Sketch::addConstraints(const std::vector<Constraint *> &ConstraintList)
00551 {
00552     // constraints on nothing makes no sense
00553     assert(!Geoms.empty() || ConstraintList.empty());
00554 
00555     int rtn = -1;
00556     for (std::vector<Constraint *>::const_iterator it = ConstraintList.begin();it!=ConstraintList.end();++it)
00557         rtn = addConstraint (*it);
00558 
00559     return rtn;
00560 }
00561 
00562 int Sketch::addCoordinateXConstraint(int geoId, PointPos pos, double value)
00563 {
00564     int pointId = getPointId(geoId, pos);
00565 
00566     if (pointId >= 0 && pointId < int(Points.size())) {
00567         double *val = new double(value);
00568         FixParameters.push_back(val);
00569         GCS::Point &p = Points[pointId];
00570         int tag = ++ConstraintsCounter;
00571         GCSsys.addConstraintCoordinateX(p, val, tag);
00572         return ConstraintsCounter;
00573     }
00574     return -1;
00575 }
00576 
00577 int Sketch::addCoordinateYConstraint(int geoId, PointPos pos, double value)
00578 {
00579     int pointId = getPointId(geoId, pos);
00580 
00581     if (pointId >= 0 && pointId < int(Points.size())) {
00582         double *val = new double(value);
00583         FixParameters.push_back(val);
00584         GCS::Point &p = Points[pointId];
00585         int tag = ++ConstraintsCounter;
00586         GCSsys.addConstraintCoordinateY(p, val, tag);
00587         return ConstraintsCounter;
00588     }
00589     return -1;
00590 }
00591 
00592 int Sketch::addDistanceXConstraint(int geoId, double value)
00593 {
00594     assert(geoId < int(Geoms.size()));
00595     if (Geoms[geoId].type != Line)
00596         return -1;
00597 
00598     GCS::Line &l = Lines[Geoms[geoId].index];
00599 
00600     FixParameters.push_back(new double(value));
00601     double *diff = FixParameters[FixParameters.size()-1];
00602 
00603     int tag = ++ConstraintsCounter;
00604     GCSsys.addConstraintDifference(l.p1.x, l.p2.x, diff, tag);
00605     return ConstraintsCounter;
00606 }
00607 
00608 int Sketch::addDistanceYConstraint(int geoId, double value)
00609 {
00610     assert(geoId < int(Geoms.size()));
00611     if (Geoms[geoId].type != Line)
00612         return -1;
00613 
00614     GCS::Line &l = Lines[Geoms[geoId].index];
00615 
00616     FixParameters.push_back(new double(value));
00617     double *diff = FixParameters[FixParameters.size()-1];
00618 
00619     int tag = ++ConstraintsCounter;
00620     GCSsys.addConstraintDifference(l.p1.y, l.p2.y, diff, tag);
00621     return ConstraintsCounter;
00622 }
00623 
00624 int Sketch::addDistanceXConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value)
00625 {
00626     int pointId1 = getPointId(geoId1, pos1);
00627     int pointId2 = getPointId(geoId2, pos2);
00628 
00629     if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
00630         pointId2 >= 0 && pointId2 < int(Points.size())) {
00631         GCS::Point &p1 = Points[pointId1];
00632         GCS::Point &p2 = Points[pointId2];
00633 
00634         FixParameters.push_back(new double(value));
00635         double *difference = FixParameters[FixParameters.size()-1];
00636 
00637         int tag = ++ConstraintsCounter;
00638         GCSsys.addConstraintDifference(p1.x, p2.x, difference, tag);
00639         return ConstraintsCounter;
00640     }
00641     return -1;
00642 }
00643 
00644 int Sketch::addDistanceYConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value)
00645 {
00646     int pointId1 = getPointId(geoId1, pos1);
00647     int pointId2 = getPointId(geoId2, pos2);
00648 
00649     if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
00650         pointId2 >= 0 && pointId2 < int(Points.size())) {
00651         GCS::Point &p1 = Points[pointId1];
00652         GCS::Point &p2 = Points[pointId2];
00653 
00654         FixParameters.push_back(new double(value));
00655         double *difference = FixParameters[FixParameters.size()-1];
00656 
00657         int tag = ++ConstraintsCounter;
00658         GCSsys.addConstraintDifference(p1.y, p2.y, difference, tag);
00659         return ConstraintsCounter;
00660     }
00661     return -1;
00662 }
00663 
00664 // horizontal line constraint
00665 int Sketch::addHorizontalConstraint(int geoId)
00666 {
00667     assert(geoId < int(Geoms.size()));
00668     if (Geoms[geoId].type != Line)
00669         return -1;
00670 
00671     GCS::Line &l = Lines[Geoms[geoId].index];
00672     int tag = ++ConstraintsCounter;
00673     GCSsys.addConstraintHorizontal(l, tag);
00674     return ConstraintsCounter;
00675 }
00676 
00677 // two points on a horizontal line constraint
00678 int Sketch::addHorizontalConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2)
00679 {
00680     int pointId1 = getPointId(geoId1, pos1);
00681     int pointId2 = getPointId(geoId2, pos2);
00682 
00683     if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
00684         pointId2 >= 0 && pointId2 < int(Points.size())) {
00685         GCS::Point &p1 = Points[pointId1];
00686         GCS::Point &p2 = Points[pointId2];
00687         int tag = ++ConstraintsCounter;
00688         GCSsys.addConstraintHorizontal(p1, p2, tag);
00689         return ConstraintsCounter;
00690     }
00691     return -1;
00692 }
00693 
00694 // vertical line constraint
00695 int Sketch::addVerticalConstraint(int geoId)
00696 {
00697     assert(geoId < int(Geoms.size()));
00698     if (Geoms[geoId].type != Line)
00699         return -1;
00700 
00701     GCS::Line &l = Lines[Geoms[geoId].index];
00702     int tag = ++ConstraintsCounter;
00703     GCSsys.addConstraintVertical(l, tag);
00704     return ConstraintsCounter;
00705 }
00706 
00707 // two points on a vertical line constraint
00708 int Sketch::addVerticalConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2)
00709 {
00710     int pointId1 = getPointId(geoId1, pos1);
00711     int pointId2 = getPointId(geoId2, pos2);
00712 
00713     if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
00714         pointId2 >= 0 && pointId2 < int(Points.size())) {
00715         GCS::Point &p1 = Points[pointId1];
00716         GCS::Point &p2 = Points[pointId2];
00717         int tag = ++ConstraintsCounter;
00718         GCSsys.addConstraintVertical(p1, p2, tag);
00719         return ConstraintsCounter;
00720     }
00721     return -1;
00722 }
00723 
00724 int Sketch::addPointCoincidentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2)
00725 {
00726     int pointId1 = getPointId(geoId1, pos1);
00727     int pointId2 = getPointId(geoId2, pos2);
00728 
00729     if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
00730         pointId2 >= 0 && pointId2 < int(Points.size())) {
00731         GCS::Point &p1 = Points[pointId1];
00732         GCS::Point &p2 = Points[pointId2];
00733         int tag = ++ConstraintsCounter;
00734         // trick: we do not tag coincidence constraints in order to exclude
00735         //        them from the diagnosing of conflicts
00736         //GCSsys.addConstraintP2PCoincident(p1, p2, tag);
00737         GCSsys.addConstraintP2PCoincident(p1, p2);
00738         return ConstraintsCounter;
00739     }
00740     return -1;
00741 }
00742 
00743 int Sketch::addParallelConstraint(int geoId1, int geoId2)
00744 {
00745     assert(geoId1 < int(Geoms.size()));
00746     assert(geoId2 < int(Geoms.size()));
00747     if (Geoms[geoId1].type != Line ||
00748         Geoms[geoId2].type != Line)
00749         return -1;
00750 
00751     GCS::Line &l1 = Lines[Geoms[geoId1].index];
00752     GCS::Line &l2 = Lines[Geoms[geoId2].index];
00753     int tag = ++ConstraintsCounter;
00754     GCSsys.addConstraintParallel(l1, l2, tag);
00755     return ConstraintsCounter;
00756 }
00757 
00758 int Sketch::addPerpendicularConstraint(int geoId1, int geoId2)
00759 {
00760     assert(geoId1 < int(Geoms.size()));
00761     assert(geoId2 < int(Geoms.size()));
00762 
00763     if (Geoms[geoId2].type == Line) {
00764         if (Geoms[geoId1].type == Line) {
00765             GCS::Line &l1 = Lines[Geoms[geoId1].index];
00766             GCS::Line &l2 = Lines[Geoms[geoId2].index];
00767             int tag = ++ConstraintsCounter;
00768             GCSsys.addConstraintPerpendicular(l1, l2, tag);
00769             return ConstraintsCounter;
00770         }
00771         else
00772             std::swap(geoId1, geoId2);
00773     }
00774 
00775     if (Geoms[geoId1].type == Line) {
00776         GCS::Line &l = Lines[Geoms[geoId1].index];
00777         if (Geoms[geoId2].type == Arc) {
00778             GCS::Arc &a = Arcs[Geoms[geoId2].index];
00779             //GCSsys.addConstraintPerpendicular(l, a);
00780             Base::Console().Warning("Perpendicular constraints between lines and arcs are not implemented yet.\n");
00781             return -1;
00782         } else if (Geoms[geoId2].type == Circle) {
00783             GCS::Circle &c = Circles[Geoms[geoId2].index];
00784             //GCSsys.addConstraintPerpendicular(l, c);
00785             Base::Console().Warning("Perpendicular constraints between lines and circles are not implemented yet.\n");
00786             return -1;
00787         }
00788     }
00789 
00790     Base::Console().Warning("Perpendicular constraints between %s and %s are not supported.\n",
00791                             nameByType(Geoms[geoId1].type), nameByType(Geoms[geoId2].type));
00792     return -1;
00793 }
00794 
00795 // simple tangency constraint
00796 int Sketch::addTangentConstraint(int geoId1, int geoId2)
00797 {
00798     // accepts the following combinations:
00799     // 1) Line1, Line2/Circle2/Arc2
00800     // 2) Circle1, Line2 (converted to case #1)
00801     //    Circle1, Circle2/Arc2 (not implemented yet)
00802     // 3) Arc1, Line2 (converted to case #1)
00803     //    Arc1, Circle2/Arc2 (not implemented yet)
00804     assert(geoId1 < int(Geoms.size()));
00805     assert(geoId2 < int(Geoms.size()));
00806 
00807     if (Geoms[geoId2].type == Line) {
00808         if (Geoms[geoId1].type == Line) {
00809             GCS::Line &l1 = Lines[Geoms[geoId1].index];
00810             GCS::Point &l2p1 = Points[Geoms[geoId2].startPointId];
00811             GCS::Point &l2p2 = Points[Geoms[geoId2].endPointId];
00812             int tag = ++ConstraintsCounter;
00813             GCSsys.addConstraintPointOnLine(l2p1, l1, tag);
00814             GCSsys.addConstraintPointOnLine(l2p2, l1, tag);
00815             return ConstraintsCounter;
00816         }
00817         else
00818             std::swap(geoId1, geoId2);
00819     }
00820 
00821     if (Geoms[geoId1].type == Line) {
00822         GCS::Line &l = Lines[Geoms[geoId1].index];
00823         if (Geoms[geoId2].type == Arc) {
00824             GCS::Arc &a = Arcs[Geoms[geoId2].index];
00825             int tag = ++ConstraintsCounter;
00826             GCSsys.addConstraintTangent(l, a, tag);
00827             return ConstraintsCounter;
00828         } else if (Geoms[geoId2].type == Circle) {
00829             GCS::Circle &c = Circles[Geoms[geoId2].index];
00830             int tag = ++ConstraintsCounter;
00831             GCSsys.addConstraintTangent(l, c, tag);
00832             return ConstraintsCounter;
00833         }
00834     } else
00835         Base::Console().Warning("Tangency constraints between circles and arcs are not implemented yet.\n");
00836 
00837     return -1;
00838 }
00839 
00840 // tangency at specific point constraint
00841 int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2)
00842 {
00843     // accepts the following combinations:
00844     // 1) Line1, start/end/mid, Line2
00845     // 2) Line1, start/end/mid, Circle2
00846     // 3) Line1, start/end/mid, Arc2
00847     // 4) Arc1, start/end, Line2
00848     // 5) Arc1, start/end, Circle2 (not implemented yet)
00849     // 6) Arc1, start/end, Arc2 (not implemented yet)
00850 
00851     int pointId1 = getPointId(geoId1, pos1);
00852     assert(geoId2 < int(Geoms.size()));
00853 
00854     if (pointId1 < 0 || pointId1 >= int(Points.size()))
00855         return addTangentConstraint(geoId1, geoId2);
00856 
00857     GCS::Point &p1 = Points[pointId1];
00858     if (Geoms[geoId1].type == Line) {
00859         GCS::Line &l1 = Lines[Geoms[geoId1].index];
00860         if (Geoms[geoId2].type == Line) {
00861             GCS::Line &l2 = Lines[Geoms[geoId2].index];
00862             int tag = ++ConstraintsCounter;
00863             GCSsys.addConstraintPointOnLine(p1, l2, tag);
00864             GCSsys.addConstraintParallel(l1, l2, tag);
00865             return ConstraintsCounter;
00866         }
00867         else if (Geoms[geoId2].type == Arc) {
00868             GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
00869             int tag = ++ConstraintsCounter;
00870             GCSsys.addConstraintPointOnArc(p1, a2, tag);
00871             GCSsys.addConstraintTangent(l1, a2, tag);
00872             return ConstraintsCounter;
00873         }
00874         else if (Geoms[geoId2].type == Circle) {
00875             GCS::Circle &c2 = Circles[Geoms[geoId2].index];
00876             int tag = ++ConstraintsCounter;
00877             GCSsys.addConstraintPointOnCircle(p1, c2, tag);
00878             GCSsys.addConstraintTangent(l1, c2, tag);
00879             return ConstraintsCounter;
00880         }
00881     }
00882     else if (Geoms[geoId1].type == Arc) {
00883         GCS::Arc &a1 = Arcs[Geoms[geoId1].index];
00884         if (Geoms[geoId2].type == Line) {
00885             GCS::Line &l2 = Lines[Geoms[geoId2].index];
00886             int tag = ++ConstraintsCounter;
00887             GCSsys.addConstraintPointOnLine(p1, l2, tag);
00888             GCSsys.addConstraintTangent(l2, a1, tag);
00889             return ConstraintsCounter;
00890         }
00891         else if (Geoms[geoId2].type == Arc) {
00892             //GCS::Arcs &a2 = Arcs[Geoms[geoId2].index];
00893             //GCSsys.addConstraintPointOnArc(p1, a2);
00894             //GCSsys.addConstraintTangent(a1, a2);
00895             Base::Console().Warning("Tangency constraints between circles and arcs are not implemented yet.\n");
00896         }
00897         else if (Geoms[geoId2].type == Circle) {
00898             //GCS::Circle &c2 = Circles[Geoms[geoId2].index];
00899             //GCSsys.addConstraintPointOnCircle(p1, c2);
00900             //GCSsys.addConstraintTangent(a1, c2);
00901             Base::Console().Warning("Tangency constraints between circles and arcs are not implemented yet.\n");
00902         }
00903     }
00904     return -1;
00905 }
00906 
00907 // tangency at common point constraint
00908 int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2)
00909 {
00910     // accepts the following combinations:
00911     // 1) Line1, start/end/mid, Line2, start/end/mid
00912     // 2) Line1, start/end/mid, Arc2, start/end
00913     // 3) Arc1, start/end, Line2, start/end/mid (converted to case #2)
00914     // 4) Arc1, start/end, Arc2, start/end (not implemented yet)
00915 
00916     int pointId1 = getPointId(geoId1, pos1);
00917     int pointId2 = getPointId(geoId2, pos2);
00918 
00919     if (pointId1 < 0 || pointId1 >= int(Points.size()) ||
00920         pointId2 < 0 || pointId2 >= int(Points.size()))
00921         return -1;
00922 
00923     GCS::Point &p1 = Points[pointId1];
00924     GCS::Point &p2 = Points[pointId2];
00925     if (Geoms[geoId2].type == Line) {
00926         if (Geoms[geoId1].type == Line) {
00927             GCS::Line &l1 = Lines[Geoms[geoId1].index];
00928             GCS::Line &l2 = Lines[Geoms[geoId2].index];
00929             int tag = ++ConstraintsCounter;
00930             GCSsys.addConstraintP2PCoincident(p1, p2, tag);
00931             GCSsys.addConstraintParallel(l1, l2, tag);
00932             return ConstraintsCounter;
00933         }
00934         else {
00935             std::swap(geoId1, geoId2);
00936             std::swap(pos1, pos2);
00937             std::swap(pointId1, pointId2);
00938             p1 = Points[pointId1];
00939             p2 = Points[pointId2];
00940         }
00941     }
00942 
00943     if (Geoms[geoId1].type == Line) {
00944         GCS::Line &l1 = Lines[Geoms[geoId1].index];
00945         if (Geoms[geoId2].type == Line) {
00946             GCS::Line &l2 = Lines[Geoms[geoId2].index];
00947             int tag = ++ConstraintsCounter;
00948             GCSsys.addConstraintP2PCoincident(p1, p2, tag);
00949             GCSsys.addConstraintParallel(l1, l2, tag);
00950             return ConstraintsCounter;
00951         }
00952         else if (Geoms[geoId2].type == Arc) {
00953             GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
00954             if (pos2 == start) {
00955                 if (pos1 == start) {
00956                     int tag = ++ConstraintsCounter;
00957                     GCSsys.addConstraintTangentLine2Arc(l1.p2, l1.p1, a2, tag);
00958                     return ConstraintsCounter;
00959                 }
00960                 else if (pos1 == end) {
00961                     int tag = ++ConstraintsCounter;
00962                     GCSsys.addConstraintTangentLine2Arc(l1.p1, l1.p2, a2, tag);
00963                     return ConstraintsCounter;
00964                 }
00965                 else if (pos1 == mid) {
00966                     int tag = ++ConstraintsCounter;
00967                     GCSsys.addConstraintP2PCoincident(p1, p2, tag);
00968                     GCSsys.addConstraintTangent(l1, a2, tag);
00969                     return ConstraintsCounter;
00970                 }
00971             }
00972             else if (pos2 == end) {
00973                 if (pos1 == start) {
00974                     int tag = ++ConstraintsCounter;
00975                     GCSsys.addConstraintTangentArc2Line(a2, l1.p1, l1.p2, tag);
00976                     return ConstraintsCounter;
00977                 }
00978                 else if (pos1 == end) {
00979                     int tag = ++ConstraintsCounter;
00980                     GCSsys.addConstraintTangentArc2Line(a2, l1.p2, l1.p1, tag);
00981                     return ConstraintsCounter;
00982                 }
00983                 else if (pos1 == mid) {
00984                     int tag = ++ConstraintsCounter;
00985                     GCSsys.addConstraintP2PCoincident(p1, p2, tag);
00986                     GCSsys.addConstraintTangent(l1, a2, tag);
00987                     return ConstraintsCounter;
00988                 }
00989             }
00990             else
00991                 return -1;
00992         }
00993     }
00994     else if (Geoms[geoId1].type == Arc) {
00995         //GCS::Arc &a1 = Arcs[Geoms[geoId1].index];
00996         if (Geoms[geoId2].type == Arc) {
00997             //GCS::Arcs &a2 = Arcs[Geoms[geoId2].index];
00998             //GCSsys.addConstraintPointOnArc(p1, a2);
00999             //GCSsys.addConstraintTangent(a1, a2);
01000             Base::Console().Warning("Tangency constraints between arcs are not implemented yet.\n");
01001         }
01002     }
01003     return -1;
01004 }
01005 
01006 // line length constraint
01007 int Sketch::addDistanceConstraint(int geoId, double value)
01008 {
01009     assert(geoId < int(Geoms.size()));
01010     if (Geoms[geoId].type != Line)
01011         return -1;
01012 
01013     GCS::Line &l = Lines[Geoms[geoId].index];
01014 
01015     // add the parameter for the length
01016     FixParameters.push_back(new double(value));
01017     double *distance = FixParameters[FixParameters.size()-1];
01018 
01019     int tag = ++ConstraintsCounter;
01020     GCSsys.addConstraintP2PDistance(l.p1, l.p2, distance, tag);
01021     return ConstraintsCounter;
01022 }
01023 
01024 // line to line distance constraint
01025 int Sketch::addDistanceConstraint(int geoId1, int geoId2, double value)
01026 {
01027     assert(geoId1 < int(Geoms.size()));
01028     assert(geoId2 < int(Geoms.size()));
01029 
01030     //assert(Geoms[geoId1].type == Line);
01031     //assert(Geoms[geoId2].type == Line);
01032 
01033     Base::Console().Warning("Line to line distance constraints are not implemented yet.\n");
01034 
01035     return -1;
01036 }
01037 
01038 // point to line distance constraint
01039 int Sketch::addDistanceConstraint(int geoId1, PointPos pos1, int geoId2, double value)
01040 {
01041     int pointId1 = getPointId(geoId1, pos1);
01042     assert(geoId2 < int(Geoms.size()));
01043     if (Geoms[geoId2].type != Line)
01044         return -1;
01045 
01046     if (pointId1 >= 0 && pointId1 < int(Points.size())) {
01047         GCS::Point &p1 = Points[pointId1];
01048         GCS::Line &l2 = Lines[Geoms[geoId2].index];
01049 
01050         // add the parameter for the distance
01051         FixParameters.push_back(new double(value));
01052         double *distance = FixParameters[FixParameters.size()-1];
01053 
01054         int tag = ++ConstraintsCounter;
01055         GCSsys.addConstraintP2LDistance(p1, l2, distance, tag);
01056         return ConstraintsCounter;
01057     }
01058     return -1;
01059 }
01060 
01061 // point to point distance constraint
01062 int Sketch::addDistanceConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value)
01063 {
01064     int pointId1 = getPointId(geoId1, pos1);
01065     int pointId2 = getPointId(geoId2, pos2);
01066 
01067     if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
01068         pointId2 >= 0 && pointId2 < int(Points.size())) {
01069         GCS::Point &p1 = Points[pointId1];
01070         GCS::Point &p2 = Points[pointId2];
01071 
01072         // add the parameter for the distance
01073         FixParameters.push_back(new double(value));
01074         double *distance = FixParameters[FixParameters.size()-1];
01075 
01076         int tag = ++ConstraintsCounter;
01077         GCSsys.addConstraintP2PDistance(p1, p2, distance, tag);
01078         return ConstraintsCounter;
01079     }
01080     return -1;
01081 }
01082 
01083 int Sketch::addRadiusConstraint(int geoId, double value)
01084 {
01085     assert(geoId < int(Geoms.size()));
01086 
01087     if (Geoms[geoId].type == Circle) {
01088         GCS::Circle &c = Circles[Geoms[geoId].index];
01089         // add the parameter for the radius
01090         FixParameters.push_back(new double(value));
01091         double *radius = FixParameters[FixParameters.size()-1];
01092         int tag = ++ConstraintsCounter;
01093         GCSsys.addConstraintCircleRadius(c, radius, tag);
01094         return ConstraintsCounter;
01095     }
01096     else if (Geoms[geoId].type == Arc) {
01097         GCS::Arc &a = Arcs[Geoms[geoId].index];
01098         // add the parameter for the radius
01099         FixParameters.push_back(new double(value));
01100         double *radius = FixParameters[FixParameters.size()-1];
01101         int tag = ++ConstraintsCounter;
01102         GCSsys.addConstraintArcRadius(a, radius, tag);
01103         return ConstraintsCounter;
01104     }
01105     return -1;
01106 }
01107 
01108 // line orientation angle constraint
01109 int Sketch::addAngleConstraint(int geoId, double value)
01110 {
01111     assert(geoId < int(Geoms.size()));
01112     if (Geoms[geoId].type != Line)
01113         return -1;
01114 
01115     GCS::Line &l = Lines[Geoms[geoId].index];
01116 
01117     // add the parameter for the angle
01118     FixParameters.push_back(new double(value));
01119     double *angle = FixParameters[FixParameters.size()-1];
01120 
01121     int tag = ++ConstraintsCounter;
01122     GCSsys.addConstraintP2PAngle(l.p1, l.p2, angle, tag);
01123     return ConstraintsCounter;
01124 }
01125 
01126 // line to line angle constraint
01127 int Sketch::addAngleConstraint(int geoId1, int geoId2, double value)
01128 {
01129     assert(geoId1 < int(Geoms.size()));
01130     assert(geoId2 < int(Geoms.size()));
01131 
01132     if (Geoms[geoId1].type != Line ||
01133         Geoms[geoId2].type != Line)
01134         return -1;
01135 
01136     GCS::Line &l1 = Lines[Geoms[geoId1].index];
01137     GCS::Line &l2 = Lines[Geoms[geoId2].index];
01138 
01139     // add the parameter for the angle
01140     FixParameters.push_back(new double(value));
01141     double *angle = FixParameters[FixParameters.size()-1];
01142 
01143     int tag = ++ConstraintsCounter;
01144     GCSsys.addConstraintL2LAngle(l1, l2, angle, tag);
01145     return ConstraintsCounter;
01146 }
01147 
01148 // line to line angle constraint (with explicitly given start points)
01149 int Sketch::addAngleConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value)
01150 {
01151     assert(geoId1 < int(Geoms.size()));
01152     assert(geoId2 < int(Geoms.size()));
01153 
01154     if (Geoms[geoId1].type != Line ||
01155         Geoms[geoId2].type != Line)
01156         return -1;
01157 
01158     GCS::Point *l1p1=0, *l1p2=0;
01159     if (pos1 == start) {
01160         l1p1 = &Points[Geoms[geoId1].startPointId];
01161         l1p2 = &Points[Geoms[geoId1].endPointId];
01162     } else if (pos1 == end) {
01163         l1p1 = &Points[Geoms[geoId1].endPointId];
01164         l1p2 = &Points[Geoms[geoId1].startPointId];
01165     }
01166 
01167     GCS::Point *l2p1=0, *l2p2=0;
01168     if (pos2 == start) {
01169         l2p1 = &Points[Geoms[geoId2].startPointId];
01170         l2p2 = &Points[Geoms[geoId2].endPointId];
01171     } else if (pos2 == end) {
01172         l2p1 = &Points[Geoms[geoId2].endPointId];
01173         l2p2 = &Points[Geoms[geoId2].startPointId];
01174     }
01175 
01176     if (l1p1 == 0 || l2p1 == 0)
01177         return -1;
01178 
01179     // add the parameter for the angle
01180     FixParameters.push_back(new double(value));
01181     double *angle = FixParameters[FixParameters.size()-1];
01182 
01183     int tag = ++ConstraintsCounter;
01184     GCSsys.addConstraintL2LAngle(*l1p1, *l1p2, *l2p1, *l2p2, angle, tag);
01185     return ConstraintsCounter;
01186 }
01187 
01188 int Sketch::addEqualConstraint(int geoId1, int geoId2)
01189 {
01190     assert(geoId1 < int(Geoms.size()));
01191     assert(geoId2 < int(Geoms.size()));
01192 
01193     if (Geoms[geoId1].type == Line &&
01194         Geoms[geoId2].type == Line) {
01195         GCS::Line &l1 = Lines[Geoms[geoId1].index];
01196         GCS::Line &l2 = Lines[Geoms[geoId2].index];
01197         double dx1 = (*l1.p2.x - *l1.p1.x);
01198         double dy1 = (*l1.p2.y - *l1.p1.y);
01199         double dx2 = (*l2.p2.x - *l2.p1.x);
01200         double dy2 = (*l2.p2.y - *l2.p1.y);
01201         double value = (sqrt(dx1*dx1+dy1*dy1)+sqrt(dx2*dx2+dy2*dy2))/2;
01202         // add the parameter for the common length (this is added to Parameters, not FixParameters)
01203         Parameters.push_back(new double(value));
01204         double *length = Parameters[Parameters.size()-1];
01205         int tag = ++ConstraintsCounter;
01206         GCSsys.addConstraintEqualLength(l1, l2, length, tag);
01207         return ConstraintsCounter;
01208     }
01209 
01210     if (Geoms[geoId2].type == Circle) {
01211         if (Geoms[geoId1].type == Circle) {
01212             GCS::Circle &c1 = Circles[Geoms[geoId1].index];
01213             GCS::Circle &c2 = Circles[Geoms[geoId2].index];
01214             int tag = ++ConstraintsCounter;
01215             GCSsys.addConstraintEqualRadius(c1, c2, tag);
01216             return ConstraintsCounter;
01217         }
01218         else
01219             std::swap(geoId1, geoId2);
01220     }
01221 
01222     if (Geoms[geoId1].type == Circle) {
01223         GCS::Circle &c1 = Circles[Geoms[geoId1].index];
01224         if (Geoms[geoId2].type == Arc) {
01225             GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
01226             int tag = ++ConstraintsCounter;
01227             GCSsys.addConstraintEqualRadius(c1, a2, tag);
01228             return ConstraintsCounter;
01229         }
01230     }
01231 
01232     if (Geoms[geoId1].type == Arc &&
01233         Geoms[geoId2].type == Arc) {
01234         GCS::Arc &a1 = Arcs[Geoms[geoId1].index];
01235         GCS::Arc &a2 = Arcs[Geoms[geoId2].index];
01236         int tag = ++ConstraintsCounter;
01237         GCSsys.addConstraintEqualRadius(a1, a2, tag);
01238         return ConstraintsCounter;
01239     }
01240 
01241     Base::Console().Warning("Equality constraints between %s and %s are not supported.\n",
01242                             nameByType(Geoms[geoId1].type), nameByType(Geoms[geoId2].type));
01243     return -1;
01244 }
01245 
01246 // point on object constraint
01247 int Sketch::addPointOnObjectConstraint(int geoId1, PointPos pos1, int geoId2)
01248 {
01249     int pointId1 = getPointId(geoId1, pos1);
01250     assert(geoId2 < int(Geoms.size()));
01251 
01252     if (pointId1 >= 0 && pointId1 < int(Points.size())) {
01253         GCS::Point &p1 = Points[pointId1];
01254 
01255         if (Geoms[geoId2].type == Line) {
01256             GCS::Line &l2 = Lines[Geoms[geoId2].index];
01257             int tag = ++ConstraintsCounter;
01258             GCSsys.addConstraintPointOnLine(p1, l2, tag);
01259             return ConstraintsCounter;
01260         }
01261         else if (Geoms[geoId2].type == Arc) {
01262             GCS::Arc &a = Arcs[Geoms[geoId2].index];
01263             int tag = ++ConstraintsCounter;
01264             GCSsys.addConstraintPointOnArc(p1, a, tag);
01265             return ConstraintsCounter;
01266         }
01267         else if (Geoms[geoId2].type == Circle) {
01268             GCS::Circle &c = Circles[Geoms[geoId2].index];
01269             int tag = ++ConstraintsCounter;
01270             GCSsys.addConstraintPointOnCircle(p1, c, tag);
01271             return ConstraintsCounter;
01272         }
01273     }
01274     return -1;
01275 }
01276 
01277 // symmetric points constraint
01278 int Sketch::addSymmetricConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, int geoId3)
01279 {
01280     assert(geoId1 < int(Geoms.size()));
01281     assert(geoId2 < int(Geoms.size()));
01282     assert(geoId3 < int(Geoms.size()));
01283 
01284     if (Geoms[geoId3].type != Line)
01285         return -1;
01286 
01287     int pointId1 = getPointId(geoId1, pos1);
01288     int pointId2 = getPointId(geoId2, pos2);
01289 
01290     if (pointId1 >= 0 && pointId1 < int(Points.size()) &&
01291         pointId2 >= 0 && pointId2 < int(Points.size())) {
01292         GCS::Point &p1 = Points[pointId1];
01293         GCS::Point &p2 = Points[pointId2];
01294         GCS::Line &l = Lines[Geoms[geoId3].index];
01295         int tag = ++ConstraintsCounter;
01296         GCSsys.addConstraintP2PSymmetric(p1, p2, l, tag);
01297         return ConstraintsCounter;
01298     }
01299     return -1;
01300 }
01301 
01302 bool Sketch::updateGeometry()
01303 {
01304     int i=0;
01305     for (std::vector<GeoDef>::const_iterator it=Geoms.begin();it!=Geoms.end();++it,i++) {
01306         try {
01307             if (it->type == Line) {
01308                 GeomLineSegment *lineSeg = dynamic_cast<GeomLineSegment*>(it->geo);
01309                 lineSeg->setPoints(Vector3d(*Lines[it->index].p1.x,
01310                                             *Lines[it->index].p1.y,
01311                                             0.0),
01312                                    Vector3d(*Lines[it->index].p2.x,
01313                                             *Lines[it->index].p2.y,
01314                                             0.0)
01315                                   );
01316             } else if (it->type == Arc) {
01317                 GCS::Arc &myArc = Arcs[it->index];
01318                 // the following 4 lines are redundant since these equations are already included in the arc constraints
01319 //                *myArc.start.x = *myArc.center.x + *myArc.rad * cos(*myArc.startAngle);
01320 //                *myArc.start.y = *myArc.center.y + *myArc.rad * sin(*myArc.startAngle);
01321 //                *myArc.end.x = *myArc.center.x + *myArc.rad * cos(*myArc.endAngle);
01322 //                *myArc.end.y = *myArc.center.y + *myArc.rad * sin(*myArc.endAngle);
01323                 GeomArcOfCircle *aoc = dynamic_cast<GeomArcOfCircle*>(it->geo);
01324                 aoc->setCenter(Vector3d(*Points[it->midPointId].x,
01325                                         *Points[it->midPointId].y,
01326                                         0.0)
01327                               );
01328                 aoc->setRadius(*myArc.rad);
01329                 aoc->setRange(*myArc.startAngle, *myArc.endAngle);
01330             } else if (it->type == Circle) {
01331                 GeomCircle *circ = dynamic_cast<GeomCircle*>(it->geo);
01332                 circ->setCenter(Vector3d(*Points[it->midPointId].x,
01333                                          *Points[it->midPointId].y,
01334                                          0.0)
01335                                );
01336                 circ->setRadius(*Circles[it->index].rad);
01337             }
01338         } catch (Base::Exception e) {
01339             Base::Console().Error("Updating geometry: Error build geometry(%d): %s\n",
01340                                   i,e.what());
01341             return false;
01342         }
01343     }
01344     return true;
01345 }
01346 
01347 // solving ==========================================================
01348 
01349 int Sketch::solve()
01350 {
01351 
01352     Base::TimeInfo start_time;
01353     if (!isInitMove) { // make sure we are in single subsystem mode
01354         GCSsys.clearByTag(-1);
01355         GCSsys.clearByTag(-2);
01356     }
01357 
01358     int ret;
01359     bool valid_solution;
01360     for (int soltype=0; soltype < (isInitMove ? 1 : 4); soltype++) {
01361         std::string solvername;
01362         switch (soltype) {
01363         case 0: // solving with the default DogLeg solver
01364                 // (or with SQP if we are in moving mode)
01365             solvername = isInitMove ? "SQP" : "DogLeg";
01366             ret = GCSsys.solve(true, GCS::DogLeg);
01367             break;
01368         case 1: // solving with the LevenbergMarquardt solver
01369             solvername = "LevenbergMarquardt";
01370             ret = GCSsys.solve(true, GCS::LevenbergMarquardt);
01371             break;
01372         case 2: // solving with the BFGS solver
01373             solvername = "BFGS";
01374             ret = GCSsys.solve(true, GCS::BFGS);
01375             break;
01376         case 3: // last resort: augment the system with a second subsystem and use the SQP solver
01377             solvername = "SQP(augmented system)";
01378             GCSsys.clearByTag(-1);
01379             GCSsys.clearByTag(-2);
01380             InitParameters.resize(Parameters.size());
01381             int i=0;
01382             for (std::vector<double*>::iterator it = Parameters.begin(); it != Parameters.end(); ++it, i++) {
01383                 InitParameters[i] = **it;
01384                 GCSsys.addConstraintEqual(*it, &InitParameters[i], -2);
01385             }
01386             GCSsys.initSolution(Parameters);
01387             ret = GCSsys.solve(true);
01388             break;
01389         }
01390 
01391         // if successfully solved try write the parameters back
01392         if (ret == GCS::Success) {
01393             GCSsys.applySolution();
01394             valid_solution = updateGeometry();
01395             if (!valid_solution)
01396                 Base::Console().Warning("Invalid solution from %s solver.\n", solvername.c_str());
01397         } else {
01398             valid_solution = false;
01399             //Base::Console().Log("NotSolved ");
01400         }
01401 
01402         if (soltype == 3) // cleanup temporary constraints of the augmented system
01403             GCSsys.clearByTag(-2);
01404 
01405         if (valid_solution) {
01406             if (soltype == 1)
01407                 Base::Console().Log("Important: the LevenbergMarquardt solver succeeded where the DogLeg solver had failed.\n");
01408             else if (soltype == 2)
01409                 Base::Console().Log("Important: the BFGS solver succeeded where the DogLeg and LevenbergMarquardt solvers have failed.\n");
01410             else if (soltype == 3)
01411                 Base::Console().Log("Important: the SQP solver succeeded where all single subsystem solvers have failed.\n");
01412 
01413             if (soltype > 0) {
01414                 Base::Console().Log("If you see this message please report a way of reproducing this result at\n");
01415                 Base::Console().Log("https://sourceforge.net/apps/mantisbt/free-cad/main_page.php\n");
01416             }
01417 
01418             break;
01419         }
01420     } // soltype
01421 
01422     if (!valid_solution) { // undo any changes
01423         GCSsys.undoSolution();
01424         updateGeometry();
01425     }
01426 
01427     Base::TimeInfo end_time;
01428     //Base::Console().Log("T:%s\n",Base::TimeInfo::diffTime(start_time,end_time).c_str());
01429     SolveTime = Base::TimeInfo::diffTimeF(start_time,end_time);
01430     return ret;
01431 }
01432 
01433 int Sketch::initMove(int geoId, PointPos pos)
01434 {
01435     assert(geoId >= 0 && geoId < int(Geoms.size()));
01436 
01437     GCSsys.clearByTag(-1);
01438     GCSsys.clearByTag(-2);
01439 
01440     // don't try to move sketches that contain conflicting constraints
01441     if (hasConflicts()) {
01442         isInitMove = false;
01443         return -1;
01444     }
01445 
01446     if (Geoms[geoId].type == Line) {
01447         if (pos == start || pos == end) {
01448             MoveParameters.resize(2); // x,y
01449             GCS::Point p0;
01450             p0.x = &MoveParameters[0];
01451             p0.y = &MoveParameters[1];
01452             if (pos == start) {
01453                 GCS::Point &p = Points[Geoms[geoId].startPointId];
01454                 *p0.x = *p.x;
01455                 *p0.y = *p.y;
01456                 GCSsys.addConstraintP2PCoincident(p0,p,-1);
01457             } else if (pos == end) {
01458                 GCS::Point &p = Points[Geoms[geoId].endPointId];
01459                 *p0.x = *p.x;
01460                 *p0.y = *p.y;
01461                 GCSsys.addConstraintP2PCoincident(p0,p,-1);
01462             }
01463         } else if (pos == none || pos == mid) {
01464             MoveParameters.resize(4); // x1,y1,x2,y2
01465             GCS::Point p1, p2;
01466             p1.x = &MoveParameters[0];
01467             p1.y = &MoveParameters[1];
01468             p2.x = &MoveParameters[2];
01469             p2.y = &MoveParameters[3];
01470             GCS::Line &l = Lines[Geoms[geoId].index];
01471             *p1.x = *l.p1.x;
01472             *p1.y = *l.p1.y;
01473             *p2.x = *l.p2.x;
01474             *p2.y = *l.p2.y;
01475             GCSsys.addConstraintP2PCoincident(p1,l.p1,-1);
01476             GCSsys.addConstraintP2PCoincident(p2,l.p2,-1);
01477         }
01478     } else if (Geoms[geoId].type == Circle) {
01479         GCS::Point &center = Points[Geoms[geoId].midPointId];
01480         GCS::Point p0,p1;
01481         if (pos == mid) {
01482             MoveParameters.resize(2); // cx,cy
01483             p0.x = &MoveParameters[0];
01484             p0.y = &MoveParameters[1];
01485             *p0.x = *center.x;
01486             *p0.y = *center.y;
01487             GCSsys.addConstraintP2PCoincident(p0,center,-1);
01488         } else if (pos == none) {
01489             MoveParameters.resize(4); // x,y,cx,cy
01490             GCS::Circle &c = Circles[Geoms[geoId].index];
01491             p0.x = &MoveParameters[0];
01492             p0.y = &MoveParameters[1];
01493             *p0.x = *center.x;
01494             *p0.y = *center.y + *c.rad;
01495             GCSsys.addConstraintPointOnCircle(p0,c,-1);
01496             p1.x = &MoveParameters[2];
01497             p1.y = &MoveParameters[3];
01498             *p1.x = *center.x;
01499             *p1.y = *center.y;
01500             int i=GCSsys.addConstraintP2PCoincident(p1,center,-1);
01501             GCSsys.rescaleConstraint(i-1, 0.01);
01502             GCSsys.rescaleConstraint(i, 0.01);
01503         }
01504     } else if (Geoms[geoId].type == Arc) {
01505         GCS::Point &center = Points[Geoms[geoId].midPointId];
01506         GCS::Point p0,p1;
01507         if (pos == mid) {
01508             MoveParameters.resize(2); // cx,cy
01509             p0.x = &MoveParameters[0];
01510             p0.y = &MoveParameters[1];
01511             *p0.x = *center.x;
01512             *p0.y = *center.y;
01513             GCSsys.addConstraintP2PCoincident(p0,center,-1);
01514         } else if (pos == start || pos == end || pos == none) {
01515             MoveParameters.resize(4); // x,y,cx,cy
01516             if (pos == start || pos == end) {
01517                 GCS::Point &p = (pos == start) ? Points[Geoms[geoId].startPointId]
01518                                                : Points[Geoms[geoId].endPointId];;
01519                 p0.x = &MoveParameters[0];
01520                 p0.y = &MoveParameters[1];
01521                 *p0.x = *p.x;
01522                 *p0.y = *p.y;
01523                 GCSsys.addConstraintP2PCoincident(p0,p,-1);
01524             } else if (pos == none) {
01525                 GCS::Arc &a = Arcs[Geoms[geoId].index];
01526                 p0.x = &MoveParameters[0];
01527                 p0.y = &MoveParameters[1];
01528                 *p0.x = *center.x;
01529                 *p0.y = *center.y + *a.rad;
01530                 GCSsys.addConstraintPointOnArc(p0,a,-1);
01531             }
01532             p1.x = &MoveParameters[2];
01533             p1.y = &MoveParameters[3];
01534             *p1.x = *center.x;
01535             *p1.y = *center.y;
01536             int i=GCSsys.addConstraintP2PCoincident(p1,center,-1);
01537             GCSsys.rescaleConstraint(i-1, 0.01);
01538             GCSsys.rescaleConstraint(i, 0.01);
01539         }
01540     }
01541     InitParameters = MoveParameters;
01542 
01543     GCSsys.initSolution(Parameters);
01544     isInitMove = true;
01545     return 0;
01546 }
01547 
01548 int Sketch::movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative)
01549 {
01550     // index out of bounds?
01551     assert(geoId < int(Geoms.size()));
01552 
01553     // don't try to move sketches that contain conflicting constraints
01554     if (hasConflicts())
01555         return -1;
01556 
01557     if (!isInitMove)
01558         initMove(geoId, pos);
01559 
01560     if (relative) {
01561         for (int i=0; i < MoveParameters.size()-1; i+=2) {
01562             MoveParameters[i] = InitParameters[i] + toPoint.x;
01563             MoveParameters[i+1] = InitParameters[i+1] + toPoint.y;
01564         }
01565     } else if (Geoms[geoId].type == Line) {
01566         if (pos == start || pos == end) {
01567             MoveParameters[0] = toPoint.x;
01568             MoveParameters[1] = toPoint.y;
01569         } else if (pos == none || pos == mid) {
01570             double dx = (InitParameters[2]-InitParameters[0])/2;
01571             double dy = (InitParameters[3]-InitParameters[1])/2;
01572             MoveParameters[0] = toPoint.x - dx;
01573             MoveParameters[1] = toPoint.y - dy;
01574             MoveParameters[2] = toPoint.x + dx;
01575             MoveParameters[3] = toPoint.y + dy;
01576         }
01577     } else if (Geoms[geoId].type == Circle) {
01578         if (pos == mid || pos == none) {
01579             MoveParameters[0] = toPoint.x;
01580             MoveParameters[1] = toPoint.y;
01581         }
01582     } else if (Geoms[geoId].type == Arc) {
01583         if (pos == start || pos == end || pos == mid || pos == none) {
01584             MoveParameters[0] = toPoint.x;
01585             MoveParameters[1] = toPoint.y;
01586         }
01587     }
01588 
01589     return solve();
01590 }
01591 
01592 int Sketch::setDatum(int constrId, double value)
01593 {
01594     return -1;
01595 }
01596 
01597 int Sketch::getPointId(int geoId, PointPos pos) const
01598 {
01599     assert(geoId < int(Geoms.size()));
01600     switch (pos) {
01601     case start:
01602         return Geoms[geoId].startPointId;
01603     case end:
01604         return Geoms[geoId].endPointId;
01605     case mid:
01606         return Geoms[geoId].midPointId;
01607     case none:
01608         break;
01609     }
01610     return -1;
01611 }
01612 
01613 Base::Vector3d Sketch::getPoint(int geoId, PointPos pos)
01614 {
01615     int pointId = getPointId(geoId, pos);
01616     if (pointId != -1)
01617         return Base::Vector3d(*Points[pointId].x, *Points[pointId].y, 0);
01618 
01619     return Base::Vector3d();
01620 }
01621 
01622 int Sketch::diagnose(void)
01623 {
01624     Conflicting.clear();
01625     if (GCSsys.isInit()) {
01626         int dofs = GCSsys.diagnose(Parameters, Conflicting);
01627         return dofs;
01628     }
01629     else {
01630         return -1;
01631     }
01632 }
01633 
01634 
01635 
01636 TopoShape Sketch::toShape(void) const
01637 {
01638     TopoShape result;
01639     std::vector<GeoDef>::const_iterator it=Geoms.begin();
01640 
01641 #if 0
01642 
01643     bool first = true;
01644     for (;it!=Geoms.end();++it) {
01645         if (!it->construction) {
01646             TopoDS_Shape sh = it->geo->toShape();
01647             if (first) {
01648                 first = false;
01649                 result._Shape = sh;
01650             } else {
01651                 result._Shape = result.fuse(sh);
01652             }
01653         }
01654     }
01655     return result;
01656 #else
01657     std::list<TopoDS_Edge> edge_list;
01658     std::list<TopoDS_Wire> wires;
01659 
01660     // collecting all (non constructive) edges out of the sketch
01661     for (;it!=Geoms.end();++it) {
01662         if (!it->construction) {
01663             edge_list.push_back(TopoDS::Edge(it->geo->toShape()));
01664         }
01665     }
01666 
01667     // sort them together to wires
01668     while (edge_list.size() > 0) {
01669         BRepBuilderAPI_MakeWire mkWire;
01670         // add and erase first edge
01671         mkWire.Add(edge_list.front());
01672         edge_list.pop_front();
01673 
01674         TopoDS_Wire new_wire = mkWire.Wire(); // current new wire
01675 
01676         // try to connect each edge to the wire, the wire is complete if no more egdes are connectible
01677         bool found = false;
01678         do {
01679             found = false;
01680             for (std::list<TopoDS_Edge>::iterator pE = edge_list.begin(); pE != edge_list.end(); ++pE) {
01681                 mkWire.Add(*pE);
01682                 if (mkWire.Error() != BRepBuilderAPI_DisconnectedWire) {
01683                     // edge added ==> remove it from list
01684                     found = true;
01685                     edge_list.erase(pE);
01686                     new_wire = mkWire.Wire();
01687                     break;
01688                 }
01689             }
01690         }
01691         while (found);
01692         wires.push_back(new_wire);
01693     }
01694     if (wires.size() == 1)
01695         result = *wires.begin();
01696     else if (wires.size() > 1) {
01697         // FIXME: The right way here would be to determine the outer and inner wires and
01698         // generate a face with holes (inner wires have to be taged REVERSE or INNER).
01699         // thats the only way to transport a somwhat more complex sketch...
01700         //result = *wires.begin();
01701 
01702         // I think a compound can be used as container because it is just a collection of
01703         // shapes and doesn't need too much information about the topology.
01704         // The actual knowledge how to create a prism from several wires should go to the Pad
01705         // feature (Werner).
01706         BRep_Builder builder;
01707         TopoDS_Compound comp;
01708         builder.MakeCompound(comp);
01709         for (std::list<TopoDS_Wire>::iterator wt = wires.begin(); wt != wires.end(); ++wt)
01710             builder.Add(comp, *wt);
01711         result._Shape = comp;
01712     }
01713     // FIXME: if free edges are left over its probably better to
01714     // create a compound with the closed structures and let the
01715     // features decide what to do with it...
01716     if (edge_list.size() > 0)
01717         Base::Console().Warning("Left over edges in Sketch. Only closed structures will be propagated at the moment!\n");
01718 
01719 #endif
01720 
01721     return result;
01722 }
01723 
01724 // Persistance implementer -------------------------------------------------
01725 
01726 unsigned int Sketch::getMemSize(void) const
01727 {
01728     return 0;
01729 }
01730 
01731 void Sketch::Save(Writer &writer) const
01732 {
01733 
01734 }
01735 
01736 void Sketch::Restore(XMLReader &reader)
01737 {
01738 
01739 }
01740 

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