diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index 15fc66dd8..06eb433fb 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -15,6 +15,7 @@ include_directories( ${ZLIB_INCLUDE_DIR} ${PYTHON_INCLUDE_PATH} ${XERCESC_INCLUDE_DIR} + ${EIGEN3_INCLUDE_DIR} ) link_directories(${OCC_LIBRARY_DIR}) diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 244db2d19..7a3972ad0 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -315,6 +315,9 @@ public: //see more info in respective function in GCS. double calculateConstraintError(int icstr) { return GCSsys.calculateConstraintErrorByTag(icstr);} + /// Returns the size of the Geometry + int getGeometrySize(void) {return Geoms.size();} + enum GeoType { None = 0, Point = 1, // 1 Point(start), 2 Parameters(x,y) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 7548d950f..3f087acfe 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -82,6 +82,12 @@ SketchObject::SketchObject() ExternalGeo.push_back(HLine); ExternalGeo.push_back(VLine); rebuildVertexIndex(); + + lastDoF=0; + lastHasConflict=false; + lastHasRedundancies=false; + lastSolverStatus=0; + lastSolveTime=0; } SketchObject::~SketchObject() @@ -110,49 +116,69 @@ App::DocumentObjectExecReturn *SketchObject::execute(void) delConstraintsToExternal(); } - Sketch sketch; - - int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + // We should have an updated Sketcher geometry or this execute should not have happened + // therefore we update our sketch object geometry with the SketchObject one. + // + // set up a sketch (including dofs counting and diagnosing of conflicts) + lastDoF = solvedSketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), getExternalGeometryCount()); - if (dofs < 0) { // over-constrained sketch + lastHasConflict = solvedSketch.hasConflicts(); + lastHasRedundancies = solvedSketch.hasRedundancies(); + lastConflicting=solvedSketch.getConflicting(); + lastRedundant=solvedSketch.getRedundant(); + + if (lastDoF < 0) { // over-constrained sketch std::string msg="Over-constrained sketch\n"; - appendConflictMsg(sketch.getConflicting(), msg); + appendConflictMsg(lastConflicting, msg); return new App::DocumentObjectExecReturn(msg.c_str(),this); } - if (sketch.hasConflicts()) { // conflicting constraints + if (lastHasConflict) { // conflicting constraints std::string msg="Sketch with conflicting constraints\n"; - appendConflictMsg(sketch.getConflicting(), msg); + appendConflictMsg(lastConflicting, msg); return new App::DocumentObjectExecReturn(msg.c_str(),this); } - if (sketch.hasRedundancies()) { // redundant constraints + if (lastHasRedundancies) { // redundant constraints std::string msg="Sketch with redundant constraints\n"; - appendRedundantMsg(sketch.getRedundant(), msg); + appendRedundantMsg(lastRedundant, msg); return new App::DocumentObjectExecReturn(msg.c_str(),this); } - // solve the sketch - if (sketch.solve() != 0) + lastSolverStatus=solvedSketch.solve(); + lastSolveTime=solvedSketch.SolveTime; + + if (lastSolverStatus != 0) return new App::DocumentObjectExecReturn("Solving the sketch failed",this); - std::vector geomlist = sketch.extractGeometry(); + std::vector geomlist = solvedSketch.extractGeometry(); Geometry.setValues(geomlist); for (std::vector::iterator it=geomlist.begin(); it != geomlist.end(); ++it) if (*it) delete *it; - Shape.setValue(sketch.toShape()); + // this is not necessary for sketch representation in edit mode, unless we want to trigger an update of + // the objects that depend on this sketch (like pads) + Shape.setValue(solvedSketch.toShape()); return App::DocumentObject::StdReturn; } -int SketchObject::hasConflicts(void) const +int SketchObject::hasConflicts(void) { + // TODO: This must be reviewed to see if we are not setting an already set geometry again (and calculating again) + // it is unclear if we need to know if there are conflicts of an updated geometry that has not been already solved + // or not. + // set up a sketch (including dofs counting and diagnosing of conflicts) - Sketch sketch; - int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + /*lastDoF = solvedSketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), getExternalGeometryCount()); - if (dofs < 0) // over-constrained sketch + + lastHasConflict = solvedSketch.hasConflicts(); + lastHasRedundancies = solvedSketch.hasRedundancies(); + lastConflicting=solvedSketch.getConflicting(); + lastRedundant=solvedSketch.getRedundant();*/ + + if (lastDoF < 0) // over-constrained sketch return -2; - if (sketch.hasConflicts()) // conflicting constraints + if (solvedSketch.hasConflicts()) // conflicting constraints return -1; return 0; @@ -160,21 +186,35 @@ int SketchObject::hasConflicts(void) const int SketchObject::solve() { + // We should have an updated Sketcher geometry or this solver should not have happened + // therefore we update our sketch object geometry with the SketchObject one. + // // set up a sketch (including dofs counting and diagnosing of conflicts) - Sketch sketch; - int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + lastDoF = solvedSketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), getExternalGeometryCount()); + + lastHasConflict = solvedSketch.hasConflicts(); + int err=0; - if (dofs < 0) // over-constrained sketch + if (lastDoF < 0) // over-constrained sketch err = -3; - else if (sketch.hasConflicts()) // conflicting constraints + else if (lastHasConflict) // conflicting constraints err = -3; - else if (sketch.solve() != 0) // solving - err = -2; + else { + lastSolverStatus=solvedSketch.solve(); + if (lastSolverStatus != 0) // solving + err = -2; + } + + lastHasRedundancies = solvedSketch.hasRedundancies(); + + lastConflicting=solvedSketch.getConflicting(); + lastRedundant=solvedSketch.getRedundant(); + lastSolveTime=solvedSketch.SolveTime; if (err == 0) { // set the newly solved geometry - std::vector geomlist = sketch.extractGeometry(); + std::vector geomlist = solvedSketch.extractGeometry(); Geometry.setValues(geomlist); for (std::vector::iterator it = geomlist.begin(); it != geomlist.end(); ++it) if (*it) delete *it; @@ -306,18 +346,30 @@ int SketchObject::toggleDriving(int ConstrId) int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toPoint, bool relative) { - Sketch sketch; - int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + // if we are moving a point, we need to start from a solved sketch + // if we have conflicts we can forget about moving + + /*lastDoF = solvedSketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), getExternalGeometryCount()); - if (dofs < 0) // over-constrained sketch + + lastHasConflict = solvedSketch.hasConflicts(); + lastHasRedundancies = solvedSketch.hasRedundancies(); + lastConflicting=solvedSketch.getConflicting(); + lastRedundant=solvedSketch.getRedundant();*/ + + if (lastDoF < 0) // over-constrained sketch return -1; - if (sketch.hasConflicts()) // conflicting constraints + if (lastHasConflict) // conflicting constraints return -1; // move the point and solve - int ret = sketch.movePoint(GeoId, PosId, toPoint, relative); - if (ret == 0) { - std::vector geomlist = sketch.extractGeometry(); + lastSolverStatus = solvedSketch.movePoint(GeoId, PosId, toPoint, relative); + + // moving the point can not result in a conflict that we did not have + // or a redundancy that we did not have before, or a change of DoF + + if (lastSolverStatus == 0) { + std::vector geomlist = solvedSketch.extractGeometry(); Geometry.setValues(geomlist); //Constraints.acceptGeometry(getCompleteGeometry()); for (std::vector::iterator it=geomlist.begin(); it != geomlist.end(); ++it) { @@ -325,7 +377,7 @@ int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toP } } - return ret; + return lastSolverStatus; } Base::Vector3d SketchObject::getPoint(int GeoId, PointPos PosId) const diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 89ba9bd63..c8f4bf241 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -32,6 +32,8 @@ #include #include +#include "Sketch.h" + namespace Sketcher { @@ -104,7 +106,7 @@ public: std::vector getCompleteGeometry(void) const; /// returns non zero if the sketch contains conflicting constraints - int hasConflicts(void) const; + int hasConflicts(void); /// solves the sketch and updates the Geometry int solve(); @@ -190,6 +192,23 @@ public: bool evaluateConstraints() const; /// Remove constraints with invalid indexes void validateConstraints(); + + /// gets DoF of last solver execution + int getLastDoF() {return lastDoF;} + /// gets HasConflicts status of last solver execution + bool getLastHasConflicts() {return lastHasConflict;} + /// gets HasRedundancies status of last solver execution + bool getLastHasRedundancies() {return lastHasRedundancies;} + /// gets solver status of last solver execution + int getLastSolverStatus() {return lastSolverStatus;} + /// gets solver SolveTime of last solver execution + float getLastSolveTime() {return lastSolveTime;} + /// gets the conflicting constraints of the last solver execution + const std::vector &getLastConflicting(void) const { return lastConflicting; } + /// gets the redundant constraints of last solver execution + const std::vector &getLastRedundant(void) const { return lastRedundant; } + + Sketch &getSolvedSketch(void) {return solvedSketch;} protected: /// get called by the container when a property has changed @@ -201,6 +220,17 @@ private: std::vector VertexId2GeoId; std::vector VertexId2PosId; + + Sketch solvedSketch; + + int lastDoF; + bool lastHasConflict; + bool lastHasRedundancies; + int lastSolverStatus; + float lastSolveTime; + + std::vector lastConflicting; + std::vector lastRedundant; bool AutoLockTangencyAndPerpty(Constraint* cstr, bool bForce = false, bool bLock = true); }; diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index 924c08bc8..7e7d2c5fa 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -241,7 +241,20 @@ PyObject* SketchObjectPy::addConstraint(PyObject *args) return 0; } int ret = this->getSketchObjectPtr()->addConstraint(constr); - this->getSketchObjectPtr()->solve(); + // this solve is necessary because: + // 1. The addition of constraint is part of a command addition + // 2. This solve happens before the command is committed + // 3. A constraint, may effect a geometry change (think of coincident, + // a line's point moves to meet the other line's point + // 4. The transaction is comitted before any other solve, for example + // the one of execute() triggered by a recompute (UpdateActive) is generated. + // 5. Upon "undo", the constraint is removed (it was before the command was committed) + // however, the geometry changed after the command was committed, so the point that + // moved do not go back to the position where it was. + // + // N.B.: However, the solve itself may be inhibited in cases where groups of geometry/constraints + // are added together, because in that case undoing will also make the geometry disappear. + this->getSketchObjectPtr()->solve(); return Py::new_reference_to(Py::Int(ret)); } else if (PyObject_TypeCheck(pcObj, &(PyList_Type)) || diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 3b67757dc..44fee1a8d 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -160,6 +160,7 @@ void openEditDatumDialog(Sketcher::SketchObject* sketch, int ConstrNbr) catch (const Base::Exception& e) { QMessageBox::critical(qApp->activeWindow(), QObject::tr("Dimensional constraint"), QString::fromUtf8(e.what())); Gui::Command::abortCommand(); + Gui::Command::updateActive(); } } } @@ -866,7 +867,7 @@ void CmdSketcherConstrainCoincident::activated(int iMsg) else abortCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes // clear the selection (convenience) getSelection().clearSelection(); @@ -1552,7 +1553,8 @@ void CmdSketcherConstrainParallel::activated(int iMsg) } // finish the transaction and update commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + // clear the selection (convenience) getSelection().clearSelection(); @@ -1673,7 +1675,8 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) } commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + getSelection().clearSelection(); return; @@ -1697,7 +1700,8 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Perpendicular',%d,%d,%d,%d)) ", selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2); commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + getSelection().clearSelection(); return; } @@ -1719,7 +1723,7 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Perpendicular',%d,%d,%d)) ", selection[0].getFeatName(),GeoId1,PosId1,GeoId2); commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes getSelection().clearSelection(); return; } @@ -1806,7 +1810,7 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) } commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes getSelection().clearSelection(); return; @@ -1817,7 +1821,7 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Perpendicular',%d,%d)) ", selection[0].getFeatName(),GeoId1,GeoId2); commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes getSelection().clearSelection(); return; } @@ -1945,7 +1949,7 @@ void CmdSketcherConstrainTangent::activated(int iMsg) } commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes getSelection().clearSelection(); return; @@ -1969,7 +1973,7 @@ void CmdSketcherConstrainTangent::activated(int iMsg) Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d,%d)) ", selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2); commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes getSelection().clearSelection(); return; } @@ -1991,7 +1995,7 @@ void CmdSketcherConstrainTangent::activated(int iMsg) Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d)) ", selection[0].getFeatName(),GeoId1,PosId1,GeoId2); commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes getSelection().clearSelection(); return; } @@ -2051,7 +2055,7 @@ void CmdSketcherConstrainTangent::activated(int iMsg) Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", selection[0].getFeatName(),GeoId1,GeoId2); commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes getSelection().clearSelection(); return; } @@ -2301,13 +2305,14 @@ void CmdSketcherConstrainRadius::activated(int iMsg) } } commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes commitNeeded=false; updateNeeded=false; } catch (const Base::Exception& e) { QMessageBox::critical(qApp->activeWindow(), QObject::tr("Dimensional constraint"), QString::fromUtf8(e.what())); abortCommand(); + updateActive(); } } else { @@ -2327,8 +2332,9 @@ void CmdSketcherConstrainRadius::activated(int iMsg) if(commitNeeded) commitCommand(); - if(updateNeeded) - updateActive(); + //if(updateNeeded) + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + } void CmdSketcherConstrainRadius::updateAction(int mode) @@ -2715,7 +2721,8 @@ void CmdSketcherConstrainEqual::activated(int iMsg) } // finish the transaction and update commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + // clear the selection (convenience) getSelection().clearSelection(); @@ -2795,7 +2802,8 @@ void CmdSketcherConstrainSymmetric::activated(int iMsg) // finish the transaction and update commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + // clear the selection (convenience) getSelection().clearSelection(); @@ -2846,7 +2854,8 @@ void CmdSketcherConstrainSymmetric::activated(int iMsg) // finish the transaction and update commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + // clear the selection (convenience) getSelection().clearSelection(); @@ -2862,7 +2871,8 @@ void CmdSketcherConstrainSymmetric::activated(int iMsg) // finish the transaction and update commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + // clear the selection (convenience) getSelection().clearSelection(); @@ -3003,7 +3013,8 @@ void CmdSketcherConstrainSnellsLaw::activated(int iMsg) }*/ commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + // clear the selection (convenience) getSelection().clearSelection(); @@ -3245,7 +3256,8 @@ void CmdSketcherConstrainInternalAlignment::activated(int iMsg) // finish the transaction and update commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + if(extra_elements){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Extra elements"), @@ -3401,7 +3413,8 @@ void CmdSketcherConstrainInternalAlignment::activated(int iMsg) // finish the transaction and update commitCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + if(extra_elements){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Extra elements"), @@ -3540,7 +3553,8 @@ void CmdSketcherToggleDrivingConstraint::activated(int iMsg) else abortCommand(); - updateActive(); + //updateActive(); on adding constraints the updateActive's are unnecessary and introduce extra recomputes + // clear the selection (convenience) getSelection().clearSelection(); diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index 8509328cb..22153ef00 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -477,7 +477,7 @@ void CmdSketcherSelectRedundantConstraints::activated(int iMsg) std::stringstream ss; // get the needed lists and objects - const std::vector< int > &solverredundant = dynamic_cast(doc->getInEdit())->getRedundant(); + const std::vector< int > &solverredundant = dynamic_cast(doc->getInEdit())->getSketchObject()->getLastRedundant(); const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); getSelection().clearSelection(); @@ -532,7 +532,7 @@ void CmdSketcherSelectConflictingConstraints::activated(int iMsg) std::stringstream ss; // get the needed lists and objects - const std::vector< int > &solverconflicting = dynamic_cast(doc->getInEdit())->getConflicting(); + const std::vector< int > &solverconflicting = dynamic_cast(doc->getInEdit())->getSketchObject()->getLastConflicting(); const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); getSelection().clearSelection(); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 7d6bf3c29..b5eb47589 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -152,7 +152,7 @@ struct EditData { PreselectCross(-1), blockedPreselection(false), FullyConstrained(false), - //ActSketch(0), + //ActSketch(0), // if you are wondering, it went to SketchObject, accessible via getSketchObject()->getSolvedSketch() EditRoot(0), PointsMaterials(0), CurvesMaterials(0), @@ -183,8 +183,6 @@ struct EditData { bool FullyConstrained; bool visibleBeforeEdit; - // instance of the solver - Sketcher::Sketch ActSketch; // container to track our own selected parts std::set SelPointSet; std::set SelCurvSet; // also holds cross axes at -1 and -2 @@ -997,7 +995,7 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor preselectChanged = detectPreselection(pp, viewer, cursorPos); delete pp; } - + switch (Mode) { case STATUS_NONE: if (preselectChanged) { @@ -1007,7 +1005,7 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor } return false; case STATUS_SELECT_Point: - if (!edit->ActSketch.hasConflicts() && + if (!getSketchObject()->getSolvedSketch().hasConflicts() && edit->PreselectPoint != -1 && edit->DragPoint != edit->PreselectPoint) { Mode = STATUS_SKETCH_DragPoint; edit->DragPoint = edit->PreselectPoint; @@ -1015,7 +1013,7 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor Sketcher::PointPos PosId; getSketchObject()->getGeoVertexIndex(edit->DragPoint, GeoId, PosId); if (GeoId != Sketcher::Constraint::GeoUndef && PosId != Sketcher::none) { - edit->ActSketch.initMove(GeoId, PosId, false); + getSketchObject()->getSolvedSketch().initMove(GeoId, PosId, false); relative = false; xInit = 0; yInit = 0; @@ -1029,11 +1027,11 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor edit->PreselectConstraintSet.clear(); return true; case STATUS_SELECT_Edge: - if (!edit->ActSketch.hasConflicts() && + if (!getSketchObject()->getSolvedSketch().hasConflicts() && edit->PreselectCurve != -1 && edit->DragCurve != edit->PreselectCurve) { Mode = STATUS_SKETCH_DragCurve; edit->DragCurve = edit->PreselectCurve; - edit->ActSketch.initMove(edit->DragCurve, Sketcher::none, false); + getSketchObject()->getSolvedSketch().initMove(edit->DragCurve, Sketcher::none, false); const Part::Geometry *geo = getSketchObject()->getGeometry(edit->DragCurve); if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { relative = true; @@ -1074,12 +1072,12 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor getSketchObject()->getGeoVertexIndex(edit->DragPoint, GeoId, PosId); Base::Vector3d vec(x-xInit,y-yInit,0); if (GeoId != Sketcher::Constraint::GeoUndef && PosId != Sketcher::none) { - if (edit->ActSketch.movePoint(GeoId, PosId, vec, relative) == 0) { + if (getSketchObject()->getSolvedSketch().movePoint(GeoId, PosId, vec, relative) == 0) { setPositionText(Base::Vector2D(x,y)); draw(true); - signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime)); + signalSolved(QString::fromLatin1("Solved in %1 sec").arg(getSketchObject()->getSolvedSketch().SolveTime)); } else { - signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime)); + signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(getSketchObject()->getSolvedSketch().SolveTime)); //Base::Console().Log("Error solving:%d\n",ret); } } @@ -1088,12 +1086,12 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor case STATUS_SKETCH_DragCurve: if (edit->DragCurve != -1) { Base::Vector3d vec(x-xInit,y-yInit,0); - if (edit->ActSketch.movePoint(edit->DragCurve, Sketcher::none, vec, relative) == 0) { + if (getSketchObject()->getSolvedSketch().movePoint(edit->DragCurve, Sketcher::none, vec, relative) == 0) { setPositionText(Base::Vector2D(x,y)); draw(true); - signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime)); + signalSolved(QString::fromLatin1("Solved in %1 sec").arg(getSketchObject()->getSolvedSketch().SolveTime)); } else { - signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime)); + signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(getSketchObject()->getSolvedSketch().SolveTime)); } } return true; @@ -1144,8 +1142,9 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2D &toPo int intGeoCount = getSketchObject()->getHighestCurveIndex() + 1; int extGeoCount = getSketchObject()->getExternalGeometryCount(); + // with memory allocation - const std::vector geomlist = edit->ActSketch.extractGeometry(true, true); + const std::vector geomlist = getSketchObject()->getSolvedSketch().extractGeometry(true, true); assert(int(geomlist.size()) == extGeoCount + intGeoCount); assert((Constr->First >= -extGeoCount && Constr->First < intGeoCount) @@ -1156,10 +1155,10 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2D &toPo Base::Vector3d p1(0.,0.,0.), p2(0.,0.,0.); if (Constr->SecondPos != Sketcher::none) { // point to point distance - p1 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos); - p2 = edit->ActSketch.getPoint(Constr->Second, Constr->SecondPos); + p1 = getSketchObject()->getSolvedSketch().getPoint(Constr->First, Constr->FirstPos); + p2 = getSketchObject()->getSolvedSketch().getPoint(Constr->Second, Constr->SecondPos); } else if (Constr->Second != Constraint::GeoUndef) { // point to line distance - p1 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos); + p1 = getSketchObject()->getSolvedSketch().getPoint(Constr->First, Constr->FirstPos); const Part::Geometry *geo = GeoById(geomlist, Constr->Second); if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { const Part::GeomLineSegment *lineSeg = dynamic_cast(geo); @@ -1171,7 +1170,7 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2D &toPo } else return; } else if (Constr->FirstPos != Sketcher::none) { - p2 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos); + p2 = getSketchObject()->getSolvedSketch().getPoint(Constr->First, Constr->FirstPos); } else if (Constr->First != Constraint::GeoUndef) { const Part::Geometry *geo = GeoById(geomlist, Constr->First); if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { @@ -1263,11 +1262,11 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2D &toPo p0 = Base::Vector3d(x,y,0); } } else {//angle-via-point - Base::Vector3d p = edit->ActSketch.getPoint(Constr->Third, Constr->ThirdPos); + Base::Vector3d p = getSketchObject()->getSolvedSketch().getPoint(Constr->Third, Constr->ThirdPos); p0 = Base::Vector3d(p.x, p.y, 0); - dir1 = edit->ActSketch.calculateNormalAtPoint(Constr->First, p.x, p.y); + dir1 = getSketchObject()->getSolvedSketch().calculateNormalAtPoint(Constr->First, p.x, p.y); dir1.RotateZ(-M_PI/2);//convert to vector of tangency by rotating - dir2 = edit->ActSketch.calculateNormalAtPoint(Constr->Second, p.x, p.y); + dir2 = getSketchObject()->getSolvedSketch().calculateNormalAtPoint(Constr->Second, p.x, p.y); dir2.RotateZ(-M_PI/2); } @@ -2254,7 +2253,7 @@ void ViewProviderSketch::updateColor(void) hasMaterial = true; m = dynamic_cast(s->getChild(CONSTRAINT_SEPARATOR_INDEX_MATERIAL_OR_DATUMLABEL)); } - + if (edit->SelConstraintSet.find(i) != edit->SelConstraintSet.end()) { if (hasDatumLabel) { SoDatumLabel *l = dynamic_cast(s->getChild(CONSTRAINT_SEPARATOR_INDEX_MATERIAL_OR_DATUMLABEL)); @@ -2263,9 +2262,9 @@ void ViewProviderSketch::updateColor(void) m->diffuseColor = SelectColor; } else if (type == Sketcher::Coincident) { int index; - index = edit->ActSketch.getPointId(constraint->First, constraint->FirstPos) + 1; + index = getSketchObject()->getSolvedSketch().getPointId(constraint->First, constraint->FirstPos) + 1; if (index >= 0 && index < PtNum) pcolor[index] = SelectColor; - index = edit->ActSketch.getPointId(constraint->Second, constraint->SecondPos) + 1; + index = getSketchObject()->getSolvedSketch().getPointId(constraint->Second, constraint->SecondPos) + 1; if (index >= 0 && index < PtNum) pcolor[index] = SelectColor; } else if (type == Sketcher::InternalAlignment) { switch(constraint->AlignmentType) { @@ -2288,7 +2287,7 @@ void ViewProviderSketch::updateColor(void) case EllipseFocus1: case EllipseFocus2: { - int index = edit->ActSketch.getPointId(constraint->First, constraint->FirstPos) + 1; + int index = getSketchObject()->getSolvedSketch().getPointId(constraint->First, constraint->FirstPos) + 1; if (index >= 0 && index < PtNum) pcolor[index] = SelectColor; } break; @@ -2890,7 +2889,7 @@ void ViewProviderSketch::draw(bool temp) const std::vector *geomlist; std::vector tempGeo; if (temp) - tempGeo = edit->ActSketch.extractGeometry(true, true); // with memory allocation + tempGeo = getSketchObject()->getSolvedSketch().extractGeometry(true, true); // with memory allocation else tempGeo = getSketchObject()->getCompleteGeometry(); // without memory allocation geomlist = &tempGeo; @@ -3195,11 +3194,11 @@ Restart: assert(0);//no point found! } while (false); if (temp) - midpos1 = edit->ActSketch.getPoint(ptGeoId, ptPosId); + midpos1 = getSketchObject()->getSolvedSketch().getPoint(ptGeoId, ptPosId); else midpos1 = getSketchObject()->getPoint(ptGeoId, ptPosId); - norm1 = edit->ActSketch.calculateNormalAtPoint(Constr->Second, midpos1.x, midpos1.y); + norm1 = getSketchObject()->getSolvedSketch().calculateNormalAtPoint(Constr->Second, midpos1.x, midpos1.y); norm1.Normalize(); dir1 = norm1; dir1.RotateZ(-M_PI/2.0); @@ -3424,15 +3423,15 @@ Restart: Base::Vector3d pnt1(0.,0.,0.), pnt2(0.,0.,0.); if (Constr->SecondPos != Sketcher::none) { // point to point distance if (temp) { - pnt1 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos); - pnt2 = edit->ActSketch.getPoint(Constr->Second, Constr->SecondPos); + pnt1 = getSketchObject()->getSolvedSketch().getPoint(Constr->First, Constr->FirstPos); + pnt2 = getSketchObject()->getSolvedSketch().getPoint(Constr->Second, Constr->SecondPos); } else { pnt1 = getSketchObject()->getPoint(Constr->First, Constr->FirstPos); pnt2 = getSketchObject()->getPoint(Constr->Second, Constr->SecondPos); } } else if (Constr->Second != Constraint::GeoUndef) { // point to line distance if (temp) { - pnt1 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos); + pnt1 = getSketchObject()->getSolvedSketch().getPoint(Constr->First, Constr->FirstPos); } else { pnt1 = getSketchObject()->getPoint(Constr->First, Constr->FirstPos); } @@ -3448,7 +3447,7 @@ Restart: break; } else if (Constr->FirstPos != Sketcher::none) { if (temp) { - pnt2 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos); + pnt2 = getSketchObject()->getSolvedSketch().getPoint(Constr->First, Constr->FirstPos); } else { pnt2 = getSketchObject()->getPoint(Constr->First, Constr->FirstPos); } @@ -3522,9 +3521,9 @@ Restart: if (ptPosId != Sketcher::none) break; assert(0);//no point found! } while (false); - pos = edit->ActSketch.getPoint(ptGeoId, ptPosId); + pos = getSketchObject()->getSolvedSketch().getPoint(ptGeoId, ptPosId); - Base::Vector3d norm = edit->ActSketch.calculateNormalAtPoint(Constr->Second, pos.x, pos.y); + Base::Vector3d norm = getSketchObject()->getSolvedSketch().calculateNormalAtPoint(Constr->Second, pos.x, pos.y); norm.Normalize(); Base::Vector3d dir = norm; dir.RotateZ(-M_PI/2.0); @@ -3650,8 +3649,8 @@ Restart: assert(Constr->First >= -extGeoCount && Constr->First < intGeoCount); assert(Constr->Second >= -extGeoCount && Constr->Second < intGeoCount); - Base::Vector3d pnt1 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos); - Base::Vector3d pnt2 = edit->ActSketch.getPoint(Constr->Second, Constr->SecondPos); + Base::Vector3d pnt1 = getSketchObject()->getSolvedSketch().getPoint(Constr->First, Constr->FirstPos); + Base::Vector3d pnt2 = getSketchObject()->getSolvedSketch().getPoint(Constr->Second, Constr->SecondPos); SbVec3f p1(pnt1.x,pnt1.y,zConstr); SbVec3f p2(pnt2.x,pnt2.y,zConstr); @@ -3730,11 +3729,11 @@ Restart: } } } else {//angle-via-point - Base::Vector3d p = edit->ActSketch.getPoint(Constr->Third, Constr->ThirdPos); + Base::Vector3d p = getSketchObject()->getSolvedSketch().getPoint(Constr->Third, Constr->ThirdPos); p0 = SbVec3f(p.x, p.y, 0); - dir1 = edit->ActSketch.calculateNormalAtPoint(Constr->First, p.x, p.y); + dir1 = getSketchObject()->getSolvedSketch().calculateNormalAtPoint(Constr->First, p.x, p.y); dir1.RotateZ(-M_PI/2);//convert to vector of tangency by rotating - dir2 = edit->ActSketch.calculateNormalAtPoint(Constr->Second, p.x, p.y); + dir2 = getSketchObject()->getSolvedSketch().calculateNormalAtPoint(Constr->Second, p.x, p.y); dir2.RotateZ(-M_PI/2); } @@ -4056,8 +4055,21 @@ void ViewProviderSketch::updateData(const App::Property *prop) if (edit && (prop == &(getSketchObject()->Geometry) || prop == &(getSketchObject()->Constraints))) { edit->FullyConstrained = false; - solveSketch(); - draw(true); + + // UpdateData is only called as a consequence of SketchObject having changed + // and triggered from SketchObject::onChanged. Therefore we have to assume that + // SketchObject is updated and solved , or will soon be updated and solved in the + // still to be processed recompute (SketchObject::execute() that will trigger a + // SketchObject::onChanged). + // + // At this point, we do not need to solve the Sketch and we can draw directly from + // the SketchObject geometry. + // + // This SketchObject:: + //solveSketch(); + //draw(true); + UpdateSolverInformation(); // just update the solver window with the last SketchObject solving information + draw(); } if (edit && &(getSketchObject()->Constraints)) { // send the signal for the TaskDlg. @@ -4182,8 +4194,8 @@ bool ViewProviderSketch::setEdit(int ModNum) else Gui::Control().showDialog(new TaskDlgEditSketch(this)); - solveSketch(); - draw(); + getSketchObject()->solve(); // This call to the solver is needed to initialize the DoF and solve time controls + //draw(); is not necessary, because a solve triggers an updateData. return true; } @@ -4225,72 +4237,66 @@ QString ViewProviderSketch::appendRedundantMsg(const std::vector &redundant return msg; } -const std::vector &ViewProviderSketch::getConflicting(void) const +void ViewProviderSketch::UpdateSolverInformation() { - return edit->ActSketch.getConflicting(); -} - -const std::vector &ViewProviderSketch::getRedundant(void) const -{ - return edit->ActSketch.getRedundant(); -} - -void ViewProviderSketch::solveSketch(void) -{ - // set up the sketch and diagnose possible conflicts - int dofs = edit->ActSketch.setUpSketch(getSketchObject()->getCompleteGeometry(), - getSketchObject()->Constraints.getValues(), - getSketchObject()->getExternalGeometryCount()); + // Updates Solver Information with the Last solver execution at SketchObject level + int dofs = getSketchObject()->getLastDoF(); + bool hasConflicts = getSketchObject()->getLastHasConflicts(); + bool hasRedundancies = getSketchObject()->getLastHasRedundancies(); + if (getSketchObject()->Geometry.getSize() == 0) { signalSetUp(tr("Empty sketch")); signalSolved(QString()); } else if (dofs < 0) { // over-constrained sketch std::string msg; - SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); + SketchObject::appendConflictMsg(getSketchObject()->getLastConflicting(), msg); signalSetUp(QString::fromLatin1("%1%2
%3

") .arg(tr("Over-constrained sketch ")) .arg(tr("(click to select)")) .arg(QString::fromStdString(msg))); signalSolved(QString()); } - else if (edit->ActSketch.hasConflicts()) { // conflicting constraints + else if (hasConflicts) { // conflicting constraints signalSetUp(QString::fromLatin1("%1%2
%3

") .arg(tr("Sketch contains conflicting constraints ")) .arg(tr("(click to select)")) - .arg(appendConflictMsg(edit->ActSketch.getConflicting()))); + .arg(appendConflictMsg(getSketchObject()->getLastConflicting()))); signalSolved(QString()); } else { - if (edit->ActSketch.hasRedundancies()) { // redundant constraints + if (hasRedundancies) { // redundant constraints signalSetUp(QString::fromLatin1("%1%2
%3

") .arg(tr("Sketch contains redundant constraints ")) .arg(tr("(click to select)")) - .arg(appendRedundantMsg(edit->ActSketch.getRedundant()))); + .arg(appendRedundantMsg(getSketchObject()->getLastRedundant()))); } - if (edit->ActSketch.solve() == 0) { // solving the sketch + if (getSketchObject()->getLastSolverStatus() == 0) { if (dofs == 0) { - // color the sketch as fully constrained - edit->FullyConstrained = true; - if (!edit->ActSketch.hasRedundancies()) { + // color the sketch as fully constrained if it has geometry (other than the axes) + if(getSketchObject()->getSolvedSketch().getGeometrySize()>2) + edit->FullyConstrained = true; + + if (!hasRedundancies) { signalSetUp(QString::fromLatin1("%1").arg(tr("Fully constrained sketch"))); } } - else if (!edit->ActSketch.hasRedundancies()) { + else if (!hasRedundancies) { if (dofs == 1) signalSetUp(tr("Under-constrained sketch with 1 degree of freedom")); else signalSetUp(tr("Under-constrained sketch with %1 degrees of freedom").arg(dofs)); } - signalSolved(tr("Solved in %1 sec").arg(edit->ActSketch.SolveTime)); + signalSolved(tr("Solved in %1 sec").arg(getSketchObject()->getLastSolveTime())); } else { - signalSolved(tr("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime)); + signalSolved(tr("Unsolved (%1 sec)").arg(getSketchObject()->getLastSolveTime())); } } } + void ViewProviderSketch::createEditInventorNodes(void) { assert(edit); @@ -4737,6 +4743,8 @@ bool ViewProviderSketch::onDelete(const std::vector &subList) Base::Console().Error("%s\n", e.what()); } } + + Gui::Command::updateActive(); this->drawConstraintIcons(); this->updateColor(); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index ac30c83ec..f3cbfb25f 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -217,21 +217,15 @@ public: boost::signal signalSolved; /// signals if the elements list has changed boost::signal signalElementsChanged; - - /** @name Act sketch interface */ - //@{ - const std::vector &getConflicting(void) const; - const std::vector &getRedundant(void) const; - //@} - + protected: virtual bool setEdit(int ModNum); virtual void unsetEdit(int ModNum); virtual void setEditViewer(Gui::View3DInventorViewer*, int ModNum); virtual void unsetEditViewer(Gui::View3DInventorViewer*); void deactivateHandler(); - /// set up and solve the sketch - void solveSketch(void); + /// update solver information based on last solving at SketchObject + void UpdateSolverInformation(void); /// helper to detect whether the picked point lies on the sketch bool isPointOnSketch(const SoPickedPoint *pp) const; /// get called by the container whenever a property has been changed