From 73d2fa9e61b09a8d636501acd6a41ece64d6f564 Mon Sep 17 00:00:00 2001 From: logari81 Date: Mon, 14 May 2012 10:44:44 +0200 Subject: [PATCH 01/42] Sketcher: avoid duplicate code and unnecessary arguments --- src/Mod/Sketcher/App/Sketch.cpp | 13 ++---- src/Mod/Sketcher/App/Sketch.h | 16 ++++++- src/Mod/Sketcher/App/SketchObject.cpp | 8 ++-- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 51 ++++----------------- src/Mod/Sketcher/Gui/ViewProviderSketch.h | 2 + 5 files changed, 35 insertions(+), 55 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 608d9da0e..969c08312 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -96,8 +96,9 @@ void Sketch::clear(void) Conflicting.clear(); } -int Sketch::setUpSketch(const std::vector &GeoList, const std::vector &ConstraintList, - bool withDiagnose, int extGeoCount) +int Sketch::setUpSketch(const std::vector &GeoList, + const std::vector &ConstraintList, + int extGeoCount) { clear(); @@ -121,11 +122,7 @@ int Sketch::setUpSketch(const std::vector &GeoList, const std: GCSsys.clearByTag(-1); GCSsys.clearByTag(-2); GCSsys.initSolution(Parameters); - - if (withDiagnose) - return diagnose(); - else - return 0; + return diagnose(); } const char* nameByType(Sketch::GeoType type) @@ -1606,7 +1603,7 @@ int Sketch::solve(void) break; } - // if successfully solved try write the parameters back + // if successfully solved try to write the parameters back if (ret == GCS::Success) { GCSsys.applySolution(); valid_solution = updateGeometry(); diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index ec108421b..3f22f7fdd 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -53,9 +53,21 @@ public: int solve(void); /// delete all geometry and constraints, leave an empty sketch void clear(void); - /// set the sketch up with geoms and constraints + /** set the sketch up with geoms and constraints + * + * returns the degree of freedom of a sketch and calculates a list of + * conflicting constraints + * + * 0 degrees of freedom correspond to a fully constrained sketch + * -1 degrees of freedom correspond to an over-constrained sketch + * positive degrees of freedom correspond to an under-constrained sketch + * + * an over-constrained sketch will always contain conflicting constraints + * a fully constrained or under-constrained sketch may contain conflicting + * constraints or may not + */ int setUpSketch(const std::vector &GeoList, const std::vector &ConstraintList, - bool withDiagnose=true, int extGeoCount=0); + int extGeoCount=0); /// return the actual geometry of the sketch a TopoShape Part::TopoShape toShape(void) const; /// add unspecified geometry diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 95aa455a7..c9e5b3845 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -97,7 +97,7 @@ App::DocumentObjectExecReturn *SketchObject::execute(void) rebuildExternalGeometry(); Sketch sketch; int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), - true, getExternalGeometryCount()); + getExternalGeometryCount()); if (dofs < 0) { // over-constrained sketch std::string msg="Over-constrained sketch\n"; appendConflictMsg(sketch.getConflicting(), msg); @@ -128,7 +128,7 @@ int SketchObject::hasConflicts(void) const // set up a sketch (including dofs counting and diagnosing of conflicts) Sketch sketch; int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), - true, getExternalGeometryCount()); + getExternalGeometryCount()); if (dofs < 0) // over-constrained sketch return -2; if (sketch.hasConflicts()) // conflicting constraints @@ -166,7 +166,7 @@ int SketchObject::setDatum(int ConstrId, double Datum) // set up a sketch (including dofs counting and diagnosing of conflicts) Sketch sketch; int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), - true, getExternalGeometryCount()); + getExternalGeometryCount()); int err=0; if (dofs < 0) // over-constrained sketch err = -3; @@ -192,7 +192,7 @@ int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toP { Sketch sketch; int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), - true, getExternalGeometryCount()); + getExternalGeometryCount()); if (dofs < 0) // over-constrained sketch return -1; if (sketch.hasConflicts()) // conflicting constraints diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index ee289f1d7..1618af878 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -2694,42 +2694,7 @@ void ViewProviderSketch::updateData(const App::Property *prop) if (edit && (prop == &(getSketchObject()->Geometry) || &(getSketchObject()->Constraints))) { edit->FullyConstrained = false; - int dofs = edit->ActSketch.setUpSketch(getSketchObject()->getCompleteGeometry(), - getSketchObject()->Constraints.getValues(), - true, getSketchObject()->getExternalGeometryCount()); - std::string msg; - if (getSketchObject()->Geometry.getSize() == 0) { - signalSetUp(-1, 0, msg); - signalSolved(-1, 0); - } - else if (dofs < 0) { // over-constrained sketch - SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); - //Base::Console().Warning("Over-constrained sketch\n%s",msg.c_str()); - signalSetUp(3, 0, msg); - signalSolved(-1,0); - } - else if (edit->ActSketch.hasConflicts()) { // conflicting constraints - SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); - //Base::Console().Warning("Sketch with conflicting constraints\n%s",msg.c_str()); - signalSetUp(2, dofs, msg); - signalSolved(-1,0); - } - else if (edit->ActSketch.solve() == 0) { // solving the sketch - if (dofs == 0) { - // color the sketch as fully constrained - edit->FullyConstrained = true; - //Base::Console().Message("Fully constrained sketch\n"); - signalSetUp(0, 0, msg); - } - else { - //Base::Console().Message("Under-constrained sketch with %d degrees of freedom\n", dofs); - signalSetUp(1, dofs, msg); - } - signalSolved(0,edit->ActSketch.SolveTime); - } - else { - signalSolved(1,edit->ActSketch.SolveTime); - } + solveSketch(); draw(true); } if (edit && &(getSketchObject()->Constraints)) { @@ -2831,10 +2796,18 @@ bool ViewProviderSketch::setEdit(int ModNum) else Gui::Control().showDialog(new TaskDlgEditSketch(this)); + solveSketch(); + draw(); + + return true; +} + +void ViewProviderSketch::solveSketch(void) +{ // set up the sketch and diagnose possible conflicts int dofs = edit->ActSketch.setUpSketch(getSketchObject()->getCompleteGeometry(), getSketchObject()->Constraints.getValues(), - true, getSketchObject()->getExternalGeometryCount()); + getSketchObject()->getExternalGeometryCount()); std::string msg; if (getSketchObject()->Geometry.getSize() == 0) { signalSetUp(-1, 0, msg); @@ -2868,10 +2841,6 @@ bool ViewProviderSketch::setEdit(int ModNum) else { signalSolved(1, edit->ActSketch.SolveTime); } - - draw(); - - return true; } void ViewProviderSketch::createEditInventorNodes(void) diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index 572547186..234ede976 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -183,6 +183,8 @@ protected: virtual void unsetEdit(int ModNum); virtual void setEditViewer(Gui::View3DInventorViewer*, int ModNum); virtual void unsetEditViewer(Gui::View3DInventorViewer*); + /// set up and solve the sketch + void solveSketch(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 From 63b2b239b164425ad856e891cb05a5afcd1940f8 Mon Sep 17 00:00:00 2001 From: logari81 Date: Mon, 14 May 2012 10:55:44 +0200 Subject: [PATCH 02/42] Sketcher: use low precision solving during mouse drag and code simplifications --- src/Mod/Sketcher/App/Sketch.cpp | 9 ++------- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 969c08312..bfdc0aa3a 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -120,7 +120,6 @@ int Sketch::setUpSketch(const std::vector &GeoList, addConstraints(ConstraintList); GCSsys.clearByTag(-1); - GCSsys.clearByTag(-2); GCSsys.initSolution(Parameters); return diagnose(); } @@ -1566,7 +1565,6 @@ int Sketch::solve(void) Base::TimeInfo start_time; if (!isInitMove) { // make sure we are in single subsystem mode GCSsys.clearByTag(-1); - GCSsys.clearByTag(-2); isFine = true; } @@ -1590,13 +1588,11 @@ int Sketch::solve(void) break; case 3: // last resort: augment the system with a second subsystem and use the SQP solver solvername = "SQP(augmented system)"; - GCSsys.clearByTag(-1); - GCSsys.clearByTag(-2); InitParameters.resize(Parameters.size()); int i=0; for (std::vector::iterator it = Parameters.begin(); it != Parameters.end(); ++it, i++) { InitParameters[i] = **it; - GCSsys.addConstraintEqual(*it, &InitParameters[i], -2); + GCSsys.addConstraintEqual(*it, &InitParameters[i], -1); } GCSsys.initSolution(Parameters); ret = GCSsys.solve(isFine); @@ -1615,7 +1611,7 @@ int Sketch::solve(void) } if (soltype == 3) // cleanup temporary constraints of the augmented system - GCSsys.clearByTag(-2); + GCSsys.clearByTag(-1); if (valid_solution) { if (soltype == 1) @@ -1652,7 +1648,6 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine) geoId = checkGeoId(geoId); GCSsys.clearByTag(-1); - GCSsys.clearByTag(-2); // don't try to move sketches that contain conflicting constraints if (hasConflicts()) { diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 1618af878..78841d18c 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -768,7 +768,7 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal, int GeoId; Sketcher::PointPos PosId; getSketchObject()->getGeoVertexIndex(edit->DragPoint, GeoId, PosId); - edit->ActSketch.initMove(GeoId, PosId); + edit->ActSketch.initMove(GeoId, PosId, false); relative = false; xInit = 0; yInit = 0; @@ -785,7 +785,7 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal, edit->PreselectCurve != -1 && edit->DragCurve != edit->PreselectCurve) { Mode = STATUS_SKETCH_DragCurve; edit->DragCurve = edit->PreselectCurve; - edit->ActSketch.initMove(edit->DragCurve, Sketcher::none); + edit->ActSketch.initMove(edit->DragCurve, Sketcher::none, false); const Part::Geometry *geo = getSketchObject()->getGeometry(edit->DragCurve); if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { relative = true; From ce5d9a332a75c3e02c79709f38c62311d60a0b2e Mon Sep 17 00:00:00 2001 From: logari81 Date: Mon, 14 May 2012 11:28:05 +0200 Subject: [PATCH 03/42] Sketcher, Issue #0000691: detect redundant constraints and skip them if necessary --- src/Mod/Sketcher/App/Sketch.cpp | 33 +- src/Mod/Sketcher/App/Sketch.h | 19 +- src/Mod/Sketcher/App/SketchObject.cpp | 19 + src/Mod/Sketcher/App/SketchObject.h | 2 + src/Mod/Sketcher/App/freegcs/GCS.cpp | 438 ++++++++++++------ src/Mod/Sketcher/App/freegcs/GCS.h | 40 +- src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp | 3 + src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 33 +- 8 files changed, 386 insertions(+), 201 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index bfdc0aa3a..59b6410a7 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -120,8 +120,11 @@ int Sketch::setUpSketch(const std::vector &GeoList, addConstraints(ConstraintList); GCSsys.clearByTag(-1); - GCSsys.initSolution(Parameters); - return diagnose(); + GCSsys.declareUnknowns(Parameters); + GCSsys.initSolution(); + GCSsys.getConflicting(Conflicting); + GCSsys.getRedundant(Redundant); + return GCSsys.dofsNumber(); } const char* nameByType(Sketch::GeoType type) @@ -1594,7 +1597,7 @@ int Sketch::solve(void) InitParameters[i] = **it; GCSsys.addConstraintEqual(*it, &InitParameters[i], -1); } - GCSsys.initSolution(Parameters); + GCSsys.initSolution(); ret = GCSsys.solve(isFine); break; } @@ -1603,8 +1606,11 @@ int Sketch::solve(void) if (ret == GCS::Success) { GCSsys.applySolution(); valid_solution = updateGeometry(); - if (!valid_solution) + if (!valid_solution) { + GCSsys.undoSolution(); + updateGeometry(); Base::Console().Warning("Invalid solution from %s solver.\n", solvername.c_str()); + } } else { valid_solution = false; //Base::Console().Log("NotSolved "); @@ -1630,11 +1636,6 @@ int Sketch::solve(void) } } // soltype - if (!valid_solution) { // undo any changes - GCSsys.undoSolution(); - updateGeometry(); - } - Base::TimeInfo end_time; //Base::Console().Log("T:%s\n",Base::TimeInfo::diffTime(start_time,end_time).c_str()); SolveTime = Base::TimeInfo::diffTimeF(start_time,end_time); @@ -1752,7 +1753,7 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine) } InitParameters = MoveParameters; - GCSsys.initSolution(Parameters); + GCSsys.initSolution(); isInitMove = true; return 0; } @@ -1830,18 +1831,6 @@ Base::Vector3d Sketch::getPoint(int geoId, PointPos pos) return Base::Vector3d(); } -int Sketch::diagnose(void) -{ - Conflicting.clear(); - if (GCSsys.isInit()) { - int dofs = GCSsys.diagnose(Parameters, Conflicting); - return dofs; - } - else { - return -1; - } -} - TopoShape Sketch::toShape(void) const diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 3f22f7fdd..3ea95bc4f 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -83,20 +83,10 @@ public: /// retrieves a point Base::Vector3d getPoint(int geoId, PointPos pos); - /** returns the degree of freedom of a sketch and calculates a list of - * conflicting constraints - * - * 0 degrees of freedom correspond to a fully constrained sketch - * -1 degrees of freedom correspond to an over-constrained sketch - * positive degrees of freedom correspond to an under-constrained sketch - * - * an over-constrained sketch will always contain conflicting constraints - * a fully constrained or under-constrained sketch may contain conflicting - * constraints or may not - */ - int diagnose(void); - bool hasConflicts(void) const { return (Conflicting.size() > 0); }; - const std::vector &getConflicting(void) const { return Conflicting; }; + bool hasConflicts(void) const { return (Conflicting.size() > 0); } + const std::vector &getConflicting(void) const { return Conflicting; } + bool hasRedundancies(void) const { return (Redundant.size() > 0); } + const std::vector &getRedundant(void) const { return Redundant; } /** set the datum of a distance or angle constraint to a certain value and solve * This can cause the solving to fail! @@ -213,6 +203,7 @@ protected: GCS::System GCSsys; int ConstraintsCounter; std::vector Conflicting; + std::vector Redundant; // solving parameters std::vector Parameters; // with memory allocation diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index c9e5b3845..8d75c5f24 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -108,6 +108,11 @@ App::DocumentObjectExecReturn *SketchObject::execute(void) appendConflictMsg(sketch.getConflicting(), msg); return new App::DocumentObjectExecReturn(msg.c_str(),this); } + if (sketch.hasRedundancies()) { // redundant constraints + std::string msg="Sketch with redundant constraints\n"; + appendRedundantMsg(sketch.getRedundant(), msg); + return new App::DocumentObjectExecReturn(msg.c_str(),this); + } // solve the sketch if (sketch.solve() != 0) @@ -1396,6 +1401,20 @@ void SketchObject::appendConflictMsg(const std::vector &conflicting, std::s msg = ss.str(); } +void SketchObject::appendRedundantMsg(const std::vector &redundant, std::string &msg) +{ + std::stringstream ss; + if (msg.length() > 0) + ss << msg; + if (redundant.size() > 0) { + ss << "The following constraints were identified as redundant and should be removed:\n" << redundant[0]; + for (unsigned int i=1; i < redundant.size(); i++) + ss << ", " << redundant[i]; + ss << "\n"; + } + msg = ss.str(); +} + PyObject *SketchObject::getPyObject(void) { if (PythonObject.is(Py::_None())) { diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 83802d83a..cf865d405 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -136,6 +136,8 @@ public: /// generates a warning message about constraint conflicts and appends it to the given message static void appendConflictMsg(const std::vector &conflicting, std::string &msg); + /// generates a warning message about redundant constraints and appends it to the given message + static void appendRedundantMsg(const std::vector &redundant, std::string &msg); // from base class virtual PyObject *getPyObject(void); diff --git a/src/Mod/Sketcher/App/freegcs/GCS.cpp b/src/Mod/Sketcher/App/freegcs/GCS.cpp index c608c9bd0..aa850c9a2 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/freegcs/GCS.cpp @@ -41,19 +41,20 @@ typedef boost::adjacency_list Gra // System System::System() -: clist(0), +: plist(0), clist(0), c2p(), p2c(), - subsyslist(0), - reference(), - init(false) + subSystems(0), subSystemsAux(0), + reference(0), + hasUnknowns(false), hasDiagnosis(false), isInit(false) { } System::System(std::vector clist_) -: c2p(), p2c(), - subsyslist(0), - reference(), - init(false) +: plist(0), + c2p(), p2c(), + subSystems(0), subSystemsAux(0), + reference(0), + hasUnknowns(false), hasDiagnosis(false), isInit(false) { // create own (shallow) copy of constraints for (std::vector::iterator constr=clist_.begin(); @@ -125,7 +126,16 @@ System::~System() void System::clear() { - clearReference(); + plist.clear(); + pIndex.clear(); + hasUnknowns = false; + hasDiagnosis = false; + + redundant.clear(); + conflictingTags.clear(); + redundantTags.clear(); + + reference.clear(); clearSubSystems(); free(clist); c2p.clear(); @@ -148,7 +158,9 @@ void System::clearByTag(int tagId) int System::addConstraint(Constraint *constr) { - clearReference(); + isInit = false; + if (constr->getTag() >= 0) // negatively tagged constraints have no impact + hasDiagnosis = false; // on the diagnosis clist.push_back(constr); VEC_pD constr_params = constr->params(); @@ -163,12 +175,15 @@ int System::addConstraint(Constraint *constr) void System::removeConstraint(Constraint *constr) { - clearReference(); - clearSubSystems(); - std::vector::iterator it; it = std::find(clist.begin(), clist.end(), constr); + if (it == clist.end()) + return; + clist.erase(it); + if (constr->getTag() >= 0) + hasDiagnosis = false; + clearSubSystems(); VEC_pD constr_params = c2p[constr]; for (VEC_pD::const_iterator param=constr_params.begin(); @@ -545,9 +560,18 @@ void System::rescaleConstraint(int id, double coeff) clist[id]->rescale(coeff); } - -void System::initSolution(VEC_pD ¶ms) +void System::declareUnknowns(VEC_pD ¶ms) { + plist = params; + pIndex.clear(); + for (int i=0; i < int(plist.size()); ++i) + pIndex[plist[i]] = i; + hasUnknowns = true; +} + +void System::initSolution() +{ + // - Stores the current parameters values in the vector "reference" // - identifies any decoupled subsystems and partitions the original // system into corresponding components // - Stores the current parameters in the vector "reference" @@ -556,18 +580,38 @@ void System::initSolution(VEC_pD ¶ms) // - Organizes the rest of constraints into two subsystems for // tag ids >=0 and < 0 respectively and applies the // system reduction specified in the previous step - MAP_pD_I pIndex; - for (int i=0; i < int(params.size()); ++i) - pIndex[params[i]] = i; + + isInit = false; + if (!hasUnknowns) + return; + + // storing reference configuration + setReference(); + + // diagnose conflicting or redundant constraints + if (!hasDiagnosis) { + diagnose(); + if (!hasDiagnosis) + return; + } + std::vector clistR; + if (redundant.size()) { + for (std::vector::const_iterator constr=clist.begin(); + constr != clist.end(); ++constr) + if (redundant.count(*constr) == 0) + clistR.push_back(*constr); + } + else + clistR = clist; // partitioning into decoupled components Graph g; - for (int i=0; i < int(params.size() + clist.size()); i++) + for (int i=0; i < int(plist.size() + clistR.size()); i++) boost::add_vertex(g); - int cvtid = int(params.size()); - for (std::vector::const_iterator constr=clist.begin(); - constr != clist.end(); ++constr, cvtid++) { + int cvtid = int(plist.size()); + for (std::vector::const_iterator constr=clistR.begin(); + constr != clistR.end(); ++constr, cvtid++) { VEC_pD &cparams = c2p[*constr]; for (VEC_pD::const_iterator param=cparams.begin(); param != cparams.end(); ++param) { @@ -580,113 +624,131 @@ void System::initSolution(VEC_pD ¶ms) VEC_I components(boost::num_vertices(g)); int componentsSize = boost::connected_components(g, &components[0]); - clearReference(); - for (VEC_pD::const_iterator param=params.begin(); - param != params.end(); ++param) - reference[*param] = **param; - // identification of equality constraints and parameter reduction - std::set eliminated; // constraints that will be eliminated through reduction - reductionmap.clear(); + std::set reducedConstrs; // constraints that will be eliminated through reduction + reductionmaps.clear(); // destroy any maps + reductionmaps.resize(componentsSize); // create empty maps to be filled in { - VEC_pD reduced_params=params; + VEC_pD reducedParams=plist; - for (std::vector::const_iterator constr=clist.begin(); - constr != clist.end(); ++constr) { + for (std::vector::const_iterator constr=clistR.begin(); + constr != clistR.end(); ++constr) { if ((*constr)->getTag() >= 0 && (*constr)->getTypeId() == Equal) { MAP_pD_I::const_iterator it1,it2; it1 = pIndex.find((*constr)->params()[0]); it2 = pIndex.find((*constr)->params()[1]); if (it1 != pIndex.end() && it2 != pIndex.end()) { - eliminated.insert(*constr); - double *p_kept = reduced_params[it1->second]; - double *p_replaced = reduced_params[it2->second]; - for (int i=0; i < int(params.size()); ++i) - if (reduced_params[i] == p_replaced) - reduced_params[i] = p_kept; + reducedConstrs.insert(*constr); + double *p_kept = reducedParams[it1->second]; + double *p_replaced = reducedParams[it2->second]; + for (int i=0; i < int(plist.size()); ++i) + if (reducedParams[i] == p_replaced) + reducedParams[i] = p_kept; } } } - for (int i=0; i < int(params.size()); ++i) - if (params[i] != reduced_params[i]) - reductionmap[params[i]] = reduced_params[i]; + for (int i=0; i < int(plist.size()); ++i) + if (plist[i] != reducedParams[i]) { + int cid = components[i]; + reductionmaps[cid][plist[i]] = reducedParams[i]; + } } - std::vector< std::vector > clists0(componentsSize), - clists1(componentsSize), - clists2(componentsSize); - int i = int(params.size()); - for (std::vector::const_iterator constr=clist.begin(); - constr != clist.end(); ++constr, i++) { - if (eliminated.count(*constr) == 0) { - int id = components[i]; - if ((*constr)->getTag() >= 0) - clists0[id].push_back(*constr); - else if ((*constr)->getTag() == -1) // move constraints - clists1[id].push_back(*constr); - else // distance from reference constraints - clists2[id].push_back(*constr); + clists.clear(); // destroy any lists + clists.resize(componentsSize); // create empty lists to be filled in + int i = int(plist.size()); + for (std::vector::const_iterator constr=clistR.begin(); + constr != clistR.end(); ++constr, i++) { + if (reducedConstrs.count(*constr) == 0) { + int cid = components[i]; + clists[cid].push_back(*constr); } } - std::vector< std::vector > plists(componentsSize); - for (int i=0; i < int(params.size()); ++i) { - int id = components[i]; - plists[id].push_back(params[i]); + plists.clear(); // destroy any lists + plists.resize(componentsSize); // create empty lists to be filled in + for (int i=0; i < int(plist.size()); ++i) { + int cid = components[i]; + plists[cid].push_back(plist[i]); } + // calculates subSystems and subSystemsAux from clists, plists and reductionmaps clearSubSystems(); - for (int cid=0; cid < componentsSize; cid++) { - subsyslist.push_back(std::vector(0)); - if (clists0[cid].size() > 0) - subsyslist[cid].push_back(new SubSystem(clists0[cid], plists[cid], reductionmap)); - if (clists1[cid].size() > 0) - subsyslist[cid].push_back(new SubSystem(clists1[cid], plists[cid], reductionmap)); - if (clists2[cid].size() > 0) - subsyslist[cid].push_back(new SubSystem(clists2[cid], plists[cid], reductionmap)); + for (int cid=0; cid < clists.size(); cid++) { + std::vector clist0, clist1; + for (std::vector::const_iterator constr=clists[cid].begin(); + constr != clists[cid].end(); ++constr) { + if ((*constr)->getTag() >= 0) + clist0.push_back(*constr); + else // move or distance from reference constraints + clist1.push_back(*constr); + } + + subSystems.push_back(NULL); + subSystemsAux.push_back(NULL); + if (clist0.size() > 0) + subSystems[cid] = new SubSystem(clist0, plists[cid], reductionmaps[cid]); + if (clist1.size() > 0) + subSystemsAux[cid] = new SubSystem(clist1, plists[cid], reductionmaps[cid]); } - init = true; + + isInit = true; } -void System::clearReference() +void System::setReference() { - init = false; reference.clear(); + reference.reserve(plist.size()); + for (VEC_pD::const_iterator param=plist.begin(); + param != plist.end(); ++param) + reference.push_back(**param); } void System::resetToReference() { - for (MAP_pD_D::const_iterator it=reference.begin(); - it != reference.end(); ++it) - *(it->first) = it->second; + if (reference.size() == plist.size()) { + VEC_D::const_iterator ref=reference.begin(); + VEC_pD::iterator param=plist.begin(); + for (; ref != reference.end(); ++ref, ++param) + **param = *ref; + } } int System::solve(VEC_pD ¶ms, bool isFine, Algorithm alg) { - initSolution(params); + declareUnknowns(params); + initSolution(); return solve(isFine, alg); } int System::solve(bool isFine, Algorithm alg) { + if (!isInit) + return Failed; + bool isReset = false; // return success by default in order to permit coincidence constraints to be applied // even if no other system has to be solved int res = Success; - for (int cid=0; cid < int(subsyslist.size()); cid++) { - if (subsyslist[cid].size() > 0 && !isReset) { + for (int cid=0; cid < int(subSystems.size()); cid++) { + if ((subSystems[cid] || subSystemsAux[cid]) && !isReset) { resetToReference(); isReset = true; } - if (subsyslist[cid].size() == 1) - res = std::max(res, solve(subsyslist[cid][0], isFine, alg)); - else if (subsyslist[cid].size() == 2) - res = std::max(res, solve(subsyslist[cid][0], subsyslist[cid][1], isFine)); - else if (subsyslist[cid].size() > 2) - // subsystem 1 has higher priority than subsystems 2,3,... - // these subsystems act like a preconditioner - for (int i=subsyslist[cid].size()-1; i > 0; i--) - res = std::max(res, solve(subsyslist[cid][0], subsyslist[cid][i], isFine)); + if (subSystems[cid] && subSystemsAux[cid]) + res = std::max(res, solve(subSystems[cid], subSystemsAux[cid], isFine)); + else if (subSystems[cid]) + res = std::max(res, solve(subSystems[cid], isFine, alg)); + else if (subSystemsAux[cid]) + res = std::max(res, solve(subSystemsAux[cid], isFine, alg)); + } + if (res == Success) { + for (std::set::const_iterator constr=redundant.begin(); + constr != redundant.end(); constr++) + if ((*constr)->error() > XconvergenceFine) { + res = Converged; + return res; + } } return res; } @@ -1068,7 +1130,7 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) int xsizeB = subsysB->pSize(); int csizeA = subsysA->cSize(); - VEC_pD plist(xsizeA+xsizeB); + VEC_pD plistAB(xsizeA+xsizeB); { VEC_pD plistA, plistB; subsysA->getParamList(plistA); @@ -1079,10 +1141,10 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) VEC_pD::const_iterator it; it = std::set_union(plistA.begin(),plistA.end(), - plistB.begin(),plistB.end(),plist.begin()); - plist.resize(it-plist.begin()); + plistB.begin(),plistB.end(),plistAB.begin()); + plistAB.resize(it-plistAB.begin()); } - int xsize = plist.size(); + int xsize = plistAB.size(); Eigen::MatrixXd B = Eigen::MatrixXd::Identity(xsize, xsize); Eigen::MatrixXd JA(csizeA, xsize); @@ -1100,12 +1162,12 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) subsysA->redirectParams(); subsysB->redirectParams(); - subsysB->getParams(plist,x); - subsysA->getParams(plist,x); - subsysB->setParams(plist,x); // just to ensure that A and B are synchronized + subsysB->getParams(plistAB,x); + subsysA->getParams(plistAB,x); + subsysB->setParams(plistAB,x); // just to ensure that A and B are synchronized - subsysB->calcGrad(plist,grad); - subsysA->calcJacobi(plist,JA); + subsysB->calcGrad(plistAB,grad); + subsysA->calcJacobi(plistAB,JA); subsysA->calcResidual(resA); double convergence = isFine ? XconvergenceFine : XconvergenceRough; @@ -1130,7 +1192,7 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) double tau=0.5; double rho=0.5; double alpha=1; - alpha = std::min(alpha, subsysA->maxStep(plist,xdir)); + alpha = std::min(alpha, subsysA->maxStep(plistAB,xdir)); // Eq. 18.32 // double mu = lambda.lpNorm() + 0.01; @@ -1148,8 +1210,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) double deriv = grad.dot(xdir) - mu * resA.lpNorm<1>(); x = x0 + alpha * xdir; - subsysA->setParams(plist,x); - subsysB->setParams(plist,x); + subsysA->setParams(plistAB,x); + subsysB->setParams(plistAB,x); subsysA->calcResidual(resA); double f = subsysB->error() + mu * resA.lpNorm<1>(); @@ -1161,8 +1223,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) // Eigen::ComputeThinV).solve(-resA); xdir1 = -Y*resA; x += xdir1; // = x0 + alpha * xdir + xdir1 - subsysA->setParams(plist,x); - subsysB->setParams(plist,x); + subsysA->setParams(plistAB,x); + subsysB->setParams(plistAB,x); subsysA->calcResidual(resA); f = subsysB->error() + mu * resA.lpNorm<1>(); if (f < f0 + eta * alpha * deriv) @@ -1172,8 +1234,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) if (alpha < 1e-8) // let the linesearch fail alpha = 0.; x = x0 + alpha * xdir; - subsysA->setParams(plist,x); - subsysB->setParams(plist,x); + subsysA->setParams(plistAB,x); + subsysB->setParams(plistAB,x); subsysA->calcResidual(resA); f = subsysB->error() + mu * resA.lpNorm<1>(); if (alpha < 1e-8) // let the linesearch fail @@ -1186,8 +1248,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) y = grad - JA.transpose() * lambda; { - subsysB->calcGrad(plist,grad); - subsysA->calcJacobi(plist,JA); + subsysB->calcGrad(plistAB,grad); + subsysA->calcJacobi(plistAB,JA); subsysA->calcResidual(resA); } y = grad - JA.transpose() * lambda - y; // Eq. 18.13 @@ -1225,13 +1287,15 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) void System::applySolution() { - for (int cid=0; cid < int(subsyslist.size()); cid++) - for (int i=subsyslist[cid].size()-1; i >= 0; i--) - subsyslist[cid][i]->applySolution(); - - for (MAP_pD_pD::const_iterator it=reductionmap.begin(); - it != reductionmap.end(); ++it) - *(it->first) = *(it->second); + for (int cid=0; cid < int(subSystems.size()); cid++) { + if (subSystemsAux[cid]) + subSystemsAux[cid]->applySolution(); + if (subSystems[cid]) + subSystems[cid]->applySolution(); + for (MAP_pD_pD::const_iterator it=reductionmaps[cid].begin(); + it != reductionmaps[cid].end(); ++it) + *(it->first) = *(it->second); + } } void System::undoSolution() @@ -1239,7 +1303,7 @@ void System::undoSolution() resetToReference(); } -int System::diagnose(VEC_pD ¶ms, VEC_I &conflictingTags) +int System::diagnose() { // Analyses the constrainess grad of the system and provides feedback // The vector "conflictingTags" will hold a group of conflicting constraints @@ -1251,22 +1315,24 @@ int System::diagnose(VEC_pD ¶ms, VEC_I &conflictingTags) // will provide no feedback about possible conflicts between // two high priority constraints. For this reason, tagging // constraints with 0 should be used carefully. - if (!isInit()) - return -1; + hasDiagnosis = false; + if (!hasUnknowns) { + dofs = -1; + return dofs; + } + redundant.clear(); conflictingTags.clear(); - std::vector conflictingIndex; - VEC_I tags; - Eigen::MatrixXd J(clist.size(), params.size()); + redundantTags.clear(); + Eigen::MatrixXd J(clist.size(), plist.size()); int count=0; for (std::vector::iterator constr=clist.begin(); constr != clist.end(); ++constr) { (*constr)->revertParams(); if ((*constr)->getTag() >= 0) { count++; - tags.push_back((*constr)->getTag()); - for (int j=0; j < int(params.size()); j++) - J(count-1,j) = (*constr)->grad(params[j]); + for (int j=0; j < int(plist.size()); j++) + J(count-1,j) = (*constr)->grad(plist[j]); } } @@ -1284,7 +1350,7 @@ int System::diagnose(VEC_pD ¶ms, VEC_I &conflictingTags) R = qrJT.matrixQR().topRows(constrNum) .triangularView(); - if (constrNum > rank) { // conflicting constraints + if (constrNum > rank) { // conflicting or redundant constraints for (int i=1; i < rank; i++) { // eliminate non zeros above pivot assert(R(i,i) != 0); @@ -1296,43 +1362,139 @@ int System::diagnose(VEC_pD ¶ms, VEC_I &conflictingTags) } } } - conflictingIndex.resize(constrNum-rank); + std::vector< std::vector > conflictGroups(constrNum-rank); for (int j=rank; j < constrNum; j++) { for (int row=0; row < rank; row++) { if (fabs(R(row,j)) > 1e-10) { int origCol = qrJT.colsPermutation().indices()[row]; - conflictingIndex[j-rank].push_back(origCol); + conflictGroups[j-rank].push_back(clist[origCol]); } } int origCol = qrJT.colsPermutation().indices()[j]; - conflictingIndex[j-rank].push_back(origCol); + conflictGroups[j-rank].push_back(clist[origCol]); } - SET_I tags_set; - for (int i=0; i < conflictingIndex.size(); i++) { - for (int j=0; j < conflictingIndex[i].size(); j++) { - tags_set.insert(tags[conflictingIndex[i][j]]); + // try to remove the conflicting constraints and solve the + // system in order to check if the removed constraints were + // just redundant but not really conflicting + std::set skipped; + SET_I satisfiedGroups; + while (1) { + std::map< Constraint *, SET_I > conflictingMap; + for (int i=0; i < conflictGroups.size(); i++) { + if (satisfiedGroups.count(i) == 0) { + for (int j=0; j < conflictGroups[i].size(); j++) { + Constraint *constr = conflictGroups[i][j]; + if (constr->getTag() != 0) // exclude constraints tagged with zero + conflictingMap[constr].insert(i); + } + } + } + if (conflictingMap.empty()) + break; + + int maxPopularity = 0; + Constraint *mostPopular = NULL; + for (std::map< Constraint *, SET_I >::const_iterator it=conflictingMap.begin(); + it != conflictingMap.end(); it++) { + if (it->second.size() >= maxPopularity) { + mostPopular = it->first; + maxPopularity = it->second.size(); + } + } + if (maxPopularity > 0) { + skipped.insert(mostPopular); + for (SET_I::const_iterator it=conflictingMap[mostPopular].begin(); + it != conflictingMap[mostPopular].end(); it++) + satisfiedGroups.insert(*it); } } - tags_set.erase(0); // exclude constraints tagged with zero - conflictingTags.resize(tags_set.size()); - std::copy(tags_set.begin(), tags_set.end(), conflictingTags.begin()); - if (paramsNum == rank) // over-constrained - return paramsNum - constrNum; + std::vector clistTmp; + clistTmp.reserve(clist.size()); + for (std::vector::iterator constr=clist.begin(); + constr != clist.end(); ++constr) + if (skipped.count(*constr) == 0) + clistTmp.push_back(*constr); + + SubSystem *subSysTmp = new SubSystem(clistTmp, plist); + int res = solve(subSysTmp); + if (res == Success) { + subSysTmp->applySolution(); + for (std::set::const_iterator constr=skipped.begin(); + constr != skipped.end(); constr++) { + if ((*constr)->error() < XconvergenceFine) + redundant.insert(*constr); + } + resetToReference(); + + std::vector< std::vector > conflictGroupsOrig=conflictGroups; + conflictGroups.clear(); + for (int i=conflictGroupsOrig.size()-1; i >= 0; i--) { + bool isRedundant = false; + for (int j=0; j < conflictGroupsOrig[i].size(); j++) { + if (redundant.count(conflictGroupsOrig[i][j]) > 0) { + isRedundant = true; + break; + } + } + if (!isRedundant) + conflictGroups.push_back(conflictGroupsOrig[i]); + else + constrNum--; + } + } + delete subSysTmp; + + // simplified output of conflicting tags + SET_I conflictingTagsSet; + for (int i=0; i < conflictGroups.size(); i++) { + for (int j=0; j < conflictGroups[i].size(); j++) { + conflictingTagsSet.insert(conflictGroups[i][j]->getTag()); + } + } + conflictingTagsSet.erase(0); // exclude constraints tagged with zero + conflictingTags.resize(conflictingTagsSet.size()); + std::copy(conflictingTagsSet.begin(), conflictingTagsSet.end(), + conflictingTags.begin()); + + // output of redundant tags + SET_I redundantTagsSet; + for (std::set::iterator constr=redundant.begin(); + constr != redundant.end(); ++constr) + redundantTagsSet.insert((*constr)->getTag()); + // remove tags represented at least in one non-redundant constraint + for (std::vector::iterator constr=clist.begin(); + constr != clist.end(); ++constr) + if (redundant.count(*constr) == 0) + redundantTagsSet.erase((*constr)->getTag()); + redundantTags.resize(redundantTagsSet.size()); + std::copy(redundantTagsSet.begin(), redundantTagsSet.end(), + redundantTags.begin()); + + if (paramsNum == rank && constrNum > rank) { // over-constrained + hasDiagnosis = true; + dofs = paramsNum - constrNum; + return dofs; + } } - return paramsNum - rank; + hasDiagnosis = true; + dofs = paramsNum - rank; + return dofs; } - return params.size(); + hasDiagnosis = true; + dofs = plist.size(); + return dofs; } void System::clearSubSystems() { - init = false; - for (int i=0; i < int(subsyslist.size()); i++) - free(subsyslist[i]); - subsyslist.clear(); + isInit = false; + free(subSystems); + free(subSystemsAux); + subSystems.clear(); + subSystemsAux.clear(); } double lineSearch(SubSystem *subsys, Eigen::VectorXd &xdir) diff --git a/src/Mod/Sketcher/App/freegcs/GCS.h b/src/Mod/Sketcher/App/freegcs/GCS.h index 5cd1466ea..f0d87906f 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.h +++ b/src/Mod/Sketcher/App/freegcs/GCS.h @@ -49,25 +49,31 @@ namespace GCS // This is the main class. It holds all constraints and information // about partitioning into subsystems and solution strategies private: - std::vector clist; + VEC_pD plist; // list of the unknown parameters + MAP_pD_I pIndex; + std::vector clist; std::map c2p; // constraint to parameter adjacency list std::map > p2c; // parameter to constraint adjacency list - // each row of subsyslist contains up to 3 subsystems. - // the first one has the highest priority, always used as the primary subsystem - // the second one is used as secondary subsystem - // the third one is used as secondary system and serves as a preconditioner - std::vector< std::vector > subsyslist; + std::vector subSystems, subSystemsAux; void clearSubSystems(); - MAP_pD_D reference; - void clearReference(); - void resetToReference(); + VEC_D reference; + void setReference(); // copies the current parameter values to reference + void resetToReference(); // reverts all parameter values to the stored reference - MAP_pD_pD reductionmap; // for simplification of equality constraints + std::vector< VEC_pD > plists; // partitioned plist except equality constraints + std::vector< std::vector > clists; // partitioned clist except equality constraints + std::vector< MAP_pD_pD > reductionmaps; // for simplification of equality constraints - bool init; + int dofs; + std::set redundant; + VEC_I conflictingTags, redundantTags; + + bool hasUnknowns; // if plist is filled with the unknown parameters + bool hasDiagnosis; // if dofs, conflictingTags, redundantTags are up to date + bool isInit; // if plists, clists, reductionmaps are up to date int solve_BFGS(SubSystem *subsys, bool isFine); int solve_LM(SubSystem *subsys); @@ -147,7 +153,8 @@ namespace GCS int addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId=0); void rescaleConstraint(int id, double coeff); - void initSolution(VEC_pD ¶ms); + void declareUnknowns(VEC_pD ¶ms); + void initSolution(); int solve(bool isFine=true, Algorithm alg=DogLeg); int solve(VEC_pD ¶ms, bool isFine=true, Algorithm alg=DogLeg); @@ -157,9 +164,12 @@ namespace GCS void applySolution(); void undoSolution(); - bool isInit() const { return init; } - - int diagnose(VEC_pD ¶ms, VEC_I &conflictingTags); + int diagnose(); + int dofsNumber() { return hasDiagnosis ? dofs : -1; } + void getConflicting(VEC_I &conflictingOut) const + { conflictingOut = hasDiagnosis ? conflictingTags : VEC_I(0); } + void getRedundant(VEC_I &redundantOut) const + { redundantOut = hasDiagnosis ? redundantTags : VEC_I(0); } }; /////////////////////////////////////// diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp index 7061f3a97..5ef6c65fb 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp @@ -86,6 +86,9 @@ void TaskSketcherMessages::slotSetUp(int type, int dofs, const std::string &msg) case 3: ui->labelConstrainStatus->setText(QString::fromLatin1("Over-constrained sketch
%1
").arg(QString::fromStdString(msg))); break; + case 4: + ui->labelConstrainStatus->setText(QString::fromLatin1("Sketch contains redundant constraints
%1").arg(QString::fromStdString(msg))); + break; } } diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 78841d18c..2239f7445 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -2825,21 +2825,30 @@ void ViewProviderSketch::solveSketch(void) signalSetUp(2, dofs, msg); signalSolved(-1, 0); } - else if (edit->ActSketch.solve() == 0) { // solving the sketch - if (dofs == 0) { - // color the sketch as fully constrained - edit->FullyConstrained = true; - //Base::Console().Message("Fully constrained sketch\n"); - signalSetUp(0, 0, msg); + else { + if (edit->ActSketch.hasRedundancies()) { // redundant constraints + SketchObject::appendRedundantMsg(edit->ActSketch.getRedundant(), msg); + //Base::Console().Warning("Sketch with redundant constraints\n%s",msg.c_str()); + signalSetUp(4, dofs, msg); + } + if (edit->ActSketch.solve() == 0) { // solving the sketch + if (dofs == 0) { + // color the sketch as fully constrained + edit->FullyConstrained = true; + if (!edit->ActSketch.hasRedundancies()) { + //Base::Console().Message("Fully constrained sketch\n"); + signalSetUp(0, 0, msg); + } + } + else if (!edit->ActSketch.hasRedundancies()) { + //Base::Console().Message("Under-constrained sketch with %d degrees of freedom\n", dofs); + signalSetUp(1, dofs, msg); + } + signalSolved(0, edit->ActSketch.SolveTime); } else { - //Base::Console().Message("Under-constrained sketch with %d degrees of freedom\n", dofs); - signalSetUp(1, dofs, msg); + signalSolved(1, edit->ActSketch.SolveTime); } - signalSolved(0, edit->ActSketch.SolveTime); - } - else { - signalSolved(1, edit->ActSketch.SolveTime); } } From 5833e85f00c8ae9fbd1a9816e3d32f5044fa8d71 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Mon, 14 May 2012 11:13:19 -0300 Subject: [PATCH 04/42] Fixed bug in Draft Clone --- src/Mod/Draft/Draft.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 6f8250a3d..0014a4513 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -2853,8 +2853,9 @@ class _Clone: if o.isDerivedFrom("Part::Feature"): sh = o.Shape.copy() m = FreeCAD.Matrix() - m.scale(obj.Scale) - sh = sh.transformGeometry(m) + if hasattr(obj,"Scale") and not sh.isNull(): + m.scale(obj.Scale) + sh = sh.transformGeometry(m) shapes.append(sh) if shapes: obj.Shape = Part.makeCompound(shapes) From 0778aef53bf9c0d82f24d18384bdd11ee328f783 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 14 May 2012 19:15:11 +0200 Subject: [PATCH 05/42] Replace makeTube algorithm --- src/Mod/Part/App/AppPartPy.cpp | 29 +++++++++++++++++-- src/Mod/Part/App/TopoShape.cpp | 51 ++++++++++++++++++++++------------ src/Mod/Part/App/TopoShape.h | 3 +- 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 2662593c5..2132042df 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -1043,14 +1043,36 @@ static PyObject * makeTube(PyObject *self, PyObject *args) PyObject *pshape; double radius; double tolerance=0.001; + char* scont = "C0"; + int maxdegree = 3; + int maxsegment = 30; // Path + radius - if (!PyArg_ParseTuple(args, "O!d", &(TopoShapePy::Type), &pshape, &radius)) + if (!PyArg_ParseTuple(args, "O!d|sii", &(TopoShapePy::Type), &pshape, &radius, &scont, &maxdegree, &maxsegment)) return 0; + std::string str_cont = scont; + int cont; + if (str_cont == "C0") + cont = (int)GeomAbs_C0; + else if (str_cont == "C1") + cont = (int)GeomAbs_C1; + else if (str_cont == "C2") + cont = (int)GeomAbs_C2; + else if (str_cont == "C3") + cont = (int)GeomAbs_C3; + else if (str_cont == "CN") + cont = (int)GeomAbs_CN; + else if (str_cont == "G1") + cont = (int)GeomAbs_G1; + else if (str_cont == "G2") + cont = (int)GeomAbs_G2; + else + cont = (int)GeomAbs_C0; + try { const TopoDS_Shape& path_shape = static_cast(pshape)->getTopoShapePtr()->_Shape; TopoShape myShape(path_shape); - TopoDS_Shape face = myShape.makeTube(radius, tolerance); + TopoDS_Shape face = myShape.makeTube(radius, tolerance, cont, maxdegree, maxsegment); return new TopoShapeFacePy(new TopoShape(face)); } catch (Standard_Failure) { @@ -1465,7 +1487,8 @@ struct PyMethodDef Part_methods[] = { "these must have the same number of edges."}, {"makeTube" ,makeTube,METH_VARARGS, - "makeTube(edge,float) -- Create a tube."}, + "makeTube(edge,radius,[continuity,max degree,max segments]) -- Create a tube.\n" + "continuity is a string which must be 'C0','C1','C2','C3','CN','G1' or 'G1',"}, {"makeSweepSurface" ,makeSweepSurface,METH_VARARGS, "makeSweepSurface(edge(path),edge(profile),[float]) -- Create a profile along a path."}, diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index f78bc5026..22ccd16ad 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -32,7 +32,9 @@ # include # include # include +# include # include +# include # include # include # include @@ -1343,7 +1345,8 @@ TopoDS_Shape TopoShape::makePipeShell(const TopTools_ListOfShape& profiles, return mkPipeShell.Shape(); } -TopoDS_Shape TopoShape::makeTube(double radius, double tol) const +#if 0 +TopoDS_Shape TopoShape::makeTube() const { // http://opencascade.blogspot.com/2009/11/surface-modeling-part3.html if (this->_Shape.IsNull()) @@ -1378,43 +1381,54 @@ TopoDS_Shape TopoShape::makeTube(double radius, double tol) const ); return mkBuilder.Face(); } - -// for testing -static Handle(Law_Function) CreateBsFunction (const Standard_Real theFirst, const Standard_Real theLast) +#else +static Handle(Law_Function) CreateBsFunction (const Standard_Real theFirst, const Standard_Real theLast, const Standard_Real theRadius) { //Handle_Law_BSpline aBs; //Handle_Law_BSpFunc aFunc = new Law_BSpFunc (aBs, theFirst, theLast); Handle_Law_Linear aFunc = new Law_Linear(); - aFunc->Set(theFirst, 2.0, theLast, 3.0); + aFunc->Set(theFirst, theRadius, theLast, theRadius); return aFunc; } -// for testing -TopoDS_Shape TopoShape::makeTube() const +TopoDS_Shape TopoShape::makeTube(double radius, double tol, int cont, int maxdegree, int maxsegm) const { // http://opencascade.blogspot.com/2009/11/surface-modeling-part3.html - Standard_Real theTol = 0.001; + Standard_Real theTol = tol; Standard_Boolean theIsPolynomial = Standard_True; Standard_Boolean myIsElem = Standard_True; - GeomAbs_Shape theContinuity = GeomAbs_G1; - Standard_Integer theMaxDegree = 3; - Standard_Integer theMaxSegment = 1000; + GeomAbs_Shape theContinuity = GeomAbs_Shape(cont); + Standard_Integer theMaxDegree = maxdegree; + Standard_Integer theMaxSegment = maxsegm; if (this->_Shape.IsNull()) Standard_Failure::Raise("Cannot sweep along empty spine"); - if (this->_Shape.ShapeType() != TopAbs_EDGE) - Standard_Failure::Raise("Spine shape is not an edge"); - const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape); - BRepAdaptor_Curve path_adapt(path_edge); + Handle(Adaptor3d_HCurve) myPath; + if (this->_Shape.ShapeType() == TopAbs_EDGE) { + const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape); + BRepAdaptor_Curve path_adapt(path_edge); + myPath = new BRepAdaptor_HCurve(path_adapt); + theContinuity = GeomAbs_C0; + } + //else if (this->_Shape.ShapeType() == TopAbs_WIRE) { + // const TopoDS_Wire& path_wire = TopoDS::Wire(this->_Shape); + // BRepAdaptor_CompCurve path_adapt(path_wire); + // myPath = new BRepAdaptor_HCompCurve(path_adapt); + //} + //else { + // Standard_Failure::Raise("Spine shape is neither an edge nor a wire"); + //} + else { + Standard_Failure::Raise("Spine shape is not an edge"); + } //circular profile - Handle(Geom_Circle) aCirc = new Geom_Circle (gp::XOY(), 1.0); + Handle(Geom_Circle) aCirc = new Geom_Circle (gp::XOY(), radius); aCirc->Rotate (gp::OZ(), Standard_PI/2.); //perpendicular section - Handle(BRepAdaptor_HCurve) myPath = new BRepAdaptor_HCurve(path_adapt); - Handle(Law_Function) myEvol = ::CreateBsFunction (myPath->FirstParameter(), myPath->LastParameter()); + Handle(Law_Function) myEvol = ::CreateBsFunction (myPath->FirstParameter(), myPath->LastParameter(), radius); Handle(GeomFill_SectionLaw) aSec = new GeomFill_EvolvedSection(aCirc, myEvol); Handle(GeomFill_LocationLaw) aLoc = new GeomFill_CurveAndTrihedron(new GeomFill_CorrectedFrenet); aLoc->SetCurve (myPath); @@ -1438,6 +1452,7 @@ TopoDS_Shape TopoShape::makeTube() const return TopoDS_Shape(); } +#endif TopoDS_Shape TopoShape::makeSweep(const TopoDS_Shape& profile, double tol, int fillMode) const { diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index 0cf1087f9..1de76b1ca 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -158,8 +158,7 @@ public: TopoDS_Shape makeThickSolid(const TopTools_ListOfShape& remFace, Standard_Real offset, Standard_Real tolerance) const; TopoDS_Shape makeSweep(const TopoDS_Shape& profile, double, int) const; - TopoDS_Shape makeTube(double radius, double tol) const; - TopoDS_Shape makeTube() const; + TopoDS_Shape makeTube(double radius, double tol, int cont, int maxdeg, int maxsegm) const; TopoDS_Shape makeHelix(Standard_Real pitch, Standard_Real height, Standard_Real radius, Standard_Real angle=0, Standard_Boolean left=Standard_False) const; TopoDS_Shape makeLoft(const TopTools_ListOfShape& profiles, Standard_Boolean isSolid, From 3b81c25665a3f04ee4481e1a5d104f1d5bb2750e Mon Sep 17 00:00:00 2001 From: Sebastian Hoogen Date: Tue, 15 May 2012 18:01:15 +0200 Subject: [PATCH 06/42] add isNull() method to Rotation --- src/Base/RotationPy.xml | 8 ++++++++ src/Base/RotationPyImp.cpp | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/Base/RotationPy.xml b/src/Base/RotationPy.xml index 02dc34ee8..111cfb74c 100644 --- a/src/Base/RotationPy.xml +++ b/src/Base/RotationPy.xml @@ -48,6 +48,14 @@ + + + + isNull() -> Bool + returns True if the rotation equals the unity matrix + + + The rotation elements (as quaternion) diff --git a/src/Base/RotationPyImp.cpp b/src/Base/RotationPyImp.cpp index 7abede54c..159952c7e 100644 --- a/src/Base/RotationPyImp.cpp +++ b/src/Base/RotationPyImp.cpp @@ -144,6 +144,17 @@ PyObject* RotationPy::toEuler(PyObject * args) return Py::new_reference_to(tuple); } +PyObject* RotationPy::isNull(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + Base::Rotation rot = * getRotationPtr(); + Base::Rotation nullrot(0,0,0,1); + Base::Rotation nullrotinv(0,0,0,-1); + bool null = (rot == nullrot) | (rot == nullrotinv); + return Py_BuildValue("O", (null ? Py_True : Py_False)); +} + Py::Tuple RotationPy::getQ(void) const { double q0, q1, q2, q3; From b6003874f2a36314996cdd1890b944baf9c2779d Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 16 May 2012 16:31:02 -0300 Subject: [PATCH 07/42] Added 0000145 : Drawing clip objects --- src/Mod/Drawing/App/AppDrawing.cpp | 2 + src/Mod/Drawing/App/CMakeLists.txt | 2 + src/Mod/Drawing/App/FeatureClip.cpp | 111 +++ src/Mod/Drawing/App/FeatureClip.h | 71 ++ src/Mod/Drawing/App/FeaturePage.cpp | 7 +- src/Mod/Drawing/App/Makefile.am | 2 + src/Mod/Drawing/Gui/Command.cpp | 47 +- src/Mod/Drawing/Gui/Resources/Drawing.qrc | 1 + src/Mod/Drawing/Gui/Resources/Makefile.am | 1 + .../Resources/icons/actions/drawing-clip.svg | 710 ++++++++++++++++++ src/Mod/Drawing/Gui/Workbench.cpp | 4 + 11 files changed, 955 insertions(+), 3 deletions(-) create mode 100644 src/Mod/Drawing/App/FeatureClip.cpp create mode 100644 src/Mod/Drawing/App/FeatureClip.h create mode 100644 src/Mod/Drawing/Gui/Resources/icons/actions/drawing-clip.svg diff --git a/src/Mod/Drawing/App/AppDrawing.cpp b/src/Mod/Drawing/App/AppDrawing.cpp index a581668ba..016abf81b 100644 --- a/src/Mod/Drawing/App/AppDrawing.cpp +++ b/src/Mod/Drawing/App/AppDrawing.cpp @@ -22,6 +22,7 @@ #include "FeatureViewPart.h" #include "FeatureViewAnnotation.h" #include "FeatureProjection.h" +#include "FeatureClip.h" #include "PageGroup.h" extern struct PyMethodDef Drawing_methods[]; @@ -59,6 +60,7 @@ void DrawingExport initDrawing() Drawing::FeatureViewPartPython ::init(); Drawing::FeatureViewPython ::init(); Drawing::FeatureViewAnnotation ::init(); + Drawing::FeatureClip ::init(); } } // extern "C" diff --git a/src/Mod/Drawing/App/CMakeLists.txt b/src/Mod/Drawing/App/CMakeLists.txt index 98767a24a..00710b75e 100644 --- a/src/Mod/Drawing/App/CMakeLists.txt +++ b/src/Mod/Drawing/App/CMakeLists.txt @@ -29,6 +29,8 @@ SET(Features_SRCS FeatureViewPart.h FeatureViewAnnotation.cpp FeatureViewAnnotation.h + FeatureClip.cpp + FeatureClip.h PageGroup.cpp PageGroup.h ) diff --git a/src/Mod/Drawing/App/FeatureClip.cpp b/src/Mod/Drawing/App/FeatureClip.cpp new file mode 100644 index 000000000..c45229929 --- /dev/null +++ b/src/Mod/Drawing/App/FeatureClip.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre 2012 * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +#endif + + +#include +#include +#include +#include +#include +#include + +#include "FeatureClip.h" +#include "FeatureView.h" + +using namespace Drawing; +using namespace std; + + +//=========================================================================== +// FeaturePage +//=========================================================================== + +PROPERTY_SOURCE(Drawing::FeatureClip, App::DocumentObjectGroup) + +FeatureClip::FeatureClip(void) +{ + static const char *group = "Drawing view"; + App::PropertyType hidden = (App::PropertyType)(App::Prop_Hidden); + ADD_PROPERTY_TYPE(ViewResult ,(""),group,hidden,"Resulting SVG view of this clip"); + ADD_PROPERTY_TYPE(X ,(10),group,App::Prop_None ,"The left margin of the view area of this clip"); + ADD_PROPERTY_TYPE(Y ,(10),group,App::Prop_None ,"The top margin of the view area of this clip"); + ADD_PROPERTY_TYPE(Height ,(10),group,App::Prop_None ,"The height of the view area of this clip"); + ADD_PROPERTY_TYPE(Width ,(10),group,App::Prop_None ,"The width of the view area of this clip"); + ADD_PROPERTY_TYPE(ShowFrame ,(0),group,App::Prop_None,"Specifies if the clip frame appears on the page or not"); +} + +FeatureClip::~FeatureClip() +{ +} + +/// get called by the container when a Property was changed +void FeatureClip::onChanged(const App::Property* prop) +{ + App::DocumentObjectGroup::onChanged(prop); +} + +App::DocumentObjectExecReturn *FeatureClip::execute(void) +{ + ostringstream svg; + + // creating clip path + svg << "" + << "" << endl; + + // show clip frame on the page if needed + + if (ShowFrame.getValue()) { + svg << "" << endl; + } + + // create clipped group + svg << "" << endl; + + // get through the children and collect all the views + const std::vector &Grp = Group.getValues(); + for (std::vector::const_iterator It= Grp.begin();It!=Grp.end();++It) { + if ((*It)->getTypeId().isDerivedFrom(Drawing::FeatureView::getClassTypeId())) { + Drawing::FeatureView *View = dynamic_cast(*It); + svg << View->ViewResult.getValue() << endl; + } + } + + // closing clipped group + svg << "" << endl; + + ViewResult.setValue(svg.str().c_str()); + return App::DocumentObject::StdReturn; +} diff --git a/src/Mod/Drawing/App/FeatureClip.h b/src/Mod/Drawing/App/FeatureClip.h new file mode 100644 index 000000000..ae1e6c0fc --- /dev/null +++ b/src/Mod/Drawing/App/FeatureClip.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre 2012 * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef _FeatureClip_h_ +#define _FeatureClip_h_ + + +#include +#include + +namespace Drawing +{ + +/** Base class of all View Features in the drawing module + */ +class DrawingExport FeatureClip: public App::DocumentObjectGroup +{ + PROPERTY_HEADER(Drawing::FeatureClip); + +public: + /// Constructor + FeatureClip(void); + virtual ~FeatureClip(); + + App::PropertyFloat X; + App::PropertyFloat Y; + App::PropertyFloat Width; + App::PropertyFloat Height; + App::PropertyBool ShowFrame; + App::PropertyString ViewResult; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "DrawingGui::ViewProviderDrawingPage"; + } + +protected: + void onChanged(const App::Property* prop); +}; + + +} //namespace Drawing + + +#endif diff --git a/src/Mod/Drawing/App/FeaturePage.cpp b/src/Mod/Drawing/App/FeaturePage.cpp index 684fe28cf..c1730ebc4 100644 --- a/src/Mod/Drawing/App/FeaturePage.cpp +++ b/src/Mod/Drawing/App/FeaturePage.cpp @@ -37,6 +37,7 @@ #include "FeaturePage.h" #include "FeatureView.h" +#include "FeatureClip.h" using namespace Drawing; using namespace std; @@ -124,10 +125,14 @@ App::DocumentObjectExecReturn *FeaturePage::execute(void) // get through the children and collect all the views const std::vector &Grp = Group.getValues(); for (std::vector::const_iterator It= Grp.begin();It!=Grp.end();++It) { - if ((*It)->getTypeId().isDerivedFrom(Drawing::FeatureView::getClassTypeId())) { + if ( (*It)->getTypeId().isDerivedFrom(Drawing::FeatureView::getClassTypeId()) ) { Drawing::FeatureView *View = dynamic_cast(*It); ofile << View->ViewResult.getValue(); ofile << tempendl << tempendl << tempendl; + } else if ( (*It)->getTypeId().isDerivedFrom(Drawing::FeatureClip::getClassTypeId()) ) { + Drawing::FeatureClip *Clip = dynamic_cast(*It); + ofile << Clip->ViewResult.getValue(); + ofile << tempendl << tempendl << tempendl; } } } diff --git a/src/Mod/Drawing/App/Makefile.am b/src/Mod/Drawing/App/Makefile.am index 462017c0f..098b9b786 100644 --- a/src/Mod/Drawing/App/Makefile.am +++ b/src/Mod/Drawing/App/Makefile.am @@ -15,6 +15,8 @@ libDrawing_la_SOURCES=\ FeatureViewPart.h \ FeatureViewAnnotation.cpp \ FeatureViewAnnotation.h \ + FeatureClip.cpp \ + FeatureClip.h \ PageGroup.cpp \ PageGroup.h \ ProjectionAlgos.cpp \ diff --git a/src/Mod/Drawing/Gui/Command.cpp b/src/Mod/Drawing/Gui/Command.cpp index 2f9345b97..7ed5a4641 100644 --- a/src/Mod/Drawing/Gui/Command.cpp +++ b/src/Mod/Drawing/Gui/Command.cpp @@ -366,9 +366,9 @@ CmdDrawingAnnotation::CmdDrawingAnnotation() // seting the sGroup = QT_TR_NOOP("Drawing"); sMenuText = QT_TR_NOOP("&Annotation"); - sToolTipText = QT_TR_NOOP("Inserts an Annotation view in the active document"); + sToolTipText = QT_TR_NOOP("Inserts an Annotation view in the active drawing"); sWhatsThis = "Drawing_Annotation"; - sStatusTip = QT_TR_NOOP("Inserts an Annotation view in the active document"); + sStatusTip = QT_TR_NOOP("Inserts an Annotation view in the active drawing"); sPixmap = "actions/drawing-annotation"; } @@ -398,6 +398,48 @@ bool CmdDrawingAnnotation::isActive(void) return (getActiveGuiDocument() ? true : false); } + +//=========================================================================== +// Drawing_Clip +//=========================================================================== + +DEF_STD_CMD_A(CmdDrawingClip); + +CmdDrawingClip::CmdDrawingClip() + : Command("Drawing_Clip") +{ + // seting the + sGroup = QT_TR_NOOP("Drawing"); + sMenuText = QT_TR_NOOP("&Clip"); + sToolTipText = QT_TR_NOOP("Inserts a clip group in the active drawing"); + sWhatsThis = "Drawing_Annotation"; + sStatusTip = QT_TR_NOOP("Inserts a clip group in the active drawing"); + sPixmap = "actions/drawing-clip"; +} + +void CmdDrawingClip::activated(int iMsg) +{ + + std::vector pages = this->getDocument()->getObjectsOfType(Drawing::FeaturePage::getClassTypeId()); + if (pages.empty()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No page to insert"), + QObject::tr("Create a page to insert.")); + return; + } + std::string PageName = pages.front()->getNameInDocument(); + std::string FeatName = getUniqueObjectName("Clip"); + openCommand("Create Clip"); + doCommand(Doc,"App.activeDocument().addObject('Drawing::FeatureClip','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); + updateActive(); + commitCommand(); +} + +bool CmdDrawingClip::isActive(void) +{ + return (getActiveGuiDocument() ? true : false); +} + //=========================================================================== // Drawing_ExportPage //=========================================================================== @@ -495,6 +537,7 @@ void CreateDrawingCommands(void) rcCmdMgr.addCommand(new CmdDrawingOrthoViews()); rcCmdMgr.addCommand(new CmdDrawingOpenBrowserView()); rcCmdMgr.addCommand(new CmdDrawingAnnotation()); + rcCmdMgr.addCommand(new CmdDrawingClip()); rcCmdMgr.addCommand(new CmdDrawingExportPage()); rcCmdMgr.addCommand(new CmdDrawingProjectShape()); } diff --git a/src/Mod/Drawing/Gui/Resources/Drawing.qrc b/src/Mod/Drawing/Gui/Resources/Drawing.qrc index fad40eb81..bc0ae4cdf 100644 --- a/src/Mod/Drawing/Gui/Resources/Drawing.qrc +++ b/src/Mod/Drawing/Gui/Resources/Drawing.qrc @@ -17,6 +17,7 @@ icons/actions/drawing-orthoviews.svg icons/actions/drawing-openbrowser.svg icons/actions/drawing-annotation.svg + icons/actions/drawing-clip.svg translations/Drawing_af.qm translations/Drawing_de.qm translations/Drawing_es.qm diff --git a/src/Mod/Drawing/Gui/Resources/Makefile.am b/src/Mod/Drawing/Gui/Resources/Makefile.am index e42a14b03..69b335394 100644 --- a/src/Mod/Drawing/Gui/Resources/Makefile.am +++ b/src/Mod/Drawing/Gui/Resources/Makefile.am @@ -21,6 +21,7 @@ EXTRA_DIST = \ icons/actions/drawing-orthoviews.svg \ icons/actions/drawing-openbrowser.svg \ icons/actions/drawing-annotation.svg \ + icons/actions/drawing-clip.svg \ icons/Page.svg \ icons/Pages.svg \ icons/View.svg \ diff --git a/src/Mod/Drawing/Gui/Resources/icons/actions/drawing-clip.svg b/src/Mod/Drawing/Gui/Resources/icons/actions/drawing-clip.svg new file mode 100644 index 000000000..dd58ec78a --- /dev/null +++ b/src/Mod/Drawing/Gui/Resources/icons/actions/drawing-clip.svg @@ -0,0 +1,710 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/src/Mod/Drawing/Gui/Workbench.cpp b/src/Mod/Drawing/Gui/Workbench.cpp index b7bd8bbce..e74f510e6 100644 --- a/src/Mod/Drawing/Gui/Workbench.cpp +++ b/src/Mod/Drawing/Gui/Workbench.cpp @@ -63,6 +63,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const *part << "Drawing_OrthoViews"; *part << "Drawing_OpenBrowserView"; *part << "Drawing_Annotation"; + *part << "Drawing_Clip"; *part << "Drawing_ExportPage"; return root; @@ -80,6 +81,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *part << "Drawing_OrthoViews"; *part << "Drawing_OpenBrowserView"; *part << "Drawing_Annotation"; + *part << "Drawing_Clip"; *part << "Drawing_ExportPage"; return root; } @@ -97,6 +99,8 @@ Gui::ToolBarItem* Workbench::setupCommandBars() const *img << "Drawing_NewPage"; *img << "Drawing_OrthoViews"; *img << "Drawing_OpenBrowserView"; + *img << "Drawing_Annotation"; + *img << "Drawing_Clip"; img = new Gui::ToolBarItem(root); img->setCommand("Views"); *img << "Drawing_NewView"; From abbb19987f7821991f4d97e63ea413afd74bf16b Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 18 May 2012 00:12:30 +0200 Subject: [PATCH 08/42] fix in makeTube --- src/Mod/Part/App/TopoShape.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index 22ccd16ad..fd90af18f 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -1409,7 +1409,6 @@ TopoDS_Shape TopoShape::makeTube(double radius, double tol, int cont, int maxdeg const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape); BRepAdaptor_Curve path_adapt(path_edge); myPath = new BRepAdaptor_HCurve(path_adapt); - theContinuity = GeomAbs_C0; } //else if (this->_Shape.ShapeType() == TopAbs_WIRE) { // const TopoDS_Wire& path_wire = TopoDS::Wire(this->_Shape); From d81094cd78398bdf7cd548bd4644404ee6bd1768 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 18 May 2012 01:25:31 +0200 Subject: [PATCH 09/42] Mesh segmentation --- src/Mod/Mesh/App/CMakeLists.txt | 14 +- src/Mod/Mesh/App/Core/Algorithm.cpp | 37 ++-- src/Mod/Mesh/App/Core/Algorithm.h | 45 ++++- src/Mod/Mesh/App/Core/Approximation.cpp | 99 ++++----- src/Mod/Mesh/App/Core/Approximation.h | 203 +++++++++++-------- src/Mod/Mesh/App/Core/Curvature.cpp | 236 ++++++++++++++++++++++ src/Mod/Mesh/App/Core/Curvature.h | 75 +++++++ src/Mod/Mesh/App/Core/Segmentation.cpp | 228 +++++++++++++++++++++ src/Mod/Mesh/App/Core/Segmentation.h | 161 +++++++++++++++ src/Mod/Mesh/App/FeatureMeshCurvature.cpp | 50 ++--- src/Mod/Mesh/App/Makefile.am | 11 +- src/Mod/Mesh/App/Mesh.cpp | 12 +- src/Mod/Mesh/App/Mesh.h | 2 +- src/Mod/Mesh/App/MeshPy.xml | 17 +- src/Mod/Mesh/App/MeshPyImp.cpp | 51 ++++- 15 files changed, 1033 insertions(+), 208 deletions(-) create mode 100644 src/Mod/Mesh/App/Core/Curvature.cpp create mode 100644 src/Mod/Mesh/App/Core/Curvature.h create mode 100644 src/Mod/Mesh/App/Core/Segmentation.cpp create mode 100644 src/Mod/Mesh/App/Core/Segmentation.h diff --git a/src/Mod/Mesh/App/CMakeLists.txt b/src/Mod/Mesh/App/CMakeLists.txt index ee813be7b..97e285680 100644 --- a/src/Mod/Mesh/App/CMakeLists.txt +++ b/src/Mod/Mesh/App/CMakeLists.txt @@ -1,20 +1,26 @@ if(WIN32) - add_definitions(-DFCAppMesh -DWM4_FOUNDATION_DLL_EXPORT) + add_definitions(-DFCAppMesh -DWM4_FOUNDATION_DLL_EXPORT -DEIGEN2_SUPPORT) +else (Win32) + add_definitions(-DEIGEN2_SUPPORT) endif(WIN32) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/3rdParty ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_PATH} ${XERCESC_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} - ${EIGEN2_INCLUDE_DIR} + ${EIGEN3_INCLUDE_DIR} ) set(Mesh_LIBS ${Boost_LIBRARIES} + ${QT_QTCORE_LIBRARY} + ${QT_QTCORE_LIBRARY_DEBUG} FreeCADBase FreeCADApp ) @@ -41,6 +47,8 @@ SET(Core_SRCS Core/Approximation.h Core/Builder.cpp Core/Builder.h + Core/Curvature.cpp + Core/Curvature.h Core/Definitions.cpp Core/Definitions.h Core/Degeneration.cpp @@ -61,6 +69,8 @@ SET(Core_SRCS Core/MeshKernel.h Core/Projection.cpp Core/Projection.h + Core/Segmentation.cpp + Core/Segmentation.h Core/SetOperations.cpp Core/SetOperations.h Core/Smoothing.cpp diff --git a/src/Mod/Mesh/App/Core/Algorithm.cpp b/src/Mod/Mesh/App/Core/Algorithm.cpp index 40d4907d4..281fba7f7 100644 --- a/src/Mod/Mesh/App/Core/Algorithm.cpp +++ b/src/Mod/Mesh/App/Core/Algorithm.cpp @@ -1156,7 +1156,6 @@ void MeshAlgorithm::CheckFacets(const Base::ViewProjMethod* pclProj, const Base: { const MeshPointArray& p = _rclMesh.GetPoints(); const MeshFacetArray& f = _rclMesh.GetFacets(); - Base::SequencerLauncher seq("Check facets", f.size()); Base::Vector3f pt2d; unsigned long index=0; for (MeshFacetArray::_TConstIterator it = f.begin(); it != f.end(); ++it,++index) { @@ -1167,7 +1166,6 @@ void MeshAlgorithm::CheckFacets(const Base::ViewProjMethod* pclProj, const Base: break; } } - seq.next(); } } @@ -1743,47 +1741,38 @@ std::set MeshRefPointToFacets::NeighbourPoints(const std::vector< return nb; } -// ermittelt alle Nachbarn zum Facet deren Schwerpunkt unterhalb der mpx. Distanz befindet. -// Facet deren VISIT-Flag gesetzt ist werden nicht beruecksichtig. -/// @todo -void MeshRefPointToFacets::Neighbours (unsigned long ulFacetInd, float fMpxDist, std::vector &rclNb) +void MeshRefPointToFacets::Neighbours (unsigned long ulFacetInd, float fMaxDist, MeshCollector& collect) const { - rclNb.clear(); + std::set visited; Base::Vector3f clCenter = _rclMesh.GetFacet(ulFacetInd).GetGravityPoint(); const MeshFacetArray& rFacets = _rclMesh.GetFacets(); - SearchNeighbours(rFacets.begin() + ulFacetInd, clCenter, fMpxDist * fMpxDist, rclNb); - - for (std::vector::iterator i = rclNb.begin(); i != rclNb.end(); i++) - (*i)->ResetFlag(MeshFacet::VISIT); + SearchNeighbours(rFacets, ulFacetInd, clCenter, fMaxDist * fMaxDist, visited, collect); } -/// @todo -void MeshRefPointToFacets::SearchNeighbours(MeshFacetArray::_TConstIterator f_it, const Base::Vector3f &rclCenter, float fMpxDist, std::vector &rclNb) +void MeshRefPointToFacets::SearchNeighbours(const MeshFacetArray& rFacets, unsigned long index, const Base::Vector3f &rclCenter, + float fMaxDist2, std::set& visited, MeshCollector& collect) const { - if (f_it->IsFlag(MeshFacet::VISIT) == true) + if (visited.find(index) != visited.end()) return; - if (Base::DistanceP2(rclCenter, _rclMesh.GetFacet(*f_it).GetGravityPoint()) > fMpxDist) + const MeshFacet& face = rFacets[index]; + if (Base::DistanceP2(rclCenter, _rclMesh.GetFacet(face).GetGravityPoint()) > fMaxDist2) return; - rclNb.push_back(f_it); - f_it->SetFlag(MeshFacet::VISIT); - - MeshPointArray::_TConstIterator p_beg = _rclMesh.GetPoints().begin(); - MeshFacetArray::_TConstIterator f_beg = _rclMesh.GetFacets().begin(); - + visited.insert(index); + collect.Append(_rclMesh, index); for (int i = 0; i < 3; i++) { - const std::set &f = (*this)[f_it->_aulPoints[i]]; + const std::set &f = (*this)[face._aulPoints[i]]; for (std::set::const_iterator j = f.begin(); j != f.end(); ++j) { - SearchNeighbours(f_beg+*j, rclCenter, fMpxDist, rclNb); + SearchNeighbours(rFacets, *j, rclCenter, fMaxDist2, visited, collect); } } } MeshFacetArray::_TConstIterator -MeshRefPointToFacets::getFacet (unsigned long index) const +MeshRefPointToFacets::GetFacet (unsigned long index) const { return _rclMesh.GetFacets().begin() + index; } diff --git a/src/Mod/Mesh/App/Core/Algorithm.h b/src/Mod/Mesh/App/Core/Algorithm.h index 9baa667e2..78a4caf5b 100644 --- a/src/Mod/Mesh/App/Core/Algorithm.h +++ b/src/Mod/Mesh/App/Core/Algorithm.h @@ -310,6 +310,43 @@ protected: const MeshKernel &_rclMesh; /**< The mesh kernel. */ }; +class MeshExport MeshCollector +{ +public: + MeshCollector(){} + virtual void Append(const MeshCore::MeshKernel&, unsigned long index) = 0; +}; + +class MeshExport PointCollector : public MeshCollector +{ +public: + PointCollector(std::vector& ind) : indices(ind){} + virtual void Append(const MeshCore::MeshKernel& kernel, unsigned long index) + { + unsigned long ulP1, ulP2, ulP3; + kernel.GetFacetPoints(index, ulP1, ulP2, ulP3); + indices.push_back(ulP1); + indices.push_back(ulP2); + indices.push_back(ulP3); + } + +private: + std::vector& indices; +}; + +class MeshExport FacetCollector : public MeshCollector +{ +public: + FacetCollector(std::vector& ind) : indices(ind){} + void Append(const MeshCore::MeshKernel&, unsigned long index) + { + indices.push_back(index); + } + +private: + std::vector& indices; +}; + /** * The MeshRefPointToFacets builds up a structure to have access to all facets indexing * a point. @@ -329,14 +366,14 @@ public: /// Rebuilds up data structure void Rebuild (void); const std::set& operator[] (unsigned long) const; - MeshFacetArray::_TConstIterator getFacet (unsigned long) const; + MeshFacetArray::_TConstIterator GetFacet (unsigned long) const; std::set NeighbourPoints(const std::vector& , int level) const; - void Neighbours (unsigned long ulFacetInd, float fMaxDist, std::vector &rclNb); + void Neighbours (unsigned long ulFacetInd, float fMaxDist, MeshCollector& collect) const; Base::Vector3f GetNormal(unsigned long) const; protected: - void SearchNeighbours(MeshFacetArray::_TConstIterator pFIter, const Base::Vector3f &rclCenter, - float fMaxDist, std::vector &rclNb); + void SearchNeighbours(const MeshFacetArray& rFacets, unsigned long index, const Base::Vector3f &rclCenter, + float fMaxDist, std::set &visit, MeshCollector& collect) const; protected: const MeshKernel &_rclMesh; /**< The mesh kernel. */ diff --git a/src/Mod/Mesh/App/Core/Approximation.cpp b/src/Mod/Mesh/App/Core/Approximation.cpp index ace1a796e..15b0c522f 100644 --- a/src/Mod/Mesh/App/Core/Approximation.cpp +++ b/src/Mod/Mesh/App/Core/Approximation.cpp @@ -37,6 +37,7 @@ #include //#define FC_USE_EIGEN +//#define FC_USE_BOOST #if defined(FC_USE_BOOST) #include #include @@ -54,25 +55,26 @@ extern "C" void LAPACK_DGESV (int const* n, int const* nrhs, #elif defined(FC_USE_EIGEN) # include #endif +# include using namespace MeshCore; -void Approximation::Convert( const Wm4::Vector3& Wm4, Base::Vector3f& pt) +void Approximation::Convert( const Wm4::Vector3& Wm4, Base::Vector3f& pt) { - pt.Set( Wm4.X(), Wm4.Y(), Wm4.Z() ); + pt.Set( (float)Wm4.X(), (float)Wm4.Y(), (float)Wm4.Z() ); } -void Approximation::Convert( const Base::Vector3f& pt, Wm4::Vector3& Wm4) +void Approximation::Convert( const Base::Vector3f& pt, Wm4::Vector3& Wm4) { Wm4.X() = pt.x; Wm4.Y() = pt.y; Wm4.Z() = pt.z; } -void Approximation::GetMgcVectorArray(std::vector< Wm4::Vector3 >& rcPts) const +void Approximation::GetMgcVectorArray(std::vector< Wm4::Vector3 >& rcPts) const { std::list< Base::Vector3f >::const_iterator It; for (It = _vPoints.begin(); It != _vPoints.end(); ++It) { - Wm4::Vector3 pt( (*It).x, (*It).y, (*It).z ); + Wm4::Vector3 pt( (*It).x, (*It).y, (*It).z ); rcPts.push_back( pt ); } } @@ -176,7 +178,7 @@ float PlaneFit::Fit() int r = lapack::syev('V','U',A,eigenval,lapack::optimal_workspace()); if (r) { } - float sigma; + float sigma = 0; #elif defined(FC_USE_EIGEN) Eigen::Matrix3d covMat = Eigen::Matrix3d::Zero(); covMat(0,0) = sxx; @@ -360,17 +362,15 @@ void PlaneFit::ProjectToPlane () // ------------------------------------------------------------------------------- -float FunctionContainer::dKoeff[]; // Koeffizienten der Quadrik - -bool QuadraticFit::GetCurvatureInfo(float x, float y, float z, - float &rfCurv0, float &rfCurv1, - Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, float &dDistance) +bool QuadraticFit::GetCurvatureInfo(double x, double y, double z, + double &rfCurv0, double &rfCurv1, + Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, double &dDistance) { assert( _bIsFitted ); bool bResult = false; if (_bIsFitted) { - Wm4::Vector3 Dir0, Dir1; + Wm4::Vector3 Dir0, Dir1; FunctionContainer clFuncCont( _fCoeff ); bResult = clFuncCont.CurvatureInfo( x, y, z, rfCurv0, rfCurv1, Dir0, Dir1, dDistance ); @@ -382,7 +382,7 @@ bool QuadraticFit::GetCurvatureInfo(float x, float y, float z, return bResult; } -bool QuadraticFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, float &rfCurv1) +bool QuadraticFit::GetCurvatureInfo(double x, double y, double z, double &rfCurv0, double &rfCurv1) { bool bResult = false; @@ -394,12 +394,12 @@ bool QuadraticFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, f return bResult; } -const float& QuadraticFit::GetCoeffArray() const +const double& QuadraticFit::GetCoeffArray() const { return _fCoeff[0]; } -float QuadraticFit::GetCoeff(unsigned long ulIndex) const +double QuadraticFit::GetCoeff(unsigned long ulIndex) const { assert( ulIndex >= 0 && ulIndex < 10 ); @@ -414,9 +414,9 @@ float QuadraticFit::Fit() float fResult = FLOAT_MAX; if (CountPoints() > 0) { - std::vector< Wm4::Vector3 > cPts; + std::vector< Wm4::Vector3 > cPts; GetMgcVectorArray( cPts ); - fResult = Wm4::QuadraticFit3( CountPoints(), &(cPts[0]), _fCoeff ); + fResult = Wm4::QuadraticFit3( CountPoints(), &(cPts[0]), _fCoeff ); _fLastResult = fResult; _bIsFitted = true; @@ -425,7 +425,7 @@ float QuadraticFit::Fit() return fResult; } -void QuadraticFit::CalcEigenValues(float &dLambda1, float &dLambda2, float &dLambda3, +void QuadraticFit::CalcEigenValues(double &dLambda1, double &dLambda2, double &dLambda3, Base::Vector3f &clEV1, Base::Vector3f &clEV2, Base::Vector3f &clEV3) const { assert( _bIsFitted ); @@ -451,16 +451,16 @@ void QuadraticFit::CalcEigenValues(float &dLambda1, float &dLambda2, float &dLam * */ - Wm4::Matrix3 akMat(_fCoeff[4], _fCoeff[7]/2.0f, _fCoeff[8]/2.0f, + Wm4::Matrix3 akMat(_fCoeff[4], _fCoeff[7]/2.0f, _fCoeff[8]/2.0f, _fCoeff[7]/2.0f, _fCoeff[5], _fCoeff[9]/2.0f, _fCoeff[8]/2.0f, _fCoeff[9]/2.0f, _fCoeff[6] ); - Wm4::Matrix3 rkRot, rkDiag; + Wm4::Matrix3 rkRot, rkDiag; akMat.EigenDecomposition( rkRot, rkDiag ); - Wm4::Vector3 vEigenU = rkRot.GetColumn(0); - Wm4::Vector3 vEigenV = rkRot.GetColumn(1); - Wm4::Vector3 vEigenW = rkRot.GetColumn(2); + Wm4::Vector3 vEigenU = rkRot.GetColumn(0); + Wm4::Vector3 vEigenV = rkRot.GetColumn(1); + Wm4::Vector3 vEigenW = rkRot.GetColumn(2); Convert( vEigenU, clEV1 ); Convert( vEigenV, clEV2 ); @@ -471,11 +471,11 @@ void QuadraticFit::CalcEigenValues(float &dLambda1, float &dLambda2, float &dLam dLambda3 = rkDiag[2][2]; } -void QuadraticFit::CalcZValues( float x, float y, float &dZ1, float &dZ2 ) const +void QuadraticFit::CalcZValues( double x, double y, double &dZ1, double &dZ2 ) const { assert( _bIsFitted ); - float dDisk = _fCoeff[3]*_fCoeff[3]+2*_fCoeff[3]*_fCoeff[8]*x+2*_fCoeff[3]*_fCoeff[9]*y+ + double dDisk = _fCoeff[3]*_fCoeff[3]+2*_fCoeff[3]*_fCoeff[8]*x+2*_fCoeff[3]*_fCoeff[9]*y+ _fCoeff[8]*_fCoeff[8]*x*x+2*_fCoeff[8]*x*_fCoeff[9]*y+_fCoeff[9]*_fCoeff[9]*y*y- 4*_fCoeff[6]*_fCoeff[0]-4*_fCoeff[6]*_fCoeff[1]*x-4*_fCoeff[6]*_fCoeff[2]*y- 4*_fCoeff[6]*_fCoeff[7]*x*y-4*_fCoeff[6]*_fCoeff[4]*x*x-4*_fCoeff[6]*_fCoeff[5]*y*y; @@ -494,8 +494,8 @@ void QuadraticFit::CalcZValues( float x, float y, float &dZ1, float &dZ2 ) const else dDisk = sqrt( dDisk ); - dZ1 = 0.5f * ( ( -_fCoeff[3] - _fCoeff[8]*x - _fCoeff[9]*y + dDisk ) / _fCoeff[6] ); - dZ2 = 0.5f * ( ( -_fCoeff[3] - _fCoeff[8]*x - _fCoeff[9]*y - dDisk ) / _fCoeff[6] ); + dZ1 = 0.5 * ( ( -_fCoeff[3] - _fCoeff[8]*x - _fCoeff[9]*y + dDisk ) / _fCoeff[6] ); + dZ2 = 0.5 * ( ( -_fCoeff[3] - _fCoeff[8]*x - _fCoeff[9]*y - dDisk ) / _fCoeff[6] ); } // ------------------------------------------------------------------------------- @@ -529,13 +529,13 @@ float SurfaceFit::Fit() return fResult; } -bool SurfaceFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, float &rfCurv1, - Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, float &dDistance ) +bool SurfaceFit::GetCurvatureInfo(double x, double y, double z, double &rfCurv0, double &rfCurv1, + Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, double &dDistance ) { bool bResult = false; if (_bIsFitted) { - Wm4::Vector3 Dir0, Dir1; + Wm4::Vector3 Dir0, Dir1; FunctionContainer clFuncCont( _fCoeff ); bResult = clFuncCont.CurvatureInfo( x, y, z, rfCurv0, rfCurv1, Dir0, Dir1, dDistance ); @@ -547,7 +547,7 @@ bool SurfaceFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, flo return bResult; } -bool SurfaceFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, float &rfCurv1) +bool SurfaceFit::GetCurvatureInfo(double x, double y, double z, double &rfCurv0, double &rfCurv1) { assert( _bIsFitted ); bool bResult = false; @@ -560,18 +560,17 @@ bool SurfaceFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, flo return bResult; } -float SurfaceFit::PolynomFit() +double SurfaceFit::PolynomFit() { if (PlaneFit::Fit() == FLOAT_MAX) return FLOAT_MAX; -#if 0 -#if defined(FC_USE_BOOST) Base::Vector3d bs(this->_vBase.x,this->_vBase.y,this->_vBase.z); Base::Vector3d ex(this->_vDirU.x,this->_vDirU.y,this->_vDirU.z); Base::Vector3d ey(this->_vDirV.x,this->_vDirV.y,this->_vDirV.z); Base::Vector3d ez(this->_vDirW.x,this->_vDirW.y,this->_vDirW.z); +#if defined(FC_USE_BOOST) ublas::matrix A(6,6); ublas::vector b(6); for (int i=0; i<6; i++) { @@ -580,6 +579,11 @@ float SurfaceFit::PolynomFit() } b(i) = 0.0; } +#else + Eigen::Matrix A = Eigen::Matrix::Zero(); + Eigen::Matrix b = Eigen::Matrix::Zero(); + Eigen::Matrix x = Eigen::Matrix::Zero(); +#endif for (std::list::const_iterator it = _vPoints.begin(); it != _vPoints.end(); it++) { Base::Vector3d clPoint(it->x,it->y,it->z); @@ -648,29 +652,34 @@ float SurfaceFit::PolynomFit() A(5,4) = A(4,5); - +#if defined(FC_USE_BOOST) namespace lapack= boost::numeric::bindings::lapack; //std::clog << A << std::endl; //std::clog << b << std::endl; - lapack::gesv(A,b); + //lapack::gesv(A,b); + ublas::vector x(6); + x = b; //std::clog << b << std::endl; +#else + // A.llt().solve(b,&x); // not sure if always positive definite + A.qr().solve(b,&x); +#endif - _fCoeff[0] = (float)(-b(5)); - _fCoeff[1] = (float)(-b(3)); - _fCoeff[2] = (float)(-b(4)); + _fCoeff[0] = (float)(-x(5)); + _fCoeff[1] = (float)(-x(3)); + _fCoeff[2] = (float)(-x(4)); _fCoeff[3] = 1.0f; - _fCoeff[4] = (float)(-b(0)); - _fCoeff[5] = (float)(-b(1)); + _fCoeff[4] = (float)(-x(0)); + _fCoeff[5] = (float)(-x(1)); _fCoeff[6] = 0.0f; - _fCoeff[7] = (float)(-b(2)); + _fCoeff[7] = (float)(-x(2)); _fCoeff[8] = 0.0f; _fCoeff[9] = 0.0f; -#endif -#endif + return 0.0f; } -float SurfaceFit::Value(float x, float y) const +double SurfaceFit::Value(double x, double y) const { float z = 0.0f; if (_bIsFitted) { diff --git a/src/Mod/Mesh/App/Core/Approximation.h b/src/Mod/Mesh/App/Core/Approximation.h index 74124f35e..623a17dac 100644 --- a/src/Mod/Mesh/App/Core/Approximation.h +++ b/src/Mod/Mesh/App/Core/Approximation.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -34,8 +35,64 @@ #include #include -namespace MeshCore { +namespace Wm4 +{ +/** + * An implicit surface is defined by F(x,y,z) = 0. + * This polynomial surface is actually defined as z = f(x,y) = ax^2 + by^2 + cx + dy + exy + g. + * To use Wm3 routines for implicit surfaces we can write the surface also as F(x,y,z) = f(x,y) - z = 0. + * @author Werner Mayer + */ +template +class PolynomialSurface : public ImplicitSurface +{ +public: + PolynomialSurface (const Real afCoeff[6]) + { for (int i=0; i<6; i++) m_afCoeff[i] = afCoeff[i]; } + + virtual ~PolynomialSurface () {} + + // the function + virtual Real F (const Vector3& rkP) const + { + return ( m_afCoeff[0]*rkP.X()*rkP.X() + + m_afCoeff[1]*rkP.Y()*rkP.Y() + + m_afCoeff[2]*rkP.X() + + m_afCoeff[3]*rkP.Y() + + m_afCoeff[4]*rkP.X()*rkP.Y() + + m_afCoeff[5]-rkP.Z()) ; + } + + // first-order partial derivatives + virtual Real FX (const Vector3& rkP) const + { return (Real)(2.0*m_afCoeff[0]*rkP.X() + m_afCoeff[2] + m_afCoeff[4]*rkP.Y()); } + virtual Real FY (const Vector3& rkP) const + { return (Real)(2.0*m_afCoeff[1]*rkP.Y() + m_afCoeff[3] + m_afCoeff[4]*rkP.X()); } + virtual Real FZ (const Vector3& rkP) const + { return (Real)-1.0; } + + // second-order partial derivatives + virtual Real FXX (const Vector3& rkP) const + { return (Real)(2.0*m_afCoeff[0]); } + virtual Real FXY (const Vector3& rkP) const + { return (Real)(m_afCoeff[4]); } + virtual Real FXZ (const Vector3& rkP) const + { return (Real)0.0; } + virtual Real FYY (const Vector3& rkP) const + { return (Real)(2.0*m_afCoeff[1]); } + virtual Real FYZ (const Vector3& rkP) const + { return (Real)0.0; } + virtual Real FZZ (const Vector3& rkP) const + { return (Real)0.0; } + +protected: + Real m_afCoeff[6]; +}; + +} + +namespace MeshCore { /** * Abstract base class for approximation of a geometry to a given set of points. @@ -104,15 +161,15 @@ protected: /** * Converts point from Wm4::Vector3 to Base::Vector3f. */ - static void Convert( const Wm4::Vector3&, Base::Vector3f&); + static void Convert( const Wm4::Vector3&, Base::Vector3f&); /** * Converts point from Base::Vector3f to Wm4::Vector3. */ - static void Convert( const Base::Vector3f&, Wm4::Vector3&); + static void Convert( const Base::Vector3f&, Wm4::Vector3&); /** * Creates a vector of Wm4::Vector3 elements. */ - void GetMgcVectorArray( std::vector< Wm4::Vector3 >& rcPts ) const; + void GetMgcVectorArray( std::vector< Wm4::Vector3 >& rcPts ) const; protected: std::list< Base::Vector3f > _vPoints; /**< Holds the points for the fit algorithm. */ @@ -201,22 +258,22 @@ public: /** * Übertragen der Quadric-Koeffizienten * @param ulIndex Nummer des Koeffizienten (0..9) - * @return float Wert des Koeffizienten + * @return double Wert des Koeffizienten */ - float GetCoeff(unsigned long ulIndex) const; + double GetCoeff(unsigned long ulIndex) const; /** * Übertragen der Koeffizientan als Referenz * auf das interne Array - * @return const float& Referenz auf das float-Array + * @return const double& Referenz auf das double-Array */ - const float& GetCoeffArray() const; + const double& GetCoeffArray() const; /** * Aufruf des Fit-Algorithmus * @return float Qualität des Fits. */ float Fit(); - void CalcZValues(float x, float y, float &dZ1, float &dZ2) const; + void CalcZValues(double x, double y, double &dZ1, double &dZ2) const; /** * Berechnen der Krümmungswerte der Quadric in einem bestimmten Punkt. * @param x X-Koordinate @@ -229,12 +286,12 @@ public: * @param dDistance * @return bool Fehlerfreie Ausfürhung = true, ansonsten false */ - bool GetCurvatureInfo(float x, float y, float z, - float &rfCurv0, float &rfCurv1, - Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, float &dDistance); + bool GetCurvatureInfo(double x, double y, double z, + double &rfCurv0, double &rfCurv1, + Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, double &dDistance); - bool GetCurvatureInfo(float x, float y, float z, - float &rfCurv0, float &rfcurv1); + bool GetCurvatureInfo(double x, double y, double z, + double &rfCurv0, double &rfcurv1); /** * Aufstellen der Formanmatrix A und Berechnen der Eigenwerte. * @param dLambda1 Eigenwert 1 @@ -244,11 +301,11 @@ public: * @param clEV2 Eigenvektor 2 * @param clEV3 Eigenvektor 3 */ - void CalcEigenValues(float &dLambda1, float &dLambda2, float &dLambda3, + void CalcEigenValues(double &dLambda1, double &dLambda2, double &dLambda3, Base::Vector3f &clEV1, Base::Vector3f &clEV2, Base::Vector3f &clEV3) const; protected: - float _fCoeff[ 10 ]; /**< Ziel der Koeffizienten aus dem Fit */ + double _fCoeff[ 10 ]; /**< Ziel der Koeffizienten aus dem Fit */ }; // ------------------------------------------------------------------------------- @@ -275,15 +332,15 @@ public: */ virtual ~SurfaceFit(){}; - bool GetCurvatureInfo(float x, float y, float z, float &rfCurv0, float &rfCurv1, - Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, float &dDistance); - bool GetCurvatureInfo(float x, float y, float z, float &rfCurv0, float &rfcurv1); + bool GetCurvatureInfo(double x, double y, double z, double &rfCurv0, double &rfCurv1, + Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, double &dDistance); + bool GetCurvatureInfo(double x, double y, double z, double &rfCurv0, double &rfcurv1); float Fit(); - float Value(float x, float y) const; + double Value(double x, double y) const; protected: - float PolynomFit(); - float _fCoeff[ 10 ]; /**< Ziel der Koeffizienten aus dem Fit */ + double PolynomFit(); + double _fCoeff[ 10 ]; /**< Ziel der Koeffizienten aus dem Fit */ }; // ------------------------------------------------------------------------------- @@ -300,42 +357,24 @@ public: * Die MGC-Algorithmen arbeiten mit Funktionen dieses * Types */ - typedef float (*Function)(float,float,float); + typedef double (*Function)(double,double,double); /** * Der parametrisierte Konstruktor. Erwartet ein Array * mit den Quadric-Koeffizienten. * @param pKoef Zeiger auf die Quadric-Parameter - * (float [10]) + * (double [10]) */ - FunctionContainer(const float *pKoef) + FunctionContainer(const double *pKoef) { Assign( pKoef ); -/* - Function oF; - Function aoDF[3]; - Function aoD2F[6]; - - oF = &F; - aoDF[0] = &Fx; - aoDF[1] = &Fy; - aoDF[2] = &Fz; - aoD2F[0] = &Fxx; - aoD2F[1] = &Fxy; - aoD2F[2] = &Fxz; - aoD2F[3] = &Fyy; - aoD2F[4] = &Fyz; - aoD2F[5] = &Fzz; - - pImplSurf = new Wm4::QuadricSurface( oF, aoDF, aoD2F );*/ - - pImplSurf = new Wm4::QuadricSurface( dKoeff ); + pImplSurf = new Wm4::QuadricSurface( dKoeff ); } /** * Übernehmen der Quadric-Parameter * @param pKoef Zeiger auf die Quadric-Parameter - * (doube [10]) + * (double [10]) */ - void Assign( const float *pKoef ) + void Assign( const double *pKoef ) { for (long ct=0; ct < 10; ct++) dKoeff[ ct ] = pKoef[ ct ]; @@ -344,13 +383,13 @@ public: * Destruktor. Löscht die ImpicitSurface Klasse * der MGC-Bibliothek wieder */ - virtual ~FunctionContainer(){ delete pImplSurf; } + ~FunctionContainer(){ delete pImplSurf; } /** * Zugriff auf die Koeffizienten der Quadric * @param idx Index des Parameters - * @return float& Der Koeffizient + * @return double& Der Koeffizient */ - float& operator[](int idx){ return dKoeff[ idx ]; } + double& operator[](int idx){ return dKoeff[ idx ]; } /** * Redirector auf eine Methode der MGC Bibliothek. Ermittelt * die Hauptkrümmungen und ihre Richtungen im angegebenen Punkt. @@ -364,22 +403,22 @@ public: * @param dDistance Ergebnis das die Entfernung des Punktes von der Quadrik angibt. * @return bool Fehlerfreie Ausfürhung = true, ansonsten false */ - bool CurvatureInfo(float x, float y, float z, - float &rfCurv0, float &rfCurv1, - Wm4::Vector3 &rkDir0, Wm4::Vector3 &rkDir1, float &dDistance) + bool CurvatureInfo(double x, double y, double z, + double &rfCurv0, double &rfCurv1, + Wm4::Vector3 &rkDir0, Wm4::Vector3 &rkDir1, double &dDistance) { - return pImplSurf->ComputePrincipalCurvatureInfo( Wm4::Vector3(x, y, z),rfCurv0, rfCurv1, rkDir0, rkDir1 ); + return pImplSurf->ComputePrincipalCurvatureInfo( Wm4::Vector3(x, y, z),rfCurv0, rfCurv1, rkDir0, rkDir1 ); } - Base::Vector3f GetGradient( float x, float y, float z ) const + Base::Vector3f GetGradient( double x, double y, double z ) const { - Wm4::Vector3 grad = pImplSurf->GetGradient( Wm4::Vector3(x, y, z) ); + Wm4::Vector3 grad = pImplSurf->GetGradient( Wm4::Vector3(x, y, z) ); return Base::Vector3f( grad.X(), grad.Y(), grad.Z() ); } - Base::Matrix4D GetHessian( float x, float y, float z ) const + Base::Matrix4D GetHessian( double x, double y, double z ) const { - Wm4::Matrix3 hess = pImplSurf->GetHessian( Wm4::Vector3(x, y, z) ); + Wm4::Matrix3 hess = pImplSurf->GetHessian( Wm4::Vector3(x, y, z) ); Base::Matrix4D cMat; cMat.setToUnity(); cMat[0][0] = hess[0][0]; cMat[0][1] = hess[0][1]; cMat[0][2] = hess[0][2]; cMat[1][0] = hess[1][0]; cMat[1][1] = hess[1][1]; cMat[1][2] = hess[1][2]; @@ -387,23 +426,23 @@ public: return cMat; } - bool CurvatureInfo(float x, float y, float z, - float &rfCurv0, float &rfCurv1) + bool CurvatureInfo(double x, double y, double z, + double &rfCurv0, double &rfCurv1) { - float dQuot = Fz(x,y,z); - float zx = - ( Fx(x,y,z) / dQuot ); - float zy = - ( Fy(x,y,z) / dQuot ); + double dQuot = Fz(x,y,z); + double zx = - ( Fx(x,y,z) / dQuot ); + double zy = - ( Fy(x,y,z) / dQuot ); - float zxx = - ( 2.0f * ( dKoeff[5] + dKoeff[6] * zx * zx + dKoeff[8] * zx ) ) / dQuot; - float zyy = - ( 2.0f * ( dKoeff[5] + dKoeff[6] * zy * zy + dKoeff[9] * zy ) ) / dQuot; - float zxy = - ( dKoeff[6] * zx * zy + dKoeff[7] + dKoeff[8] * zy + dKoeff[9] * zx ) / dQuot; + double zxx = - ( 2.0f * ( dKoeff[5] + dKoeff[6] * zx * zx + dKoeff[8] * zx ) ) / dQuot; + double zyy = - ( 2.0f * ( dKoeff[5] + dKoeff[6] * zy * zy + dKoeff[9] * zy ) ) / dQuot; + double zxy = - ( dKoeff[6] * zx * zy + dKoeff[7] + dKoeff[8] * zy + dKoeff[9] * zx ) / dQuot; - float dNen = 1 + zx*zx + zy*zy; - float dNenSqrt = (float)sqrt( dNen ); - float K = ( zxx * zyy - zxy * zxy ) / ( dNen * dNen ); - float H = 0.5f * ( ( 1.0f+zx*zx - 2*zx*zy*zxy + (1.0f+zy*zy)*zxx ) / ( dNenSqrt * dNenSqrt * dNenSqrt ) ) ; + double dNen = 1 + zx*zx + zy*zy; + double dNenSqrt = (double)sqrt( dNen ); + double K = ( zxx * zyy - zxy * zxy ) / ( dNen * dNen ); + double H = 0.5f * ( ( 1.0f+zx*zx - 2*zx*zy*zxy + (1.0f+zy*zy)*zxx ) / ( dNenSqrt * dNenSqrt * dNenSqrt ) ) ; - float dDiscr = (float)sqrt(fabs(H*H-K)); + double dDiscr = (double)sqrt(fabs(H*H-K)); rfCurv0 = H - dDiscr; rfCurv1 = H + dDiscr; @@ -411,7 +450,7 @@ public: } //+++++++++ Quadric +++++++++++++++++++++++++++++++++++++++ - static float F ( float x, float y, float z ) + double F ( double x, double y, double z ) { return (dKoeff[0] + dKoeff[1]*x + dKoeff[2]*y + dKoeff[3]*z + dKoeff[4]*x*x + dKoeff[5]*y*y + dKoeff[6]*z*z + @@ -419,48 +458,48 @@ public: } //+++++++++ 1. derivations ++++++++++++++++++++++++++++++++ - static float Fx ( float x, float y, float z ) + double Fx ( double x, double y, double z ) { return( dKoeff[1] + 2.0f*dKoeff[4]*x + dKoeff[7]*y + dKoeff[8]*z ); } - static float Fy ( float x, float y, float z ) + double Fy ( double x, double y, double z ) { return( dKoeff[2] + 2.0f*dKoeff[5]*y + dKoeff[7]*x + dKoeff[9]*z ); } - static float Fz ( float x, float y, float z ) + double Fz ( double x, double y, double z ) { return( dKoeff[3] + 2.0f*dKoeff[6]*z + dKoeff[8]*x + dKoeff[9]*y ); } //+++++++++ 2. derivations ++++++++++++++++++++++++++++++++ - static float Fxx( float x, float y, float z ) + double Fxx( double x, double y, double z ) { return( 2.0f*dKoeff[4] ); } - static float Fxy( float x, float y, float z ) + double Fxy( double x, double y, double z ) { return( dKoeff[7] ); } - static float Fxz( float x, float y, float z ) + double Fxz( double x, double y, double z ) { return( dKoeff[8] ); } - static float Fyy( float x, float y, float z ) + double Fyy( double x, double y, double z ) { return( 2.0f*dKoeff[5] ); } - static float Fyz( float x, float y, float z ) + double Fyz( double x, double y, double z ) { return( dKoeff[9] ); } - static float Fzz( float x, float y, float z ) + double Fzz( double x, double y, double z ) { return( 2.0f*dKoeff[6] ); } protected: - static float dKoeff[ 10 ]; /**< Koeffizienten der Quadric */ - Wm4::ImplicitSurface *pImplSurf; /**< Zugriff auf die MGC-Bibliothek */ + double dKoeff[ 10 ]; /**< Koeffizienten der Quadric */ + Wm4::ImplicitSurface *pImplSurf; /**< Zugriff auf die MGC-Bibliothek */ private: /** diff --git a/src/Mod/Mesh/App/Core/Curvature.cpp b/src/Mod/Mesh/App/Core/Curvature.cpp new file mode 100644 index 000000000..d0371da4b --- /dev/null +++ b/src/Mod/Mesh/App/Core/Curvature.cpp @@ -0,0 +1,236 @@ +/*************************************************************************** + * Copyright (c) 2012 Imetric 3D GmbH * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +#endif + +#include +#include +#include +#include + +#include +#include + +#include "Curvature.h" +#include "Algorithm.h" +#include "Approximation.h" +#include "MeshKernel.h" +#include "Iterator.h" +#include "Tools.h" +#include +#include + +using namespace MeshCore; + +MeshCurvature::MeshCurvature(const MeshKernel& kernel) + : myKernel(kernel), myMinPoints(20), myRadius(0.5f) +{ + mySegment.resize(kernel.CountFacets()); + std::generate(mySegment.begin(), mySegment.end(), Base::iotaGen(0)); +} + +MeshCurvature::MeshCurvature(const MeshKernel& kernel, const std::vector& segm) + : myKernel(kernel), myMinPoints(20), myRadius(0.5f), mySegment(segm) +{ +} + +void MeshCurvature::ComputePerFace(bool parallel) +{ + Base::Vector3f rkDir0, rkDir1, rkPnt; + Base::Vector3f rkNormal; + myCurvature.clear(); + MeshRefPointToFacets search(myKernel); + FacetCurvature face(myKernel, search, myRadius, myMinPoints); + + if (!parallel) { + Base::SequencerLauncher seq("Curvature estimation", mySegment.size()); + for (std::vector::iterator it = mySegment.begin(); it != mySegment.end(); ++it) { + CurvatureInfo info = face.Compute(*it); + myCurvature.push_back(info); + seq.next(); + } + } + else { + QFuture future = QtConcurrent::mapped + (mySegment, boost::bind(&FacetCurvature::Compute, &face, _1)); + QFutureWatcher watcher; + watcher.setFuture(future); + watcher.waitForFinished(); + for (QFuture::const_iterator it = future.begin(); it != future.end(); ++it) { + myCurvature.push_back(*it); + } + } +} + +void MeshCurvature::ComputePerVertex() +{ + myCurvature.clear(); + + // get all points + std::vector< Wm4::Vector3 > aPnts; + aPnts.reserve(myKernel.CountPoints()); + MeshPointIterator cPIt(myKernel); + for (cPIt.Init(); cPIt.More(); cPIt.Next()) { + Wm4::Vector3 cP(cPIt->x, cPIt->y, cPIt->z); + aPnts.push_back(cP); + } + + // get all point connections + std::vector aIdx; + aIdx.reserve(3*myKernel.CountFacets()); + const MeshFacetArray& raFts = myKernel.GetFacets(); + for (MeshFacetArray::const_iterator jt = raFts.begin(); jt != raFts.end(); ++jt) { + for (int i=0; i<3; i++) { + aIdx.push_back((int)jt->_aulPoints[i]); + } + } + + // compute vertex based curvatures + Wm4::MeshCurvature meshCurv(myKernel.CountPoints(), &(aPnts[0]), myKernel.CountFacets(), &(aIdx[0])); + + // get curvature information now + const Wm4::Vector3* aMaxCurvDir = meshCurv.GetMaxDirections(); + const Wm4::Vector3* aMinCurvDir = meshCurv.GetMinDirections(); + const double* aMaxCurv = meshCurv.GetMaxCurvatures(); + const double* aMinCurv = meshCurv.GetMinCurvatures(); + + myCurvature.reserve(myKernel.CountPoints()); + for (unsigned long i=0; i& ind) : indices(ind){} + virtual void Append(const MeshCore::MeshKernel& kernel, unsigned long index) + { + unsigned long ulP1, ulP2, ulP3; + kernel.GetFacetPoints(index, ulP1, ulP2, ulP3); + indices.insert(ulP1); + indices.insert(ulP2); + indices.insert(ulP3); + } + +private: + std::set& indices; +}; +} + +// -------------------------------------------------------- + +FacetCurvature::FacetCurvature(const MeshKernel& kernel, const MeshRefPointToFacets& search, float r, unsigned long pt) + : myKernel(kernel), mySearch(search), myRadius(r), myMinPoints(pt) +{ +} + +CurvatureInfo FacetCurvature::Compute(unsigned long index) const +{ + Base::Vector3f rkDir0, rkDir1, rkPnt; + Base::Vector3f rkNormal; + + MeshGeomFacet face = myKernel.GetFacet(index); + Base::Vector3f face_gravity = face.GetGravityPoint(); + Base::Vector3f face_normal = face.GetNormal(); + std::set point_indices; + FitPointCollector collect(point_indices); + + float searchDist = myRadius; + int attempts=0; + do { + mySearch.Neighbours(index, searchDist, collect); + if (point_indices.empty()) + break; + float min_points = myMinPoints; + float use_points = point_indices.size(); + searchDist = searchDist * sqrt(min_points/use_points); + } + while((point_indices.size() < myMinPoints) && (attempts++ < 3)); + + std::vector fitPoints; + const MeshPointArray& verts = myKernel.GetPoints(); + fitPoints.reserve(point_indices.size()); + for (std::set::iterator it = point_indices.begin(); it != point_indices.end(); ++it) { + fitPoints.push_back(verts[*it] - face_gravity); + } + + float fMin, fMax; + if (fitPoints.size() >= myMinPoints) { + SurfaceFit surf_fit; + surf_fit.AddPoints(fitPoints); + surf_fit.Fit(); + rkNormal = surf_fit.GetNormal(); + double dMin, dMax, dDistance; + if (surf_fit.GetCurvatureInfo(0.0, 0.0, 0.0, dMin, dMax, rkDir1, rkDir0, dDistance)) { + fMin = (float)dMin; + fMax = (float)dMax; + } + else { + fMin = FLT_MAX; + fMax = FLT_MAX; + } + } + else { + // too few points => cannot calc any properties + fMin = FLT_MAX; + fMax = FLT_MAX; + } + + CurvatureInfo info; + if (fMin < fMax) { + info.fMaxCurvature = fMax; + info.fMinCurvature = fMin; + info.cMaxCurvDir = rkDir1; + info.cMinCurvDir = rkDir0; + } + else { + info.fMaxCurvature = fMin; + info.fMinCurvature = fMax; + info.cMaxCurvDir = rkDir0; + info.cMinCurvDir = rkDir1; + } + + // Reverse the direction of the normal vector if required + // (Z component of "local" normal vectors should be opposite in sign to the "local" view vector) + if (rkNormal * face_normal < 0.0) { + // Note: Changing the normal directions is similar to flipping over the object. + // In this case we must adjust the curvature information as well. + std::swap(info.cMaxCurvDir,info.cMinCurvDir); + std::swap(info.fMaxCurvature,info.fMinCurvature); + info.fMaxCurvature *= (-1.0); + info.fMinCurvature *= (-1.0); + } + + return info; +} diff --git a/src/Mod/Mesh/App/Core/Curvature.h b/src/Mod/Mesh/App/Core/Curvature.h new file mode 100644 index 000000000..7c200946a --- /dev/null +++ b/src/Mod/Mesh/App/Core/Curvature.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (c) 2012 Imetric 3D GmbH * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef MESHCORE_CURVATURE_H +#define MESHCORE_CURVATURE_H + +#include +#include + +namespace MeshCore { + +class MeshKernel; +class MeshRefPointToFacets; + +/** Curvature information. */ +struct MeshExport CurvatureInfo +{ + float fMaxCurvature, fMinCurvature; + Base::Vector3f cMaxCurvDir, cMinCurvDir; +}; + +class MeshExport FacetCurvature +{ +public: + FacetCurvature(const MeshKernel& kernel, const MeshRefPointToFacets& search, float, unsigned long); + CurvatureInfo Compute(unsigned long index) const; + +private: + const MeshKernel& myKernel; + const MeshRefPointToFacets& mySearch; + unsigned long myMinPoints; + float myRadius; +}; + +class MeshExport MeshCurvature +{ +public: + MeshCurvature(const MeshKernel& kernel); + MeshCurvature(const MeshKernel& kernel, const std::vector& segm); + float GetRadius() const { return myRadius; } + void SetRadius(float r) { myRadius = r; } + void ComputePerFace(bool parallel); + void ComputePerVertex(); + const std::vector& GetCurvature() const { return myCurvature; } + +private: + const MeshKernel& myKernel; + unsigned long myMinPoints; + float myRadius; + std::vector mySegment; + std::vector myCurvature; +}; + +} // MeshCore + +#endif // MESHCORE_CURVATURE_H diff --git a/src/Mod/Mesh/App/Core/Segmentation.cpp b/src/Mod/Mesh/App/Core/Segmentation.cpp new file mode 100644 index 000000000..4326457e5 --- /dev/null +++ b/src/Mod/Mesh/App/Core/Segmentation.cpp @@ -0,0 +1,228 @@ +/*************************************************************************** + * Copyright (c) 2012 Imetric 3D GmbH * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#endif + +#include "Segmentation.h" +#include "Algorithm.h" +#include "Approximation.h" + +using namespace MeshCore; + +void MeshSurfaceSegment::PrepareFacet(unsigned long) +{ +} + +void MeshSurfaceSegment::AddSegment(const std::vector& segm) +{ + if (segm.size() >= minFacets) { + segments.push_back(segm); + } +} + +// -------------------------------------------------------- + +MeshDistancePlanarSegment::MeshDistancePlanarSegment(const MeshKernel& mesh, unsigned long minFacets, float tol) + : MeshDistanceSurfaceSegment(mesh, minFacets, tol), fitter(new PlaneFit) +{ +} + +MeshDistancePlanarSegment::~MeshDistancePlanarSegment() +{ + delete fitter; +} + +void MeshDistancePlanarSegment::PrepareFacet(unsigned long index) +{ + fitter->Clear(); + + MeshGeomFacet triangle = kernel.GetFacet(index); + basepoint = triangle.GetGravityPoint(); + normal = triangle.GetNormal(); + fitter->AddPoint(triangle._aclPoints[0]); + fitter->AddPoint(triangle._aclPoints[1]); + fitter->AddPoint(triangle._aclPoints[2]); +} + +bool MeshDistancePlanarSegment::TestFacet (const MeshFacet& face) const +{ + if (!fitter->Done()) + fitter->Fit(); + MeshGeomFacet triangle = kernel.GetFacet(face); + for (int i=0; i<3; i++) { + if (fabs(fitter->GetDistanceToPlane(triangle._aclPoints[i])) > tolerance) + return false; + } + + fitter->AddPoint(triangle.GetGravityPoint()); + return true; +} + +// -------------------------------------------------------- + +bool MeshCurvaturePlanarSegment::TestFacet (const MeshFacet &rclFacet) const +{ + for (int i=0; i<3; i++) { + const CurvatureInfo& ci = info[rclFacet._aulPoints[i]]; + if (fabs(ci.fMinCurvature) > tolerance) + return false; + if (fabs(ci.fMaxCurvature) > tolerance) + return false; + } + + return true; +} + +bool MeshCurvatureCylindricalSegment::TestFacet (const MeshFacet &rclFacet) const +{ + for (int i=0; i<3; i++) { + const CurvatureInfo& ci = info[rclFacet._aulPoints[i]]; + if (ci.fMaxCurvature > ci.fMinCurvature) { + // convexe + if (fabs(ci.fMinCurvature) > tolerance) + return false; + float diff = ci.fMaxCurvature - curvature; + if (fabs(diff) > tolerance) + return false; + } + else { + // concave + if (fabs(ci.fMaxCurvature) > tolerance) + return false; + float diff = ci.fMinCurvature + curvature; + if (fabs(diff) > tolerance) + return false; + } + } + + return true; +} + +bool MeshCurvatureSphericalSegment::TestFacet (const MeshFacet &rclFacet) const +{ + for (int i=0; i<3; i++) { + const CurvatureInfo& ci = info[rclFacet._aulPoints[i]]; + if (ci.fMaxCurvature * ci.fMinCurvature < 0) + return false; + float diff; + diff = fabs(ci.fMinCurvature) - curvature; + if (fabs(diff) > tolerance) + return false; + diff = fabs(ci.fMaxCurvature) - curvature; + if (fabs(diff) > tolerance) + return false; + } + + return true; +} + +bool MeshCurvatureFreeformSegment::TestFacet (const MeshFacet &rclFacet) const +{ + for (int i=0; i<3; i++) { + const CurvatureInfo& ci = info[rclFacet._aulPoints[i]]; + if (fabs(ci.fMinCurvature-c2) > tolerance) + return false; + if (fabs(ci.fMaxCurvature-c1) > tolerance) + return false; + } + + return true; +} + +// -------------------------------------------------------- + +MeshSurfaceVisitor::MeshSurfaceVisitor (const MeshSurfaceSegment& segm, std::vector &indices) + : indices(indices), segm(segm) +{ +} + +MeshSurfaceVisitor::~MeshSurfaceVisitor () +{ +} + +bool MeshSurfaceVisitor::AllowVisit (const MeshFacet& face, const MeshFacet&, + unsigned long, unsigned long, unsigned short) +{ + return segm.TestFacet(face); +} + +bool MeshSurfaceVisitor::Visit (const MeshFacet & face, const MeshFacet &, + unsigned long ulFInd, unsigned long) +{ + indices.push_back(ulFInd); + return true; +} + +// -------------------------------------------------------- + +void MeshSegmentAlgorithm::FindSegments(std::vector& segm) +{ + // reset VISIT flags + unsigned long startFacet; + MeshCore::MeshAlgorithm cAlgo(myKernel); + cAlgo.ResetFacetFlag(MeshCore::MeshFacet::VISIT); + + const MeshCore::MeshFacetArray& rFAry = myKernel.GetFacets(); + MeshCore::MeshFacetArray::_TConstIterator iCur = rFAry.begin(); + MeshCore::MeshFacetArray::_TConstIterator iBeg = rFAry.begin(); + MeshCore::MeshFacetArray::_TConstIterator iEnd = rFAry.end(); + + // start from the first not visited facet + cAlgo.CountFacetFlag(MeshCore::MeshFacet::VISIT); + std::vector resetVisited; + + for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { + cAlgo.ResetFacetsFlag(resetVisited, MeshCore::MeshFacet::VISIT); + resetVisited.clear(); + + iCur = std::find_if(iBeg, iEnd, std::bind2nd(MeshCore::MeshIsNotFlag(), + MeshCore::MeshFacet::VISIT)); + startFacet = iCur - iBeg; + while (startFacet != ULONG_MAX) { + // collect all facets of the same geometry + std::vector indices; + indices.push_back(startFacet); + (*it)->PrepareFacet(startFacet); + MeshSurfaceVisitor pv(**it, indices); + myKernel.VisitNeighbourFacets(pv, startFacet); + + // add or discard the segment + if (indices.size() == 1) { + resetVisited.push_back(startFacet); + } + else { + (*it)->AddSegment(indices); + } + + // search for the next start facet + iCur = std::find_if(iCur, iEnd, std::bind2nd(MeshCore::MeshIsNotFlag(), + MeshCore::MeshFacet::VISIT)); + if (iCur < iEnd) + startFacet = iCur - iBeg; + else + startFacet = ULONG_MAX; + } + } +} diff --git a/src/Mod/Mesh/App/Core/Segmentation.h b/src/Mod/Mesh/App/Core/Segmentation.h new file mode 100644 index 000000000..e45ecff4c --- /dev/null +++ b/src/Mod/Mesh/App/Core/Segmentation.h @@ -0,0 +1,161 @@ +/*************************************************************************** + * Copyright (c) 2012 Imetric 3D GmbH * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef MESHCORE_SEGMENTATION_H +#define MESHCORE_SEGMENTATION_H + +#include "MeshKernel.h" +#include "Curvature.h" +#include "Visitor.h" +#include + +namespace MeshCore { + +class PlaneFit; +class MeshFacet; +typedef std::vector MeshSegment; + +class MeshExport MeshSurfaceSegment +{ +public: + MeshSurfaceSegment(unsigned long minFacets) + : minFacets(minFacets) {} + virtual ~MeshSurfaceSegment() {} + virtual bool TestFacet (const MeshFacet &rclFacet) const = 0; + virtual void PrepareFacet(unsigned long); + void AddSegment(const std::vector&); + const std::vector GetSegments() const { return segments; } + +protected: + std::vector segments; + unsigned long minFacets; +}; + +// -------------------------------------------------------- + +class MeshExport MeshDistanceSurfaceSegment : public MeshSurfaceSegment +{ +public: + MeshDistanceSurfaceSegment(const MeshKernel& mesh, unsigned long minFacets, float tol) + : MeshSurfaceSegment(minFacets), kernel(mesh), tolerance(tol) {} + +protected: + const MeshKernel& kernel; + float tolerance; +}; + +class MeshExport MeshDistancePlanarSegment : public MeshDistanceSurfaceSegment +{ +public: + MeshDistancePlanarSegment(const MeshKernel& mesh, unsigned long minFacets, float tol); + virtual ~MeshDistancePlanarSegment(); + bool TestFacet (const MeshFacet &rclFacet) const; + void PrepareFacet(unsigned long); + +protected: + Base::Vector3f basepoint; + Base::Vector3f normal; + PlaneFit* fitter; +}; + +// -------------------------------------------------------- + +class MeshExport MeshCurvatureSurfaceSegment : public MeshSurfaceSegment +{ +public: + MeshCurvatureSurfaceSegment(const std::vector& ci, unsigned long minFacets, float tol) + : MeshSurfaceSegment(minFacets), info(ci), tolerance(tol) {} + +protected: + const std::vector& info; + float tolerance; +}; + +class MeshExport MeshCurvaturePlanarSegment : public MeshCurvatureSurfaceSegment +{ +public: + MeshCurvaturePlanarSegment(const std::vector& ci, unsigned long minFacets, float tol) + : MeshCurvatureSurfaceSegment(ci, minFacets, tol) {} + virtual bool TestFacet (const MeshFacet &rclFacet) const; +}; + +class MeshExport MeshCurvatureCylindricalSegment : public MeshCurvatureSurfaceSegment +{ +public: + MeshCurvatureCylindricalSegment(const std::vector& ci, unsigned long minFacets, float tol, float radius) + : MeshCurvatureSurfaceSegment(ci, minFacets, tol) { curvature = 1/radius;} + virtual bool TestFacet (const MeshFacet &rclFacet) const; + +private: + float curvature; +}; + +class MeshExport MeshCurvatureSphericalSegment : public MeshCurvatureSurfaceSegment +{ +public: + MeshCurvatureSphericalSegment(const std::vector& ci, unsigned long minFacets, float tol, float radius) + : MeshCurvatureSurfaceSegment(ci, minFacets, tol) { curvature = 1/radius;} + virtual bool TestFacet (const MeshFacet &rclFacet) const; + +private: + float curvature; +}; + +class MeshExport MeshCurvatureFreeformSegment : public MeshCurvatureSurfaceSegment +{ +public: + MeshCurvatureFreeformSegment(const std::vector& ci, unsigned long minFacets, float tol, float c1, float c2) + : MeshCurvatureSurfaceSegment(ci, minFacets, tol), c1(c1), c2(c2) {} + virtual bool TestFacet (const MeshFacet &rclFacet) const; + +private: + float c1, c2; +}; + +class MeshExport MeshSurfaceVisitor : public MeshFacetVisitor +{ +public: + MeshSurfaceVisitor (const MeshSurfaceSegment& segm, std::vector &indices); + virtual ~MeshSurfaceVisitor (); + bool AllowVisit (const MeshFacet& face, const MeshFacet&, + unsigned long, unsigned long, unsigned short neighbourIndex); + bool Visit (const MeshFacet & face, const MeshFacet &, + unsigned long ulFInd, unsigned long); + +protected: + std::vector &indices; + const MeshSurfaceSegment& segm; +}; + +class MeshExport MeshSegmentAlgorithm +{ +public: + MeshSegmentAlgorithm(const MeshKernel& kernel) : myKernel(kernel) {} + void FindSegments(std::vector&); + +private: + const MeshKernel& myKernel; +}; + +} // MeshCore + +#endif // MESHCORE_SEGMENTATION_H diff --git a/src/Mod/Mesh/App/FeatureMeshCurvature.cpp b/src/Mod/Mesh/App/FeatureMeshCurvature.cpp index f618f2dea..f7bc01205 100644 --- a/src/Mod/Mesh/App/FeatureMeshCurvature.cpp +++ b/src/Mod/Mesh/App/FeatureMeshCurvature.cpp @@ -29,18 +29,16 @@ #include #include #include -#include -#include #include "FeatureMeshCurvature.h" #include "MeshFeature.h" +#include "Core/Curvature.h" #include "Core/Elements.h" #include "Core/Iterator.h" using namespace Mesh; -using namespace MeshCore; PROPERTY_SOURCE(Mesh::Curvature, App::DocumentObject) @@ -68,42 +66,20 @@ App::DocumentObjectExecReturn *Curvature::execute(void) } // get all points - const MeshKernel& rMesh = pcFeat->Mesh.getValue().getKernel(); - std::vector< Wm4::Vector3 > aPnts; - aPnts.reserve(rMesh.CountPoints()); - MeshPointIterator cPIt( rMesh ); - for (cPIt.Init(); cPIt.More(); cPIt.Next()) { - Wm4::Vector3 cP(cPIt->x, cPIt->y, cPIt->z); - aPnts.push_back(cP); - } + const MeshCore::MeshKernel& rMesh = pcFeat->Mesh.getValue().getKernel(); + MeshCore::MeshCurvature meshCurv(rMesh); + meshCurv.ComputePerVertex(); + const std::vector& curv = meshCurv.GetCurvature(); - // get all point connections - std::vector aIdx; - aIdx.reserve(3*rMesh.CountFacets()); - const std::vector& raFts = rMesh.GetFacets(); - for (std::vector::const_iterator jt = raFts.begin(); jt != raFts.end(); ++jt) { - for (int i=0; i<3; i++) { - aIdx.push_back((int)jt->_aulPoints[i]); - } - } - - // compute vertex based curvatures - Wm4::MeshCurvature meshCurv(rMesh.CountPoints(), &(aPnts[0]), rMesh.CountFacets(), &(aIdx[0])); - - // get curvature information now - const Wm4::Vector3* aMaxCurvDir = meshCurv.GetMaxDirections(); - const Wm4::Vector3* aMinCurvDir = meshCurv.GetMinDirections(); - const float* aMaxCurv = meshCurv.GetMaxCurvatures(); - const float* aMinCurv = meshCurv.GetMinCurvatures(); - - std::vector values(rMesh.CountPoints()); - for (unsigned long i=0; i values; + values.reserve(curv.size()); + for (std::vector::const_iterator it = curv.begin(); it != curv.end(); ++it) { CurvatureInfo ci; - ci.cMaxCurvDir = Base::Vector3f(aMaxCurvDir[i].X(), aMaxCurvDir[i].Y(), aMaxCurvDir[i].Z()); - ci.cMinCurvDir = Base::Vector3f(aMinCurvDir[i].X(), aMinCurvDir[i].Y(), aMinCurvDir[i].Z()); - ci.fMaxCurvature = aMaxCurv[i]; - ci.fMinCurvature = aMinCurv[i]; - values[i] = ci; + ci.cMaxCurvDir = it->cMaxCurvDir; + ci.cMinCurvDir = it->cMinCurvDir; + ci.fMaxCurvature = it->fMaxCurvature; + ci.fMinCurvature = it->fMinCurvature; + values.push_back(ci); } CurvInfo.setValues(values); diff --git a/src/Mod/Mesh/App/Makefile.am b/src/Mod/Mesh/App/Makefile.am index 6309f0d91..27537e060 100644 --- a/src/Mod/Mesh/App/Makefile.am +++ b/src/Mod/Mesh/App/Makefile.am @@ -22,6 +22,8 @@ libMesh_la_SOURCES=\ Core/Approximation.h \ Core/Builder.cpp \ Core/Builder.h \ + Core/Curvature.cpp \ + Core/Curvature.h \ Core/Definitions.cpp \ Core/Definitions.h \ Core/Degeneration.cpp \ @@ -42,6 +44,8 @@ libMesh_la_SOURCES=\ Core/MeshIO.h \ Core/Projection.cpp \ Core/Projection.h \ + Core/Segmentation.cpp \ + Core/Segmentation.h \ Core/SetOperations.cpp \ Core/SetOperations.h \ Core/Smoothing.cpp \ @@ -324,9 +328,9 @@ nobase_include_HEADERS = \ # the library search path. -libMesh_la_LDFLAGS = -L../../../Base -L../../../App $(all_libraries) $(GTS_LIBS) \ +libMesh_la_LDFLAGS = -L../../../Base -L../../../App $(QT4_CORE_LIBS) $(all_libraries) $(GTS_LIBS) \ -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ -libMesh_la_CPPFLAGS = -DMeshExport= +libMesh_la_CPPFLAGS = -DMeshExport= -DEIGEN2_SUPPORT libMesh_la_LIBADD = \ @BOOST_FILESYSTEM_LIB@ @BOOST_REGEX_LIB@ @BOOST_SYSTEM_LIB@ \ @@ -354,7 +358,8 @@ Mesh_la_DEPENDENCIES = libMesh.la #-------------------------------------------------------------------------------------- # set the include path found by configure -AM_CXXFLAGS = -I$(top_srcdir)/src/3rdParty -I$(top_srcdir)/src -I$(top_builddir)/src $(GTS_CFLAGS) $(all_includes) +AM_CXXFLAGS = -I$(top_srcdir)/src/3rdParty -I$(top_srcdir)/src -I$(top_builddir)/src $(GTS_CFLAGS) \ + $(all_includes) $(QT4_CORE_CXXFLAGS) includedir = @includedir@/Mod/Mesh/App libdir = $(prefix)/Mod/Mesh diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index bd7be06d0..89f85856a 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -1422,10 +1422,11 @@ MeshObject* MeshObject::meshFromSegment(const std::vector& indice return new MeshObject(kernel, _Mtrx); } -std::vector MeshObject::getSegmentsFromType(MeshObject::Type type, const Segment& aSegment, float dev) const +std::vector MeshObject::getSegmentsFromType(MeshObject::Type type, const Segment& aSegment, + float dev, unsigned long minFacets) const { std::vector segm; - unsigned long startFacet, visited; + unsigned long startFacet; if (this->_kernel.CountFacets() == 0) return segm; @@ -1445,7 +1446,7 @@ std::vector MeshObject::getSegmentsFromType(MeshObject::Type type, cons MeshCore::MeshFacetArray::_TConstIterator iEnd = rFAry.end(); // start from the first not visited facet - visited = cAlgo.CountFacetFlag(MeshCore::MeshFacet::VISIT); + cAlgo.CountFacetFlag(MeshCore::MeshFacet::VISIT); iTri = std::find_if(iTri, iEnd, std::bind2nd(MeshCore::MeshIsNotFlag(), MeshCore::MeshFacet::VISIT)); startFacet = iTri - iBeg; @@ -1455,7 +1456,7 @@ std::vector MeshObject::getSegmentsFromType(MeshObject::Type type, cons std::vector indices; indices.push_back(startFacet); MeshCore::MeshPlaneVisitor pv(this->_kernel, startFacet, dev, indices); - visited += this->_kernel.VisitNeighbourFacets(pv, startFacet); + this->_kernel.VisitNeighbourFacets(pv, startFacet); iTri = std::find_if(iTri, iEnd, std::bind2nd(MeshCore::MeshIsNotFlag(), MeshCore::MeshFacet::VISIT)); @@ -1463,7 +1464,8 @@ std::vector MeshObject::getSegmentsFromType(MeshObject::Type type, cons startFacet = iTri - iBeg; else startFacet = ULONG_MAX; - segm.push_back(Segment(const_cast(this), indices, false)); + if (indices.size() > minFacets) + segm.push_back(Segment(const_cast(this), indices, false)); } return segm; diff --git a/src/Mod/Mesh/App/Mesh.h b/src/Mod/Mesh/App/Mesh.h index dcd1ca19d..3d884517f 100644 --- a/src/Mod/Mesh/App/Mesh.h +++ b/src/Mod/Mesh/App/Mesh.h @@ -266,7 +266,7 @@ public: const Segment& getSegment(unsigned long) const; Segment& getSegment(unsigned long); MeshObject* meshFromSegment(const std::vector&) const; - std::vector getSegmentsFromType(Type, const Segment& aSegment, float dev) const; + std::vector getSegmentsFromType(Type, const Segment& aSegment, float dev, unsigned long minFacets) const; //@} /** @name Primitives */ diff --git a/src/Mod/Mesh/App/MeshPy.xml b/src/Mod/Mesh/App/MeshPy.xml index 6070d9fc1..f29a59730 100644 --- a/src/Mod/Mesh/App/MeshPy.xml +++ b/src/Mod/Mesh/App/MeshPy.xml @@ -370,13 +370,26 @@ an empty dictionary if there is no intersection. - + - Get all planes of the mesh as segment. + getPlanarSegments(dev,[min faces=0]) -> list +Get all planes of the mesh as segment. In the worst case each triangle can be regarded as single plane if none of its neighours is coplanar. + + + getSegmentsByCurvature(list) -> list +The argument list gives a list if tuples where it defines the preferred maximum curvature, +the preferred minumum curvature, the tolerance and the number of minimum faces for the segment. +Example: +c=(1.0, 0.0, 0.1, 500) # search for a cylinder with radius 1.0 +p=(0.0, 0.0, 0.1, 500) # search for a plane +mesh.getSegmentsByCurvature([c,p]) + + + A collection of the mesh points diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp index 143ff61f9..1e32bf2f3 100644 --- a/src/Mod/Mesh/App/MeshPyImp.cpp +++ b/src/Mod/Mesh/App/MeshPyImp.cpp @@ -41,6 +41,8 @@ #include "Core/Grid.h" #include "Core/MeshKernel.h" #include "Core/Triangulation.h" +#include "Core/Segmentation.h" +#include "Core/Curvature.h" using namespace Mesh; @@ -1356,15 +1358,16 @@ PyObject* MeshPy::nearestFacetOnRay(PyObject *args) } } -PyObject* MeshPy::getPlanes(PyObject *args) +PyObject* MeshPy::getPlanarSegments(PyObject *args) { float dev; - if (!PyArg_ParseTuple(args, "f",&dev)) + unsigned long minFacets=0; + if (!PyArg_ParseTuple(args, "f|k",&dev,&minFacets)) return NULL; Mesh::MeshObject* mesh = getMeshObjectPtr(); std::vector segments = mesh->getSegmentsFromType - (Mesh::MeshObject::PLANE, Mesh::Segment(mesh,false), dev); + (Mesh::MeshObject::PLANE, Mesh::Segment(mesh,false), dev, minFacets); Py::List s; for (std::vector::iterator it = segments.begin(); it != segments.end(); ++it) { @@ -1379,6 +1382,48 @@ PyObject* MeshPy::getPlanes(PyObject *args) return Py::new_reference_to(s); } +PyObject* MeshPy::getSegmentsByCurvature(PyObject *args) +{ + PyObject* l; + if (!PyArg_ParseTuple(args, "O!",&PyList_Type,&l)) + return NULL; + + const MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); + MeshCore::MeshSegmentAlgorithm finder(kernel); + MeshCore::MeshCurvature meshCurv(kernel); + meshCurv.ComputePerVertex(); + + Py::List func(l); + std::vector segm; + //segm.push_back(new MeshCore::MeshCurvatureCylindricalSegment(meshCurv.GetCurvature(), minFacets, dev, 4.75f)); + //segm.push_back(new MeshCore::MeshCurvaturePlanarSegment(meshCurv.GetCurvature(), minFacets, dev)); + for (Py::List::iterator it = func.begin(); it != func.end(); ++it) { + Py::Tuple t(*it); + float c1 = (float)Py::Float(t[0]); + float c2 = (float)Py::Float(t[1]); + float tol = (float)Py::Float(t[2]); + int num = (int)Py::Int(t[3]); + segm.push_back(new MeshCore::MeshCurvatureFreeformSegment(meshCurv.GetCurvature(), num, tol, c1, c2)); + } + + finder.FindSegments(segm); + + Py::List list; + for (std::vector::iterator segmIt = segm.begin(); segmIt != segm.end(); ++segmIt) { + std::vector data = (*segmIt)->GetSegments(); + delete (*segmIt); + for (std::vector::iterator it = data.begin(); it != data.end(); ++it) { + Py::List ary; + for (MeshCore::MeshSegment::const_iterator jt = it->begin(); jt != it->end(); ++jt) { + ary.append(Py::Int((int)*jt)); + } + list.append(ary); + } + } + + return Py::new_reference_to(list); +} + Py::Int MeshPy::getCountPoints(void) const { return Py::Int((long)getMeshObjectPtr()->countPoints()); From 8c3b83a451d152547988c61c346ea999b01068ba Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 18 May 2012 01:40:05 +0200 Subject: [PATCH 10/42] Mesh segmentation --- src/Mod/Mesh/App/Core/Segmentation.cpp | 6 +++--- src/Mod/Mesh/App/Core/Segmentation.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mod/Mesh/App/Core/Segmentation.cpp b/src/Mod/Mesh/App/Core/Segmentation.cpp index 4326457e5..450a7a067 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.cpp +++ b/src/Mod/Mesh/App/Core/Segmentation.cpp @@ -31,7 +31,7 @@ using namespace MeshCore; -void MeshSurfaceSegment::PrepareFacet(unsigned long) +void MeshSurfaceSegment::Initialize(unsigned long) { } @@ -54,7 +54,7 @@ MeshDistancePlanarSegment::~MeshDistancePlanarSegment() delete fitter; } -void MeshDistancePlanarSegment::PrepareFacet(unsigned long index) +void MeshDistancePlanarSegment::Initialize(unsigned long index) { fitter->Clear(); @@ -204,7 +204,7 @@ void MeshSegmentAlgorithm::FindSegments(std::vector& segm) // collect all facets of the same geometry std::vector indices; indices.push_back(startFacet); - (*it)->PrepareFacet(startFacet); + (*it)->Initialize(startFacet); MeshSurfaceVisitor pv(**it, indices); myKernel.VisitNeighbourFacets(pv, startFacet); diff --git a/src/Mod/Mesh/App/Core/Segmentation.h b/src/Mod/Mesh/App/Core/Segmentation.h index e45ecff4c..07e9fa9ca 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.h +++ b/src/Mod/Mesh/App/Core/Segmentation.h @@ -41,7 +41,7 @@ public: : minFacets(minFacets) {} virtual ~MeshSurfaceSegment() {} virtual bool TestFacet (const MeshFacet &rclFacet) const = 0; - virtual void PrepareFacet(unsigned long); + virtual void Initialize(unsigned long); void AddSegment(const std::vector&); const std::vector GetSegments() const { return segments; } @@ -69,7 +69,7 @@ public: MeshDistancePlanarSegment(const MeshKernel& mesh, unsigned long minFacets, float tol); virtual ~MeshDistancePlanarSegment(); bool TestFacet (const MeshFacet &rclFacet) const; - void PrepareFacet(unsigned long); + void Initialize(unsigned long); protected: Base::Vector3f basepoint; From 26a06cc91a737389ac2bad44a6dae12fabeee1d4 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 18 May 2012 15:57:32 +0200 Subject: [PATCH 11/42] Mesh segmentation --- src/Mod/Complete/Gui/Workbench.cpp | 1 + src/Mod/Mesh/App/Core/Segmentation.h | 2 +- src/Mod/Mesh/App/FeatureMeshSegmentByMesh.h | 6 +- src/Mod/Mesh/App/MeshPyImp.cpp | 8 +- src/Mod/Mesh/Gui/CMakeLists.txt | 4 + src/Mod/Mesh/Gui/Command.cpp | 35 +++ src/Mod/Mesh/Gui/Makefile.am | 2 + src/Mod/Mesh/Gui/Segmentation.cpp | 136 ++++++++++++ src/Mod/Mesh/Gui/Segmentation.h | 74 +++++++ src/Mod/Mesh/Gui/Segmentation.ui | 227 ++++++++++++++++++++ src/Mod/Mesh/Gui/Workbench.cpp | 3 +- 11 files changed, 488 insertions(+), 10 deletions(-) create mode 100644 src/Mod/Mesh/Gui/Segmentation.cpp create mode 100644 src/Mod/Mesh/Gui/Segmentation.h create mode 100644 src/Mod/Mesh/Gui/Segmentation.ui diff --git a/src/Mod/Complete/Gui/Workbench.cpp b/src/Mod/Complete/Gui/Workbench.cpp index d60424b2d..9b0b0fcf0 100644 --- a/src/Mod/Complete/Gui/Workbench.cpp +++ b/src/Mod/Complete/Gui/Workbench.cpp @@ -229,6 +229,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Mesh_PolySplit" << "Mesh_PolySegm" << "Mesh_ToolMesh" + << "Mesh_Segmentation" << "Mesh_VertexCurvature"; // Part **************************************************************************************************** diff --git a/src/Mod/Mesh/App/Core/Segmentation.h b/src/Mod/Mesh/App/Core/Segmentation.h index 07e9fa9ca..021961001 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.h +++ b/src/Mod/Mesh/App/Core/Segmentation.h @@ -43,7 +43,7 @@ public: virtual bool TestFacet (const MeshFacet &rclFacet) const = 0; virtual void Initialize(unsigned long); void AddSegment(const std::vector&); - const std::vector GetSegments() const { return segments; } + const std::vector& GetSegments() const { return segments; } protected: std::vector segments; diff --git a/src/Mod/Mesh/App/FeatureMeshSegmentByMesh.h b/src/Mod/Mesh/App/FeatureMeshSegmentByMesh.h index 16f6e1a57..76c51c54b 100644 --- a/src/Mod/Mesh/App/FeatureMeshSegmentByMesh.h +++ b/src/Mod/Mesh/App/FeatureMeshSegmentByMesh.h @@ -21,8 +21,8 @@ ***************************************************************************/ -#ifndef FEATURE_MESH_SEGMENT_H -#define FEATURE_MESH_SEGMENT_H +#ifndef FEATURE_MESH_SEGMENTBYMESH_H +#define FEATURE_MESH_SEGMENTBYMESH_H #include @@ -63,4 +63,4 @@ public: } -#endif // FEATURE_MESH_SEGMENT_H +#endif // FEATURE_MESH_SEGMENTBYMESH_H diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp index 1e32bf2f3..dd1f0e3e1 100644 --- a/src/Mod/Mesh/App/MeshPyImp.cpp +++ b/src/Mod/Mesh/App/MeshPyImp.cpp @@ -1395,8 +1395,6 @@ PyObject* MeshPy::getSegmentsByCurvature(PyObject *args) Py::List func(l); std::vector segm; - //segm.push_back(new MeshCore::MeshCurvatureCylindricalSegment(meshCurv.GetCurvature(), minFacets, dev, 4.75f)); - //segm.push_back(new MeshCore::MeshCurvaturePlanarSegment(meshCurv.GetCurvature(), minFacets, dev)); for (Py::List::iterator it = func.begin(); it != func.end(); ++it) { Py::Tuple t(*it); float c1 = (float)Py::Float(t[0]); @@ -1410,15 +1408,15 @@ PyObject* MeshPy::getSegmentsByCurvature(PyObject *args) Py::List list; for (std::vector::iterator segmIt = segm.begin(); segmIt != segm.end(); ++segmIt) { - std::vector data = (*segmIt)->GetSegments(); - delete (*segmIt); - for (std::vector::iterator it = data.begin(); it != data.end(); ++it) { + const std::vector& data = (*segmIt)->GetSegments(); + for (std::vector::const_iterator it = data.begin(); it != data.end(); ++it) { Py::List ary; for (MeshCore::MeshSegment::const_iterator jt = it->begin(); jt != it->end(); ++jt) { ary.append(Py::Int((int)*jt)); } list.append(ary); } + delete (*segmIt); } return Py::new_reference_to(list); diff --git a/src/Mod/Mesh/Gui/CMakeLists.txt b/src/Mod/Mesh/Gui/CMakeLists.txt index 9941cac13..ae4701a0f 100644 --- a/src/Mod/Mesh/Gui/CMakeLists.txt +++ b/src/Mod/Mesh/Gui/CMakeLists.txt @@ -34,6 +34,7 @@ set(Dialogs_UIC_SRCS DlgSettingsMeshView.ui DlgSmoothing.ui RemoveComponents.ui + Segmentation.ui ) qt4_wrap_ui(Dialogs_UIC_HDRS ${Dialogs_UIC_SRCS}) SET(Dialogs_SRCS @@ -53,6 +54,9 @@ SET(Dialogs_SRCS RemoveComponents.ui RemoveComponents.cpp RemoveComponents.h + Segmentation.ui + Segmentation.cpp + Segmentation.h ) SOURCE_GROUP("Dialogs" FILES ${Dialogs_SRCS}) diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp index 03d971474..cc83bdaa0 100644 --- a/src/Mod/Mesh/Gui/Command.cpp +++ b/src/Mod/Mesh/Gui/Command.cpp @@ -69,6 +69,7 @@ #include "ViewProviderMeshFaceSet.h" #include "ViewProviderCurvature.h" #include "MeshEditor.h" +#include "Segmentation.h" using namespace Mesh; @@ -1368,6 +1369,39 @@ bool CmdMeshFillInteractiveHole::isActive(void) return false; } +DEF_STD_CMD_A(CmdMeshSegmentation); + +CmdMeshSegmentation::CmdMeshSegmentation() + : Command("Mesh_Segmentation") +{ + sAppModule = "Mesh"; + sGroup = QT_TR_NOOP("Mesh"); + sMenuText = QT_TR_NOOP("Create mesh segments..."); + sToolTipText = QT_TR_NOOP("Create mesh segments"); + sWhatsThis = "Mesh_Segmentation"; + sStatusTip = QT_TR_NOOP("Create mesh segments"); +} + +void CmdMeshSegmentation::activated(int iMsg) +{ + std::vector objs = Gui::Selection().getObjectsOfType + (Mesh::Feature::getClassTypeId()); + Mesh::Feature* mesh = static_cast(objs.front()); + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + if (!dlg) { + dlg = new MeshGui::TaskSegmentation(mesh); + } + Gui::Control().showDialog(dlg); +} + +bool CmdMeshSegmentation::isActive(void) +{ + if (Gui::Control().activeDialog()) + return false; + return Gui::Selection().countObjectsOfType + (Mesh::Feature::getClassTypeId()) == 1; +} + void CreateMeshCommands(void) { Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); @@ -1400,4 +1434,5 @@ void CreateMeshCommands(void) rcCmdMgr.addCommand(new CmdMeshFillInteractiveHole()); rcCmdMgr.addCommand(new CmdMeshRemoveCompByHand()); rcCmdMgr.addCommand(new CmdMeshFromGeometry()); + rcCmdMgr.addCommand(new CmdMeshSegmentation()); } diff --git a/src/Mod/Mesh/Gui/Makefile.am b/src/Mod/Mesh/Gui/Makefile.am index 6b2066ff0..46158d1e1 100644 --- a/src/Mod/Mesh/Gui/Makefile.am +++ b/src/Mod/Mesh/Gui/Makefile.am @@ -7,6 +7,7 @@ BUILT_SOURCES=\ ui_DlgSettingsMeshView.h \ ui_DlgSmoothing.h \ ui_RemoveComponents.h \ + ui_Segmentation.h \ moc_DlgEvaluateMeshImp.cpp \ moc_DlgRegularSolidImp.cpp \ moc_DlgSettingsMeshView.cpp \ @@ -127,6 +128,7 @@ EXTRA_DIST = \ DlgSettingsMeshView.ui \ DlgSmoothing.ui \ RemoveComponents.ui \ + Segmentation.ui \ Resources/Mesh.qrc \ Resources/translations/Mesh_af.qm \ Resources/translations/Mesh_af.ts \ diff --git a/src/Mod/Mesh/Gui/Segmentation.cpp b/src/Mod/Mesh/Gui/Segmentation.cpp new file mode 100644 index 000000000..962d65f2e --- /dev/null +++ b/src/Mod/Mesh/Gui/Segmentation.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#endif + +#include "Segmentation.h" +#include "ui_Segmentation.h" +#include +#include + +#include +#include +#include +#include +#include + +using namespace MeshGui; + +Segmentation::Segmentation(Mesh::Feature* mesh, QWidget* parent, Qt::WFlags fl) + : QWidget(parent, fl), myMesh(mesh) +{ + ui = new Ui_Segmentation; + ui->setupUi(this); + ui->numPln->setRange(1, INT_MAX); + ui->numPln->setValue(100); + ui->numCyl->setRange(1, INT_MAX); + ui->numCyl->setValue(100); + ui->numSph->setRange(1, INT_MAX); + ui->numSph->setValue(100); +} + +Segmentation::~Segmentation() +{ + // no need to delete child widgets, Qt does it all for us + delete ui; +} + +void Segmentation::accept() +{ + const Mesh::MeshObject* mesh = myMesh->Mesh.getValuePtr(); + // make a copy because we might smooth the mesh before + MeshCore::MeshKernel kernel = mesh->getKernel(); + + if (ui->checkBoxSmooth->isChecked()) { + MeshCore::LaplaceSmoothing smoother(kernel); + smoother.Smooth(ui->smoothSteps->value()); + } + + MeshCore::MeshSegmentAlgorithm finder(kernel); + MeshCore::MeshCurvature meshCurv(kernel); + meshCurv.ComputePerVertex(); + + std::vector segm; + if (ui->groupBoxCyl->isChecked()) { + segm.push_back(new MeshCore::MeshCurvatureCylindricalSegment + (meshCurv.GetCurvature(), ui->numCyl->value(), ui->tolCyl->value(), ui->radCyl->value())); + } + if (ui->groupBoxSph->isChecked()) { + segm.push_back(new MeshCore::MeshCurvatureSphericalSegment + (meshCurv.GetCurvature(), ui->numSph->value(), ui->tolSph->value(), ui->radSph->value())); + } + if (ui->groupBoxPln->isChecked()) { + segm.push_back(new MeshCore::MeshCurvaturePlanarSegment + (meshCurv.GetCurvature(), ui->numPln->value(), ui->tolPln->value())); + } + finder.FindSegments(segm); + + App::Document* document = App::GetApplication().getActiveDocument(); + for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { + const std::vector& data = (*it)->GetSegments(); + for (std::vector::const_iterator jt = data.begin(); jt != data.end(); ++jt) { + Mesh::MeshObject* segment = mesh->meshFromSegment(*jt); + Mesh::Feature* feaSegm = static_cast(document->addObject("Mesh::Feature", "Segment")); + Mesh::MeshObject* feaMesh = feaSegm->Mesh.startEditing(); + feaMesh->swap(*segment); + feaSegm->Mesh.finishEditing(); + delete segment; + } + delete (*it); + } +} + +void Segmentation::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } + QWidget::changeEvent(e); +} + +// --------------------------------------- + +/* TRANSLATOR MeshGui::TaskRemoveComponents */ + +TaskSegmentation::TaskSegmentation(Mesh::Feature* mesh) +{ + widget = new Segmentation(mesh); + taskbox = new Gui::TaskView::TaskBox( + QPixmap(), widget->windowTitle(), false, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskSegmentation::~TaskSegmentation() +{ + // automatically deleted in the sub-class +} + +bool TaskSegmentation::accept() +{ + widget->accept(); + return true; +} diff --git a/src/Mod/Mesh/Gui/Segmentation.h b/src/Mod/Mesh/Gui/Segmentation.h new file mode 100644 index 000000000..95d141163 --- /dev/null +++ b/src/Mod/Mesh/Gui/Segmentation.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef MESHGUI_SEGMENTATION_H +#define MESHGUI_SEGMENTATION_H + +#include +#include +#include + +// forward declarations +namespace Mesh { class Feature; } + +namespace MeshGui { +class Ui_Segmentation; + +class MeshGuiExport Segmentation : public QWidget +{ +public: + Segmentation(Mesh::Feature* mesh, QWidget* parent = 0, Qt::WFlags fl = 0); + ~Segmentation(); + void accept(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui_Segmentation* ui; + Mesh::Feature* myMesh; +}; + +/** + * Embed the panel into a task dialog. + */ +class TaskSegmentation : public Gui::TaskView::TaskDialog +{ +public: + TaskSegmentation(Mesh::Feature* mesh); + ~TaskSegmentation(); + +public: + bool accept(); + + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; } + +private: + Segmentation* widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} + +#endif // MESHGUI_SEGMENTATION_H diff --git a/src/Mod/Mesh/Gui/Segmentation.ui b/src/Mod/Mesh/Gui/Segmentation.ui new file mode 100644 index 000000000..129c89873 --- /dev/null +++ b/src/Mod/Mesh/Gui/Segmentation.ui @@ -0,0 +1,227 @@ + + + MeshGui::Segmentation + + + + 0 + 0 + 289 + 379 + + + + Mesh segmentation + + + + + + Smooth mesh + + + true + + + + + + + 3 + + + + + + + Plane + + + true + + + + + + Tolerance + + + + + + + 0.100000000000000 + + + 0.100000000000000 + + + + + + + Minumum number of faces + + + + + + + 100000 + + + 100 + + + + + + + + + + Cylinder + + + true + + + + + + Radius + + + + + + + 0.100000000000000 + + + 5.000000000000000 + + + + + + + Tolerance + + + + + + + 0.100000000000000 + + + 0.100000000000000 + + + + + + + Minimum number of faces + + + + + + + 100000 + + + 100 + + + + + + + + + + Sphere + + + true + + + + + + Radius + + + + + + + 0.100000000000000 + + + 5.000000000000000 + + + + + + + Tolerance + + + + + + + 0.100000000000000 + + + 0.100000000000000 + + + + + + + Minimum number of faces + + + + + + + 100000 + + + 100 + + + + + + + + + + + + checkBoxSmooth + toggled(bool) + smoothSteps + setEnabled(bool) + + + 75 + 24 + + + 188 + 19 + + + + + diff --git a/src/Mod/Mesh/Gui/Workbench.cpp b/src/Mod/Mesh/Gui/Workbench.cpp index a2a3fa087..25b9bd656 100644 --- a/src/Mod/Mesh/Gui/Workbench.cpp +++ b/src/Mod/Mesh/Gui/Workbench.cpp @@ -190,7 +190,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Mesh_FillupHoles" << "Mesh_FillInteractiveHole" << "Mesh_RemoveComponents" << "Mesh_RemoveCompByHand" << "Mesh_AddFacet" << "Mesh_Smoothing" << "Separator" << "Mesh_BuildRegularSolid" << boolean << "Separator" << "Mesh_PolySelect" << "Mesh_PolyCut" - << "Mesh_PolySplit" << "Mesh_PolySegm" << "Mesh_PolyTrim" << "Mesh_VertexCurvature"; + << "Mesh_PolySplit" << "Mesh_PolySegm" << "Mesh_PolyTrim" << "Mesh_Segmentation" + << "Mesh_VertexCurvature"; return root; } From 837ceccfc76cbe126713116e7e94c48c33b2685d Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 18 May 2012 12:57:48 -0300 Subject: [PATCH 12/42] Added 0000387 : Arch roof tool --- src/Mod/Arch/Arch.py | 1 + src/Mod/Arch/ArchRoof.py | 137 ++++ src/Mod/Arch/Arch_rc.py | 1014 +++++++++++++++++++----------- src/Mod/Arch/CMakeLists.txt | 1 + src/Mod/Arch/InitGui.py | 2 +- src/Mod/Arch/Makefile.am | 3 +- src/WindowsInstaller/ModArch.wxi | 1 + 7 files changed, 781 insertions(+), 378 deletions(-) create mode 100644 src/Mod/Arch/ArchRoof.py diff --git a/src/Mod/Arch/Arch.py b/src/Mod/Arch/Arch.py index 81bb29ffe..fc537d85a 100644 --- a/src/Mod/Arch/Arch.py +++ b/src/Mod/Arch/Arch.py @@ -39,3 +39,4 @@ from ArchCommands import * from ArchSectionPlane import * from ArchWindow import * from ArchAxis import * +from ArchRoof import * diff --git a/src/Mod/Arch/ArchRoof.py b/src/Mod/Arch/ArchRoof.py new file mode 100644 index 000000000..62850f243 --- /dev/null +++ b/src/Mod/Arch/ArchRoof.py @@ -0,0 +1,137 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2012 * +#* Yorik van Havre * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* This program is distributed in the hope that it will be useful, * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +#* GNU Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * +#* License along with this program; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#*************************************************************************** + +import FreeCAD,FreeCADGui,Draft,ArchComponent +from draftlibs import fcvec +from FreeCAD import Vector +from PyQt4 import QtCore + +__title__="FreeCAD Roof" +__author__ = "Yorik van Havre" +__url__ = "http://free-cad.sourceforge.net" + +def makeRoof(baseobj,facenr=1,angle=45,name="Roof"): + '''makeRoof(baseobj,[facenr],[angle],[name]) : Makes a roof based on a + face from an existing object. You can provide the number of the face + to build the roof on (default = 1), the angle (default=45) and a name (default + = roof).''' + obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) + _Roof(obj) + _ViewProviderRoof(obj.ViewObject) + obj.Base = baseobj + obj.Face = facenr + obj.Angle = angle + return obj + +class _CommandRoof: + "the Arch Roof command definition" + def GetResources(self): + return {'Pixmap' : 'Arch_Roof', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Roof","Roof"), + 'Accel': "R, F", + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Roof","Creates a roof object from the selected face of an object")} + + def IsActive(self): + if FreeCADGui.Selection.getSelection(): + return True + else: + return False + + def Activated(self): + sel = FreeCADGui.Selection.getSelectionEx() + if sel: + sel = sel[0] + if sel.HasSubObjects: + if "Face" in sel.SubElementNames[0]: + obj = sel.Object + idx = int(sel.SubElementNames[0][4:]) + FreeCAD.ActiveDocument.openTransaction("Create Roof") + makeRoof(obj,idx) + FreeCAD.ActiveDocument.commitTransaction() + +class _Roof(ArchComponent.Component): + "The Roof object" + def __init__(self,obj): + ArchComponent.Component.__init__(self,obj) + obj.addProperty("App::PropertyAngle","Angle","Base", + "The angle of this roof") + obj.addProperty("App::PropertyInteger","Face","Base", + "The face number of the base object used to build this roof") + obj.addProperty("App::PropertyLink","Base","Base", + "The base object this roof is built on") + self.Type = "Structure" + + def execute(self,obj): + self.createGeometry(obj) + + def onChanged(self,obj,prop): + if prop in ["Base","Face","Angle","Additions","Subtractions"]: + self.createGeometry(obj) + + def createGeometry(self,obj): + import Part,math + from draftlibs import fcgeo + pl = obj.Placement + + if obj.Base and obj.Face and obj.Angle: + if len(obj.Base.Shape.Faces) >= obj.Face: + f = obj.Base.Shape.Faces[obj.Face-1] + if len(f.Wires) == 1: + if f.Wires[0].isClosed(): + c = round(math.tan(math.radians(obj.Angle)),Draft.precision()) + norm = f.normalAt(0,0) + d = f.BoundBox.DiagonalLength + edges = fcgeo.sortEdges(f.Edges) + l = len(edges) + edges.append(edges[0]) + shps = [] + for i in range(l): + v = fcgeo.vec(fcgeo.angleBisection(edges[i],edges[i+1])) + v.normalize() + bis = v.getAngle(fcgeo.vec(edges[i])) + delta = 1/math.cos(bis) + v.multiply(delta) + n = (FreeCAD.Vector(norm)).multiply(c) + dv = v.add(n) + dv.normalize() + dv.scale(d,d,d) + shps.append(f.extrude(dv)) + c = shps.pop() + for s in shps: + c = c.common(s) + c = c.removeSplitter() + if not c.isNull(): + obj.Shape = c + if not fcgeo.isNull(pl): + obj.Placement = pl + +class _ViewProviderRoof(ArchComponent.ViewProviderComponent): + "A View Provider for the Roof object" + + def __init__(self,vobj): + ArchComponent.ViewProviderComponent.__init__(self,vobj) + + def getIcon(self): + return ":/icons/Arch_Roof_Tree.svg" + +FreeCADGui.addCommand('Arch_Roof',_CommandRoof()) diff --git a/src/Mod/Arch/Arch_rc.py b/src/Mod/Arch/Arch_rc.py index cfb5796f4..6e7f3870a 100644 --- a/src/Mod/Arch/Arch_rc.py +++ b/src/Mod/Arch/Arch_rc.py @@ -2,8 +2,8 @@ # Resource object code # -# Created: Wed Apr 18 19:00:26 2012 -# by: The Resource Compiler for PyQt (Qt v4.7.4) +# Created: Sun May 13 20:45:11 2012 +# by: The Resource Compiler for PyQt (Qt v4.8.1) # # WARNING! All changes made in this file will be lost! @@ -6791,7 +6791,7 @@ qt_resource_data = "\ \x60\x24\x14\x71\x18\x20\xc8\x29\x21\x64\x0a\xba\x54\x4c\x69\x8a\ \x07\xa3\xfe\x50\x76\x18\x1a\x6f\x00\x69\x8d\xda\xda\x66\xb6\xba\ \xbe\xb8\xb2\x35\xc7\xf5\xc5\x7f\x01\x9a\x79\xce\xaf\ -\x00\x00\x12\x5a\ +\x00\x00\x12\x5c\ \x3c\ \x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ \x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\ @@ -6831,173 +6831,233 @@ qt_resource_data = "\ \x78\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x32\x39\x38\ \x35\x22\x0a\x20\x20\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\ \x2e\x31\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ -\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x31\x20\ -\x72\x39\x37\x36\x30\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\ -\x64\x69\x3a\x64\x6f\x63\x6e\x61\x6d\x65\x3d\x22\x41\x72\x63\x68\ -\x5f\x53\x69\x74\x65\x2e\x73\x76\x67\x22\x3e\x0a\x20\x20\x3c\x64\ -\x65\x66\x73\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\ -\x73\x32\x39\x38\x37\x22\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\ -\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\ -\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\ -\x64\x69\x65\x6e\x74\x33\x37\x39\x34\x22\x3e\x0a\x20\x20\x20\x20\ -\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\ -\x6f\x72\x3a\x23\x66\x66\x62\x34\x30\x30\x3b\x73\x74\x6f\x70\x2d\ -\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x30\x22\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\ -\x70\x33\x37\x39\x36\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ -\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\ -\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\ -\x3a\x23\x66\x66\x65\x61\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\ -\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\ -\x37\x39\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6c\x69\ -\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\x0a\x20\x20\ -\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\ -\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\ -\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x37\x39\x34\x2d\ -\x38\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\ -\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x62\x34\ -\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\ -\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\ -\x73\x65\x74\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x36\x2d\x35\x22\ -\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\ -\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x65\x61\ -\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\ -\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\ -\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x38\x2d\x38\x22\ -\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6c\x69\x6e\x65\x61\x72\ -\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\x0a\x20\x20\x20\x20\x3c\x6c\ -\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\ -\x20\x20\x20\x20\x20\x79\x32\x3d\x22\x32\x33\x2e\x38\x34\x38\x36\ -\x38\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x32\x3d\x22\x36\ -\x32\x2e\x36\x35\x32\x33\x37\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ -\x79\x31\x3d\x22\x32\x33\x2e\x38\x34\x38\x36\x38\x36\x22\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x78\x31\x3d\x22\x31\x35\x2e\x31\x38\x34\ -\x39\x37\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\ -\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\ -\x61\x74\x72\x69\x78\x28\x31\x2e\x30\x32\x36\x35\x35\x36\x38\x2c\ -\x30\x2c\x30\x2c\x30\x2e\x39\x31\x34\x39\x30\x36\x32\x36\x2c\x2d\ -\x33\x2e\x32\x33\x36\x37\x30\x36\x2c\x2d\x31\x2e\x38\x30\x32\x37\ -\x30\x33\x32\x29\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\ -\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\ -\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\ -\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\ -\x64\x69\x65\x6e\x74\x33\x38\x38\x36\x22\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x78\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\ -\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x37\x39\ -\x34\x2d\x38\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ -\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\ -\x77\x61\x79\x73\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\ -\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\ -\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\ -\x61\x64\x69\x65\x6e\x74\x33\x37\x39\x34\x2d\x31\x22\x3e\x0a\x20\ -\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\ -\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x62\x34\x30\x30\x3b\x73\x74\ -\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\ -\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ -\x73\x74\x6f\x70\x33\x37\x39\x36\x2d\x32\x22\x20\x2f\x3e\x0a\x20\ -\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\ -\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x65\x61\x30\x30\x3b\x73\x74\ -\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\ -\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ -\x73\x74\x6f\x70\x33\x37\x39\x38\x2d\x32\x22\x20\x2f\x3e\x0a\x20\ +\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x33\x2e\ +\x31\x20\x72\x39\x38\x38\x36\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\ +\x70\x6f\x64\x69\x3a\x64\x6f\x63\x6e\x61\x6d\x65\x3d\x22\x41\x72\ +\x63\x68\x5f\x53\x69\x74\x65\x5f\x54\x72\x65\x65\x2e\x73\x76\x67\ +\x22\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x0a\x20\x20\x20\x20\x20\ +\x69\x64\x3d\x22\x64\x65\x66\x73\x32\x39\x38\x37\x22\x3e\x0a\x20\ +\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\ +\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\ +\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x37\x39\x34\ +\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\ +\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x62\x34\x30\ +\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\ +\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\ +\x65\x74\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x36\x22\x20\x2f\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\ +\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x65\x61\x30\x30\x3b\ +\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\ +\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x38\x22\x20\x2f\x3e\x0a\x20\ \x20\x20\x20\x3c\x2f\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\ \x65\x6e\x74\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\ \x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\ -\x79\x32\x3d\x22\x32\x33\x2e\x38\x34\x38\x36\x38\x36\x22\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x78\x32\x3d\x22\x36\x32\x2e\x36\x35\x32\ -\x33\x37\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x79\x31\x3d\x22\x32\ -\x33\x2e\x38\x34\x38\x36\x38\x36\x22\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x78\x31\x3d\x22\x31\x35\x2e\x31\x38\x34\x39\x37\x31\x22\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x54\ -\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\ -\x28\x31\x2e\x30\x32\x36\x35\x35\x36\x38\x2c\x30\x2c\x30\x2c\x30\ -\x2e\x39\x31\x34\x39\x30\x36\x32\x36\x2c\x2d\x33\x2e\x32\x33\x36\ -\x37\x30\x36\x2c\x2d\x31\x2e\x38\x30\x32\x37\x30\x33\x32\x29\x22\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\ -\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\ -\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\ -\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\ -\x33\x38\x38\x36\x2d\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\ -\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\ -\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x37\x39\x34\x2d\x31\ -\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ -\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\ -\x73\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\ -\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\x65\ -\x64\x76\x69\x65\x77\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x62\ -\x61\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x70\x61\x67\x65\x63\x6f\ -\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\x66\x66\x66\x22\x0a\x20\x20\ -\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\ -\x23\x36\x36\x36\x36\x36\x36\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\ -\x72\x64\x65\x72\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x31\x2e\x30\ +\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\ +\x6e\x74\x33\x37\x39\x34\x2d\x38\x22\x3e\x0a\x20\x20\x20\x20\x20\ +\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\ +\x72\x3a\x23\x66\x66\x62\x34\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\ +\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x30\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\ +\x33\x37\x39\x36\x2d\x35\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\ +\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\ +\x72\x3a\x23\x66\x66\x65\x61\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\ +\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\ +\x33\x37\x39\x38\x2d\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\ +\x2f\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\ +\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\ +\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x79\x32\x3d\x22\ +\x32\x33\x2e\x38\x34\x38\x36\x38\x36\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x78\x32\x3d\x22\x36\x32\x2e\x36\x35\x32\x33\x37\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x79\x31\x3d\x22\x32\x33\x2e\x38\x34\ +\x38\x36\x38\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x31\x3d\ +\x22\x31\x35\x2e\x31\x38\x34\x39\x37\x31\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\ +\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x2e\x30\ +\x32\x36\x35\x35\x36\x38\x2c\x30\x2c\x30\x2c\x30\x2e\x39\x31\x34\ +\x39\x30\x36\x32\x36\x2c\x2d\x33\x2e\x32\x33\x36\x37\x30\x36\x2c\ +\x2d\x31\x2e\x38\x30\x32\x37\x30\x33\x32\x29\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\ +\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\ +\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\ +\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x38\x38\x36\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\x6b\x3a\x68\ +\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\ +\x69\x65\x6e\x74\x33\x37\x39\x34\x2d\x38\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\ +\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x20\x2f\x3e\x0a\ +\x20\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\ +\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\ +\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x37\x39\ +\x34\x2d\x31\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\ +\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\ +\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\ +\x62\x34\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\ +\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\ +\x66\x66\x73\x65\x74\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x36\x2d\ +\x32\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\ +\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\ +\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\ +\x65\x61\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\ +\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\ +\x66\x66\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x38\x2d\ +\x32\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6c\x69\x6e\x65\ +\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\x0a\x20\x20\x20\x20\ +\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x79\x32\x3d\x22\x32\x33\x2e\x38\x34\ +\x38\x36\x38\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x32\x3d\ +\x22\x36\x32\x2e\x36\x35\x32\x33\x37\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x79\x31\x3d\x22\x32\x33\x2e\x38\x34\x38\x36\x38\x36\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x31\x3d\x22\x31\x35\x2e\x31\ +\x38\x34\x39\x37\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\ +\x61\x64\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\ +\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x2e\x30\x32\x36\x35\x35\x36\ +\x38\x2c\x30\x2c\x30\x2c\x30\x2e\x39\x31\x34\x39\x30\x36\x32\x36\ +\x2c\x2d\x33\x2e\x32\x33\x36\x37\x30\x36\x2c\x2d\x31\x2e\x38\x30\ +\x32\x37\x30\x33\x32\x29\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\ +\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\ +\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\ +\x72\x61\x64\x69\x65\x6e\x74\x33\x38\x38\x36\x2d\x30\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\ +\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\ +\x74\x33\x37\x39\x34\x2d\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\ +\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x20\x2f\x3e\x0a\x20\x20\x3c\ +\x2f\x64\x65\x66\x73\x3e\x0a\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\ +\x64\x69\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\x20\x20\x20\ +\x20\x20\x69\x64\x3d\x22\x62\x61\x73\x65\x22\x0a\x20\x20\x20\x20\ +\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\ +\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\ +\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\x36\x36\x36\x22\x0a\ +\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\x61\x63\x69\ +\x74\x79\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\x70\x61\x63\x69\ +\x74\x79\x3d\x22\x30\x2e\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x73\x68\x61\x64\x6f\ +\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\x37\x2e\x37\x37\x38\x31\ +\x37\x34\x36\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x3a\x63\x78\x3d\x22\x32\x36\x2e\x34\x33\x31\x33\x36\x37\ \x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ -\x70\x61\x67\x65\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x30\x2e\x30\ -\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ -\x70\x61\x67\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\ -\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x7a\x6f\x6f\ -\x6d\x3d\x22\x32\x2e\x37\x35\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ -\x6b\x73\x63\x61\x70\x65\x3a\x63\x78\x3d\x22\x2d\x31\x32\x2e\x35\ -\x34\x31\x38\x31\x34\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ -\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\x32\x33\x2e\x38\x34\x36\x36\ -\x39\x34\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ -\x65\x3a\x63\x75\x72\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\ -\x22\x6c\x61\x79\x65\x72\x31\x22\x0a\x20\x20\x20\x20\x20\x73\x68\ -\x6f\x77\x67\x72\x69\x64\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\ -\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\ -\x6d\x65\x6e\x74\x2d\x75\x6e\x69\x74\x73\x3d\x22\x70\x78\x22\x0a\ -\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\ -\x69\x64\x2d\x62\x62\x6f\x78\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\ -\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\ -\x64\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x32\x38\x30\x22\ -\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\ -\x69\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x37\x35\ -\x38\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\ -\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x30\x22\x0a\x20\x20\ +\x63\x79\x3d\x22\x33\x30\x2e\x38\x30\x36\x36\x30\x38\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x75\x72\ +\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\x6c\x61\x79\x65\ +\x72\x31\x22\x0a\x20\x20\x20\x20\x20\x73\x68\x6f\x77\x67\x72\x69\ +\x64\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\x6d\x65\x6e\x74\x2d\ +\x75\x6e\x69\x74\x73\x3d\x22\x70\x78\x22\x0a\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x69\x64\x2d\x62\x62\ +\x6f\x78\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\x20\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x77\ +\x69\x64\x74\x68\x3d\x22\x31\x32\x38\x30\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\ +\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x37\x35\x35\x22\x0a\x20\x20\ \x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\ -\x6f\x77\x2d\x79\x3d\x22\x31\x39\x22\x0a\x20\x20\x20\x20\x20\x69\ -\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x6d\ -\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x20\x2f\x3e\x0a\ -\x20\x20\x3c\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\ -\x20\x69\x64\x3d\x22\x6d\x65\x74\x61\x64\x61\x74\x61\x32\x39\x39\ -\x30\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\ -\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\x62\ -\x6f\x75\x74\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ -\x3c\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\ -\x2f\x73\x76\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\ -\x6d\x61\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\ -\x3a\x74\x79\x70\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x72\x64\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\ -\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\ -\x63\x2f\x64\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\ -\x49\x6d\x61\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x3c\x64\x63\x3a\x74\x69\x74\x6c\x65\x3e\x3c\x2f\x64\x63\ -\x3a\x74\x69\x74\x6c\x65\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\ -\x63\x63\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x72\ -\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x3c\x2f\x6d\x65\x74\x61\ -\x64\x61\x74\x61\x3e\x0a\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\ -\x69\x64\x3d\x22\x6c\x61\x79\x65\x72\x31\x22\x0a\x20\x20\x20\x20\ -\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x6c\x61\x62\x65\x6c\x3d\ -\x22\x4c\x61\x79\x65\x72\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x69\ -\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x6f\x75\x70\x6d\x6f\x64\ -\x65\x3d\x22\x6c\x61\x79\x65\x72\x22\x3e\x0a\x20\x20\x20\x20\x3c\ +\x6f\x77\x2d\x78\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x79\x3d\ +\x22\x32\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x6d\x61\x78\x69\x6d\x69\ +\x7a\x65\x64\x3d\x22\x31\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x6d\x65\ +\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ +\x6d\x65\x74\x61\x64\x61\x74\x61\x32\x39\x39\x30\x22\x3e\x0a\x20\ +\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x20\ +\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\x62\x6f\x75\x74\x3d\x22\ +\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x66\ +\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\x2f\x73\x76\x67\x2b\ +\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x79\x70\x65\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\ +\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\ +\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x64\x63\x6d\ +\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\x49\x6d\x61\x67\x65\ +\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\ +\x3a\x74\x69\x74\x6c\x65\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ +\x3c\x2f\x63\x63\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\x20\x20\x20\x3c\ +\x2f\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x3c\x2f\x6d\x65\ +\x74\x61\x64\x61\x74\x61\x3e\x0a\x20\x20\x3c\x67\x0a\x20\x20\x20\ +\x20\x20\x69\x64\x3d\x22\x6c\x61\x79\x65\x72\x31\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x6c\x61\x62\x65\ +\x6c\x3d\x22\x4c\x61\x79\x65\x72\x20\x31\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x6f\x75\x70\x6d\ +\x6f\x64\x65\x3d\x22\x6c\x61\x79\x65\x72\x22\x3e\x0a\x20\x20\x20\ +\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x74\ +\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\ +\x30\x30\x3b\x66\x69\x6c\x6c\x3a\x23\x62\x66\x62\x62\x62\x62\x3b\ +\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\ +\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\ +\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\ +\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x33\x3b\x73\ +\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\ +\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\ +\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\x6b\x65\x2d\ +\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\x72\ +\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\x74\ +\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\x6e\ +\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x6f\ +\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\x72\x3a\x6e\ +\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\x79\x3a\x76\ +\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\x79\x3a\x69\ +\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\x77\x3a\x76\ +\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\ +\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\x6d\x75\x6c\ +\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\ +\x20\x35\x2e\x32\x39\x30\x30\x39\x32\x2c\x34\x31\x2e\x35\x33\x32\ +\x31\x34\x36\x20\x32\x39\x2e\x34\x38\x39\x34\x36\x2c\x35\x31\x2e\ +\x35\x35\x35\x35\x36\x39\x20\x32\x39\x2e\x36\x30\x35\x38\x30\x33\ +\x2c\x35\x37\x2e\x30\x37\x34\x30\x38\x31\x20\x35\x2e\x35\x32\x32\ +\x37\x37\x38\x33\x2c\x34\x36\x2e\x39\x33\x38\x30\x33\x37\x20\x7a\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\ +\x68\x33\x39\x30\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\ +\x2d\x63\x75\x72\x76\x61\x74\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\ +\x3e\x0a\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\ +\x23\x30\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\x3a\x23\x66\x66\ +\x66\x66\x66\x66\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\ +\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\ +\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\ +\x30\x30\x30\x30\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\ +\x68\x3a\x33\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\ +\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\ +\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\ +\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\ +\x34\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\ +\x3a\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\ +\x72\x61\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\ +\x64\x61\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\ +\x6b\x65\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\ +\x69\x74\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\ +\x6c\x61\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\ +\x6c\x6f\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\ +\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\ +\x63\x75\x6d\x75\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x64\x3d\x22\x4d\x20\x35\x39\x2e\x35\x30\x35\x39\x38\x35\x2c\ +\x31\x32\x2e\x33\x36\x32\x38\x36\x32\x20\x35\x39\x2e\x30\x34\x30\ +\x36\x31\x32\x2c\x33\x34\x2e\x34\x33\x36\x39\x31\x35\x20\x32\x39\ +\x2e\x36\x30\x35\x38\x30\x33\x2c\x35\x36\x2e\x39\x36\x31\x34\x35\ +\x39\x20\x32\x39\x2e\x34\x38\x39\x34\x36\x2c\x35\x31\x2e\x35\x35\ +\x35\x35\x36\x39\x20\x34\x30\x2e\x37\x37\x34\x37\x34\x33\x2c\x31\ +\x33\x2e\x39\x33\x39\x35\x38\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x38\x36\x39\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\x75\x72\x76\x61\x74\ +\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\ \x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\ -\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\x30\x30\ -\x3b\x66\x69\x6c\x6c\x3a\x23\x62\x66\x62\x62\x62\x62\x3b\x66\x69\ -\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\ -\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\ +\x65\x3d\x22\x66\x69\x6c\x6c\x3a\x23\x39\x32\x62\x64\x38\x65\x3b\ +\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\ \x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x73\x74\ \x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x33\x3b\x73\x74\x72\ \x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\x74\x74\ @@ -7006,87 +7066,27 @@ qt_resource_data = "\ \x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\x72\x6f\x6b\ \x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\x74\x72\x6f\ \x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\x6e\x6f\x6e\ -\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x6f\x66\x66\ -\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\x72\x3a\x6e\x6f\x6e\ -\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\x79\x3a\x76\x69\x73\ -\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\x79\x3a\x69\x6e\x6c\ -\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\x77\x3a\x76\x69\x73\ -\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\ -\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\x6d\x75\x6c\x61\x74\ -\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\x20\x35\ -\x2e\x32\x39\x30\x30\x39\x32\x2c\x34\x31\x2e\x35\x33\x32\x31\x34\ -\x36\x20\x32\x39\x2e\x34\x38\x39\x34\x36\x2c\x35\x31\x2e\x35\x35\ -\x35\x35\x36\x39\x20\x32\x39\x2e\x36\x30\x35\x38\x30\x33\x2c\x35\ -\x37\x2e\x30\x37\x34\x30\x38\x31\x20\x35\x2e\x35\x32\x32\x37\x37\ -\x38\x33\x2c\x34\x36\x2e\x39\x33\x38\x30\x33\x37\x20\x7a\x22\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\ -\x39\x30\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ -\x63\x61\x70\x65\x3a\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\ -\x75\x72\x76\x61\x74\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\ -\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x23\x30\ -\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\x3a\x23\x66\x66\x66\x66\ -\x66\x66\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\ -\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\x6e\x7a\ -\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\x30\x30\ -\x30\x30\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\ -\x33\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\ -\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\ -\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\ -\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\ -\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\ -\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\ -\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\ -\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\ -\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\ -\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\ -\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\ -\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\ -\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\ -\x6d\x75\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x64\ -\x3d\x22\x4d\x20\x35\x39\x2e\x35\x30\x35\x39\x38\x35\x2c\x31\x32\ -\x2e\x33\x36\x32\x38\x36\x32\x20\x35\x39\x2e\x30\x34\x30\x36\x31\ -\x32\x2c\x33\x34\x2e\x34\x33\x36\x39\x31\x35\x20\x32\x39\x2e\x36\ -\x30\x35\x38\x30\x33\x2c\x35\x36\x2e\x39\x36\x31\x34\x35\x39\x20\ -\x32\x39\x2e\x34\x38\x39\x34\x36\x2c\x35\x31\x2e\x35\x35\x35\x35\ -\x36\x39\x20\x34\x30\x2e\x37\x37\x34\x37\x34\x33\x2c\x31\x33\x2e\ -\x39\x33\x39\x35\x38\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ -\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x38\x36\x39\x22\x0a\x20\x20\ -\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\ -\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\x75\x72\x76\x61\x74\x75\x72\ -\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x70\x61\ -\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\ -\x22\x66\x69\x6c\x6c\x3a\x23\x35\x35\x39\x61\x35\x36\x3b\x66\x69\ -\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\x74\x72\ -\x6f\x6b\x65\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x73\x74\x72\x6f\ -\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x33\x3b\x73\x74\x72\x6f\x6b\ -\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\ -\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x72\ -\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\ -\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\x72\x6f\x6b\x65\x2d\ -\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\x74\x72\x6f\x6b\x65\ -\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\x6e\x6f\x6e\x65\x22\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x6d\x20\x33\x36\x2e\ -\x35\x30\x32\x38\x38\x37\x2c\x36\x2e\x34\x34\x36\x38\x36\x38\x20\ -\x2d\x31\x31\x2e\x30\x38\x39\x35\x37\x32\x2c\x38\x2e\x35\x36\x35\ -\x35\x37\x33\x20\x2d\x38\x2e\x39\x39\x39\x33\x39\x2c\x31\x36\x2e\ -\x30\x32\x39\x31\x34\x33\x20\x30\x2e\x31\x37\x34\x31\x38\x31\x2c\ -\x30\x2e\x30\x37\x35\x31\x34\x20\x4c\x20\x35\x2e\x32\x30\x38\x32\ -\x33\x31\x36\x2c\x34\x31\x2e\x37\x33\x36\x30\x32\x37\x20\x32\x39\ -\x2e\x35\x33\x35\x36\x31\x37\x2c\x35\x31\x2e\x36\x35\x34\x30\x35\ -\x39\x20\x34\x30\x2e\x34\x35\x31\x30\x30\x36\x2c\x34\x30\x2e\x36\ -\x38\x34\x31\x31\x35\x20\x34\x30\x2e\x38\x35\x37\x34\x33\x31\x2c\ -\x34\x30\x2e\x32\x38\x33\x33\x38\x36\x20\x34\x30\x2e\x36\x38\x33\ -\x32\x35\x2c\x34\x30\x2e\x32\x30\x38\x32\x34\x39\x20\x34\x39\x2e\ -\x34\x32\x31\x33\x36\x37\x2c\x32\x33\x2e\x35\x37\x38\x30\x31\x34\ -\x20\x35\x39\x2e\x35\x38\x31\x39\x36\x39\x2c\x31\x32\x2e\x34\x33\ -\x32\x37\x35\x31\x20\x33\x36\x2e\x35\x30\x32\x38\x38\x37\x2c\x36\ -\x2e\x34\x34\x36\x38\x36\x38\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x37\x36\x33\x22\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ -\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\x75\x72\x76\x61\x74\ -\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x2f\x67\ -\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ +\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x6d\x20\x33\ +\x36\x2e\x35\x30\x32\x38\x38\x37\x2c\x36\x2e\x34\x34\x36\x38\x36\ +\x38\x20\x2d\x31\x31\x2e\x30\x38\x39\x35\x37\x32\x2c\x38\x2e\x35\ +\x36\x35\x35\x37\x33\x20\x2d\x38\x2e\x39\x39\x39\x33\x39\x2c\x31\ +\x36\x2e\x30\x32\x39\x31\x34\x33\x20\x30\x2e\x31\x37\x34\x31\x38\ +\x31\x2c\x30\x2e\x30\x37\x35\x31\x34\x20\x4c\x20\x35\x2e\x32\x30\ +\x38\x32\x33\x31\x36\x2c\x34\x31\x2e\x37\x33\x36\x30\x32\x37\x20\ +\x32\x39\x2e\x35\x33\x35\x36\x31\x37\x2c\x35\x31\x2e\x36\x35\x34\ +\x30\x35\x39\x20\x34\x30\x2e\x34\x35\x31\x30\x30\x36\x2c\x34\x30\ +\x2e\x36\x38\x34\x31\x31\x35\x20\x34\x30\x2e\x38\x35\x37\x34\x33\ +\x31\x2c\x34\x30\x2e\x32\x38\x33\x33\x38\x36\x20\x34\x30\x2e\x36\ +\x38\x33\x32\x35\x2c\x34\x30\x2e\x32\x30\x38\x32\x34\x39\x20\x34\ +\x39\x2e\x34\x32\x31\x33\x36\x37\x2c\x32\x33\x2e\x35\x37\x38\x30\ +\x31\x34\x20\x35\x39\x2e\x35\x38\x31\x39\x36\x39\x2c\x31\x32\x2e\ +\x34\x33\x32\x37\x35\x31\x20\x33\x36\x2e\x35\x30\x32\x38\x38\x37\ +\x2c\x36\x2e\x34\x34\x36\x38\x36\x38\x20\x7a\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x37\x36\x33\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\x75\x72\x76\ +\x61\x74\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\x20\x20\x3c\ +\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ \x00\x00\x0e\x6b\ \x3c\ \x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ @@ -8358,6 +8358,133 @@ qt_resource_data = "\ \x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6e\x6f\x64\x65\x74\x79\x70\ \x65\x73\x3d\x22\x63\x63\x63\x63\x63\x22\x20\x2f\x3e\x0a\x20\x20\ \x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ +\x00\x00\x07\xc4\ +\x00\ +\x00\x37\x1e\x78\x9c\xed\x5b\x6d\x8f\x9b\x48\x12\xfe\x3e\xbf\x82\ +\x65\xbe\x24\x3a\x83\xfb\x9d\x6e\x32\x9e\xd5\xdd\x46\xbb\x5a\xe9\ +\x4e\x27\x5d\x12\xdd\xc7\x88\x81\xb6\xcd\x0e\x06\x0b\xf0\xd8\xce\ +\xaf\xdf\x6a\xcc\x9b\x6d\x3c\x2f\xd9\x91\x6e\x77\x38\x4b\xc9\x40\ +\x55\x75\x77\xd5\xd3\x55\xd5\xd5\xd0\xdc\xfc\xb8\x5b\x25\xd6\x83\ +\xce\x8b\x38\x4b\x67\x36\x76\x91\x6d\xe9\x34\xcc\xa2\x38\x5d\xcc\ +\xec\x2f\x9f\x7f\x76\xa4\x6d\x15\x65\x90\x46\x41\x92\xa5\x7a\x66\ +\xa7\x99\xfd\xe3\xed\xd5\xcd\x0f\x8e\x63\xfd\x94\xeb\xa0\xd4\x91\ +\xb5\x8d\xcb\xa5\xf5\x6b\x7a\x5f\x84\xc1\x5a\x5b\xef\x96\x65\xb9\ +\xf6\xa7\xd3\xed\x76\xeb\xc6\x35\xd1\xcd\xf2\xc5\xf4\xbd\xe5\x38\ +\xb7\x57\x57\x37\xc5\xc3\xe2\xca\xb2\x2c\x18\x37\x2d\xfc\x28\x9c\ +\xd9\x75\x83\xf5\x26\x4f\x2a\xc1\x28\x9c\xea\x44\xaf\x74\x5a\x16\ +\x53\xec\xe2\xa9\xdd\x89\x87\x9d\x78\x68\x46\x8f\x1f\x74\x98\xad\ +\x56\x59\x5a\x54\x2d\xd3\xe2\xba\x27\x9c\x47\xf3\x56\xda\x68\xb3\ +\xa5\x95\x10\x56\x4a\x4d\x11\x99\x12\xe2\x80\x84\x53\xec\xd3\x32\ +\xd8\x39\xc7\x4d\x41\xc7\xa1\xa6\x04\x21\x34\x05\x5e\x27\xf9\x3c\ +\x29\x7f\x97\x00\x14\x17\x95\xa9\xb8\xfd\xd1\x01\xfe\x35\xfc\x6b\ +\x1b\x34\x04\xb7\xc8\x36\x79\xa8\xe7\xd0\x52\xbb\xa9\x2e\xa7\x1f\ +\x3f\x7f\x6c\x99\x0e\x72\xa3\x32\xea\x75\xd3\xa0\x7f\x34\xee\xd1\ +\x94\xa4\xc1\x4a\x17\xeb\x20\xd4\xc5\xb4\xa1\x57\xed\xb7\x71\x54\ +\x2e\x67\xb6\x60\xeb\x5d\x75\xbf\xd4\xf1\x62\x59\xf6\x08\x71\x34\ +\xb3\xc1\x42\x22\xb1\xa8\xee\x7b\x0e\x84\x0f\x02\x75\x77\x7e\xcb\ +\x41\x2e\x93\x2e\x75\xb1\x95\x2b\x29\x0f\xad\x1a\xcd\xfd\x28\x0b\ +\x8d\x2a\x33\xfb\xef\x79\xb8\xfc\xfa\x8f\x4d\x9c\x18\xff\x73\x0d\ +\x86\xb7\x20\x78\x13\xe9\x79\x61\x1a\x1c\x06\x36\x77\x30\xb2\xac\ +\x78\xc0\x05\xf4\x74\x90\xff\x92\x07\x51\x0c\x3e\x73\x90\x3b\x48\ +\x1e\x73\xa8\x90\xb8\x6e\x03\xad\x8a\x32\x5b\x37\xb2\xb5\x41\x40\ +\xa1\x42\x79\x76\x47\xce\xe6\xf3\x42\x83\xe1\xa8\x47\x2b\xca\x7d\ +\xa2\x0f\xd2\x4e\x98\x25\x59\xee\x5f\xcf\xe7\x73\x8c\xd1\x87\x8a\ +\x94\x01\x9e\x71\xb9\xf7\xf1\x07\xdb\x9a\x5e\x18\x6d\xa0\x8b\x70\ +\xee\x21\x24\xcf\xba\x38\x57\x05\xdb\x43\x5a\x4b\xde\x8e\x76\x33\ +\x3d\x36\xbb\xa6\xb6\x33\xb2\x86\x19\x59\xeb\xd0\xc4\x4e\xd3\x53\ +\x3b\x11\xe5\xde\xb8\xcb\xb1\x28\x8d\xda\x11\xbb\x59\x5d\x7f\xdd\ +\x01\x2a\x96\x6f\x51\x02\xff\xe1\x41\x89\xfd\x41\x02\x43\x38\xc0\ +\x1f\x34\x28\xf3\xcd\x38\xd5\x23\xdd\xd4\x1a\x38\x59\x1e\x2f\x62\ +\xf0\xa2\x4a\x8e\x60\x97\x56\xbf\xe3\x36\x00\x46\xcf\x36\x22\x09\ +\xeb\x30\x79\xcc\xfa\x93\x86\x54\x10\xf2\xb4\x22\xc8\xe5\xc6\xa8\ +\x5a\x91\x53\x55\x8e\x2d\xc4\x95\x24\xff\x43\x40\xd5\x70\x9f\x76\ +\xf3\xd4\xcc\x7d\x2f\x00\x8e\x1a\x39\x04\x9c\x8e\x1c\x00\x8f\x8f\ +\x1c\x80\xde\x42\x30\x4a\x00\x3c\x32\xa0\xc3\xa8\x00\x60\x23\x5f\ +\x07\x3c\xc1\x46\x0e\x80\x1c\x79\x12\x94\x48\x8c\x1e\x00\x67\xe4\ +\x95\x80\xa4\x23\x0f\x02\x81\x47\x9e\x06\x01\x00\x47\x8e\x1c\x02\ +\x36\xf2\x2c\x00\x00\x8c\x3d\x11\x0a\x6f\xe4\xf5\x20\x00\xe0\x8c\ +\x7c\x2d\xf0\xd0\x33\x1e\x52\xbd\x71\x00\xc6\xbe\x16\x78\xec\x0d\ +\x16\xc5\xeb\xa0\x2c\x75\x9e\x36\xed\xea\xdb\xcf\x79\x90\x16\xf3\ +\x2c\x5f\xcd\xec\x55\x50\xe6\xf1\xee\x1d\x72\x05\x6c\x0b\xa9\x47\ +\xe4\xc4\x41\xae\xc4\x92\x28\xcc\xf9\x84\xb8\x8c\x7b\x92\x62\x36\ +\xc1\xae\x94\x8c\x71\xce\x26\x0e\x11\x40\x45\x02\x89\x09\x96\x2e\ +\x51\x4c\x31\xef\xfd\xf1\xe3\xda\xc3\x28\x9c\xd0\x4e\xe3\xea\x65\ +\x88\xbf\xcc\xf5\x7c\x66\x5f\x7f\x82\x31\xd7\x05\xfe\x8a\x9d\x81\ +\x12\x2c\xcc\x92\x04\xa6\x64\x66\x07\xc9\x36\xd8\x17\xdf\x35\x99\ +\x9c\x90\x37\x58\xdc\x9d\x4c\x66\x2b\x58\x94\x59\x78\x6f\x10\xa8\ +\x70\xd5\x85\x85\xfd\xe3\xe7\xe7\x43\x78\x3f\xe6\x0a\xc2\x03\x47\ +\x60\x74\xe2\x60\x17\x21\xc8\x0d\xb2\xf2\x04\x22\xb0\xf4\x24\x5c\ +\x51\x8c\x19\x67\x72\x42\x5d\xe6\x09\xa4\xa4\x07\x57\x9c\x32\x45\ +\x68\xe7\x07\xcd\xbb\xa5\x4e\x91\xfa\xed\x13\x39\xd5\xe0\x4b\x1a\ +\x97\xc5\xcc\xde\x14\x3a\xff\x64\x5e\x5a\xfd\x3b\xfd\x52\xe8\xa7\ +\xdd\xa2\x7d\x07\x93\x03\xb5\x91\x3e\x98\x6b\x28\x8c\x49\xda\xb3\ +\xb6\x53\x88\xf4\x68\xb5\x4a\xfd\x77\x2f\x30\x8f\x10\x00\xbc\x47\ +\xd9\x0d\xbe\x27\x9a\xc7\x49\xe2\xdf\x25\x41\x78\xff\xa1\x28\xf3\ +\xec\x5e\xfb\x69\x96\xea\xde\xdb\x9a\xda\xba\xef\xf3\xdd\xb7\xf8\ +\x9c\xfe\x05\xa9\xe8\xb9\xfe\xa7\x5c\x20\x51\x89\x27\xd2\x55\x42\ +\x11\x89\xd8\xc5\x44\xd4\xf3\x85\x0b\xa9\x68\x20\xfb\xbf\x56\x2a\ +\x7a\x8b\x25\xf6\x2b\x24\x23\x31\xaa\x64\x84\xfe\x34\xc9\xe8\x25\ +\x91\xc8\x31\xa5\x92\x54\xe0\x0b\x8a\x89\x52\x06\x7c\x0c\xc5\x02\ +\xa2\xe6\x8a\x41\xa1\xe0\xc1\xdc\x30\xe5\x7a\x82\x70\x61\xd8\x8a\ +\x33\x21\xd1\xa5\x9a\x40\x89\xe1\x40\xec\xc7\xea\x40\xb8\xbc\x4e\ +\x28\xca\x37\x58\xe3\xbe\x7e\x5e\x35\x15\x1e\xa5\x02\x44\x27\x18\ +\x8a\x41\xe9\x61\x75\xb9\xc2\xeb\x4d\xd6\xa5\x1a\xef\x45\xf3\xf9\ +\x1a\x45\x4e\x6f\xc0\x31\x64\x16\xd6\xcb\xa4\x7f\x9d\xdc\xc2\x00\ +\x7b\x26\xa5\x30\x1b\x0e\x41\x60\xb7\x21\x99\x82\x6d\x06\xe7\x90\ +\x5c\x84\x07\x57\x8c\x62\xaa\xc4\x84\x78\xae\x62\x92\x99\x3d\x08\ +\x75\x29\x12\x8c\x8b\x61\x67\xa4\x14\x3d\xe5\x8a\x03\x65\xd5\xab\ +\x24\x16\x4a\xfe\xbf\xc2\x77\xc8\x0c\xe1\x3d\x86\x38\xa4\x7f\x9a\ +\x28\x7c\x91\xef\x8a\x71\x3f\xfb\xe2\x54\xbe\xc1\xe0\x7d\x09\x00\ +\x0c\xbf\x41\x0f\xb8\x70\x7c\xf4\x52\x7c\x0f\x2e\x1c\x03\x07\x4d\ +\xfb\x18\x9e\xb1\xbb\xa3\x45\x3b\x3c\xb3\xa9\xe7\x4a\xe5\xf1\x6e\ +\x6d\xde\x03\x91\x41\x8e\x83\xb4\xa6\xba\x42\x74\x47\x80\x0a\xd5\ +\x35\xe2\x1e\xee\xb2\xc5\xde\x50\x91\x8b\x85\xe4\xaa\xdb\xba\x2e\ +\xea\xb1\x86\x93\xd8\xff\xd2\x76\xc5\xcf\x6d\x87\x15\xde\x3b\x36\ +\xde\x9c\x16\x66\x5e\xef\x85\x8b\x31\x5e\x10\x17\x31\xe9\x79\xea\ +\xc8\x78\x81\x5c\xa8\x2e\x31\xf6\x9e\x69\xfc\xa9\xd4\xd0\x4a\x43\ +\x18\x21\x1e\xc2\xea\x50\x72\x30\x8e\x3d\x45\x26\xd5\x2e\x47\x50\ +\x04\xa5\x06\x48\x10\x0f\x4a\x0c\xc2\x27\xdc\x15\x88\x29\xc4\xe5\ +\x84\x11\x17\x88\x98\xca\xf7\x35\xc0\x37\x53\x73\x54\xb9\xba\x6a\ +\xbd\xd1\x9c\x73\x8e\x1e\x62\xbd\xbd\x6a\x11\xba\x0b\x5a\xad\xd6\ +\xc1\x42\x57\x07\x82\x01\xd7\x79\xf5\xab\x19\x77\x59\x1e\xe9\xbc\ +\x61\x89\xea\x77\xc4\xaa\xcf\x0c\x1f\x8e\xf0\x5f\x9d\x44\x28\xf4\ +\xda\xf2\xd1\x30\xbf\x58\x06\x51\xb6\xed\x96\xa1\x96\xf9\x2d\xcb\ +\x00\x19\x0a\xd5\xbd\x02\x7f\x3c\x63\x87\x10\x7e\xb4\x2a\xc1\x30\ +\xf2\xce\x98\x46\x1f\xe6\xc2\xae\x40\x12\x7c\xc6\xdc\xe4\x39\xc0\ +\xef\x24\xc1\x5e\x83\x51\xd5\x9f\x46\xa8\x58\x66\xdb\x45\x6e\xc0\ +\x29\xf3\x8d\x3e\x6d\x19\x65\xe1\xc6\x7c\x1e\xe0\x6c\x0e\x13\x5c\ +\x1f\x4a\xef\x49\x98\xb6\xce\xdd\x5d\xb6\x1b\xee\xa0\x48\x83\xf5\ +\x23\x6c\xc3\x71\x60\x9d\x5c\x16\x8f\xf0\xd3\x2c\xd2\x17\xf8\x6d\ +\xf7\x8e\x8e\x16\xda\x59\xc5\xd1\x3a\x8b\xd3\xf2\x49\xe9\x27\x04\ +\xb3\xbb\xdf\x20\x18\x1f\x53\xac\x96\x78\x44\xb5\x6d\x9c\xc2\x34\ +\x3b\x4d\x81\x41\xe4\x99\x33\xd4\x12\x4d\x59\xe2\x71\x79\x41\xa2\ +\x57\x7f\x9c\xb2\xcc\xb4\xab\x0b\xbc\x55\xb0\x8b\x57\xf1\x37\x1d\ +\x99\xe6\x75\x9c\xac\x74\x19\x44\x41\x19\x74\x31\xd1\x50\x88\x71\ +\x9c\x3a\x59\xe5\xd1\xdc\xff\xcf\xc7\x9f\xdb\x02\x2b\x0c\xfd\xff\ +\x66\xf9\x7d\x57\x02\x19\x81\xe0\x2e\xdb\x80\xda\x6d\x19\x66\xbe\ +\x1e\x08\x7d\x13\xde\x41\x79\x1b\xaf\xc0\xd3\xcd\xa7\x19\x7f\xdb\ +\xad\x12\x88\xce\x96\x71\x24\x6c\x16\x8c\xae\xd3\x43\xb7\xb9\x3e\ +\x7c\x7a\x31\xf8\xb5\x4a\x14\xae\x62\xd3\x68\xfa\xa9\x84\xea\xeb\ +\x57\x33\x48\xef\xec\x7f\xdd\x69\x5c\x26\xfa\xb6\x1a\xf3\x70\xd9\ +\x58\x31\xad\xcd\x68\xea\xb3\x9e\x95\x37\xd3\x06\x86\xea\x6e\xd1\ +\xc1\x73\x14\x2c\x2d\xc2\x49\x70\xa7\x93\x99\xfd\x4f\xc3\xb4\xce\ +\xb8\x8b\x3c\xdb\xac\x57\xe0\x1a\x75\x73\xbb\xab\xde\x97\xed\xa2\ +\xd9\x2b\x22\xaf\x55\x20\x38\x62\x1f\xcc\x4d\xef\x93\x84\xba\xaa\ +\xbc\xa6\x1a\x9c\x47\xd4\xb7\x07\x87\xf2\x21\xf7\x40\xa8\x23\xc8\ +\x87\x0d\xdd\x64\x7f\x18\xdd\xbf\xdb\x94\x65\x9f\xf6\x1b\xf8\xb9\ +\x0f\x0a\xa5\x51\x43\x05\x08\x75\x9e\x80\x6b\x94\x3e\x6b\x68\xa7\ +\xa3\x3a\x51\x00\x79\x2a\xcf\x83\xfd\xa1\xaa\x6d\xd4\x06\x44\xfe\ +\x65\x11\x48\xcf\x54\x21\x4f\x4c\x18\x77\xb9\x14\x1e\x22\x16\xa4\ +\x64\x89\x14\x57\xb0\x4f\xa0\x2e\x26\x9c\x23\x6c\x31\x05\x9b\x43\ +\xe5\x61\x6f\xa2\x5c\x05\x49\x4d\x51\x8b\x40\x3e\xc7\xb0\xad\x24\ +\x13\x02\xe9\x9c\xc3\x6a\x44\xad\x6f\xa7\x5b\xc7\x25\x51\x68\xa0\ +\x02\x09\xb3\x14\x4c\x2c\xb3\xdc\x81\x84\xf6\x10\x94\x9b\x5c\xf7\ +\x0b\xf3\x2e\xf1\x03\xf2\xc6\x49\x20\x30\x43\xf3\x3b\xda\x3e\x0d\ +\x4e\x00\x78\xd8\xbb\xb3\xd5\x55\xf1\xf7\x7f\x99\x19\x19\x40\xda\ +\x2c\xe1\x04\x33\x4a\x27\x44\x98\xe7\x7f\xb0\xa4\x58\x94\x03\xcd\ +\x83\xd5\x7e\xc2\x61\xba\xcc\x4a\xfe\xdc\x09\x91\x6a\xf0\x59\xfc\ +\x1f\x9a\x90\x9b\xe9\xe2\xf6\xea\xc6\x24\x89\xdb\xab\xdf\x01\x64\ +\xd9\x31\x4e\ \x00\x00\x13\xbe\ \x3c\ \x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ @@ -9360,118 +9487,118 @@ qt_resource_data = "\ \x36\x14\x14\xa2\xad\xa3\xa0\xac\xa6\x04\x91\x00\x07\x92\x33\x46\ \x6d\xa5\x0d\x85\xb6\x3c\x63\xeb\xf9\x5a\xeb\xd5\x95\xd6\xd4\x5b\ \xcd\x6f\xa6\xf6\x72\x72\x7e\xf3\x07\x32\x2c\xc5\xda\ -\x00\x00\x06\xd7\ +\x00\x00\x06\xd6\ \x00\ -\x00\x27\xd0\x78\x9c\xed\x59\xdd\x6f\xe3\xb8\x11\x7f\xcf\x5f\xa1\ -\x7a\x5f\xee\x50\x93\xe2\xa7\x48\x2a\xb6\xef\xa1\x8b\x03\x0e\x68\ -\x5f\xda\x2b\xfa\x58\xc8\x12\x6d\xeb\x22\x4b\x86\x24\xc7\xc9\xfe\ -\xf5\x1d\xca\x92\x2c\x7f\xc4\xc9\x6d\x76\x7b\xc0\x39\x5a\x38\x12\ -\x39\x33\xe4\x70\x7e\x33\xe4\x0c\x77\xf2\xd3\xd3\x3a\xf3\x1e\x6d\ -\x59\xa5\x45\x3e\x1d\x51\x4c\x46\x9e\xcd\xe3\x22\x49\xf3\xe5\x74\ -\xf4\xef\x5f\x7f\x46\x7a\xe4\x55\x75\x94\x27\x51\x56\xe4\x76\x3a\ -\xca\x8b\xd1\x4f\xb3\xbb\xc9\x5f\x10\xf2\xfe\x56\xda\xa8\xb6\x89\ -\xb7\x4b\xeb\x95\xf7\x4b\xfe\x50\xc5\xd1\xc6\x7a\x3f\xac\xea\x7a\ -\x13\xfa\xfe\x6e\xb7\xc3\x69\xdb\x89\x8b\x72\xe9\xff\xe8\x21\x34\ -\xbb\xbb\x9b\x54\x8f\xcb\x3b\xcf\xf3\x60\xde\xbc\x0a\x93\x78\x3a\ -\x6a\x05\x36\xdb\x32\x6b\x18\x93\xd8\xb7\x99\x5d\xdb\xbc\xae\x7c\ -\x8a\xa9\x3f\x3a\xb0\xc7\x07\xf6\xd8\xcd\x9e\x3e\xda\xb8\x58\xaf\ -\x8b\xbc\x6a\x24\xf3\xea\xd3\x80\xb9\x4c\x16\x3d\xb7\xd3\x66\xc7\ -\x1b\x26\x6a\x8c\xf1\x09\xf3\x19\x43\xc0\x81\xaa\xe7\xbc\x8e\x9e\ -\xd0\xb1\x28\xe8\x78\x49\x94\x11\x42\x7c\xa0\x1d\x38\xdf\xc6\x15\ -\x56\x60\xd0\x0d\xfc\x7a\xf6\xae\x03\x57\xc5\xb6\x8c\xed\x02\xe4\ -\x2c\xce\x6d\xed\x7f\xfe\xf5\x73\x4f\x44\x04\x27\x75\x32\x18\xa6\ -\xb3\xe7\xd1\xac\x47\x46\xce\xa3\xb5\xad\x36\x51\x6c\x2b\xbf\xeb\ -\x6f\xe4\x77\x69\x52\xaf\xa6\xa3\x40\x6c\x9e\x9a\xf6\xca\xa6\xcb\ -\x55\x3d\xe8\x48\x93\xe9\x08\x74\x66\x9a\x06\x4d\x7b\xe0\x12\x74\ -\xcf\xd0\x0e\x17\xf6\x14\x82\x85\xc6\xd4\x2b\x8d\x0a\x48\xc3\xd2\ -\xe9\x1d\x26\x45\xec\x14\x99\x8e\x36\xa5\x5d\xd8\x12\x1c\xca\x56\ -\x28\x2a\xe3\x15\x76\x66\x99\x01\xef\x24\xb1\x8b\xca\xc9\xec\x67\ -\x76\x2d\x98\x5a\x37\x34\xa0\xf6\x93\x6d\x60\xb2\x8d\x8d\x1d\xd0\ -\x7b\xee\xc1\x2c\xf5\xb3\xb3\xc4\x31\x2b\xdf\x9b\xcb\x3b\x52\x78\ -\xf3\xdf\x27\xd0\xd6\x0b\x3d\xce\xe0\x0f\xbd\xc8\xf1\xbc\xe7\xa0\ -\x80\x1d\xbc\xc8\x45\x9e\x2f\xce\x5e\x57\x86\x69\x35\x40\x45\x99\ -\x2e\x53\x30\x50\xc3\xc7\x28\xe6\xcd\x73\x2c\x03\x8b\x1e\xac\x8d\ -\x69\x26\x46\x9e\xff\x86\xd5\x9f\x08\xf2\x80\xb1\xd7\x15\x21\x58\ -\xba\x45\xb5\x8a\x9c\xaa\x72\xbc\x42\xda\x70\xca\x77\x19\xaa\x35\ -\xf7\xe9\x30\xaf\x21\xf7\xb5\x06\x40\xe6\xc6\x4d\x20\xf9\x8d\x1b\ -\x40\xc9\x1b\x37\x80\x51\xb7\x6d\x00\xc5\x2e\xe8\x70\x53\x06\x10\ -\x37\x7e\x0e\xa8\x40\xdc\xb8\x01\xf4\x8d\x6f\x82\x9a\x04\x37\x6f\ -\x00\x74\xe3\x99\x80\xe6\x7f\xb6\x20\x98\xf8\xae\x38\x6a\xbe\x7a\ -\x01\x57\x5c\x25\x8f\xa9\xdd\x1d\x2a\xa8\x79\x54\xd9\x76\xe4\x4d\ -\xb4\x84\xaa\x38\x2b\xca\xe9\xe8\xd3\xa2\x79\x5a\xc2\xbc\x28\x13\ -\x5b\x76\xa4\xa0\x79\x8e\x48\x05\x54\x8e\x69\xfd\xbc\xbf\x07\xb8\ -\x3b\x31\x22\x8c\xda\xd3\xc9\x65\x7a\xb5\x8a\x92\x62\x37\x1d\xb1\ -\x53\xe2\x97\xa2\x58\x3b\x29\x26\x38\x09\x94\x09\x4e\xe9\x31\x98\ -\x08\x71\x26\x30\x64\xf3\xca\x9c\x51\x61\x46\xc4\x24\xc7\x84\x52\ -\x2a\xcf\xa8\xdb\x12\x2a\xcc\x1a\x65\xd1\xb3\x85\x75\x35\xaf\xce\ -\xc8\xd5\xaa\xd8\x2d\x4b\x67\x9f\xba\xdc\xda\x53\x49\x28\x53\xb7\ -\xee\x9a\x01\x6d\xf3\xb4\x86\x52\xbe\x2d\x85\x07\x1c\x4e\x16\xcd\ -\xe7\xc5\xd3\xe5\x01\xaa\x3c\xda\x5c\x21\x3b\x0a\xda\x44\xf5\xaa\ -\xba\x42\xcf\x8b\xc4\xbe\x40\xef\x87\x47\x36\x59\x5a\xb4\x4e\x93\ -\x4d\x91\xe6\xf5\xab\xdc\xaf\x30\x16\xf3\xdf\x20\x5a\xae\x29\xd6\ -\x72\x5c\x51\x6d\x97\xe6\x80\x34\x6a\xaf\x15\x28\xd3\x67\xfe\xd0\ -\x72\x74\x17\x0d\x4a\xea\x17\x38\x5c\x74\xbc\x40\x72\x9e\x78\xe6\ -\x0d\x2d\x6d\x1d\x3d\xa5\xeb\xf4\x8b\x4d\x9c\x78\x1b\x2a\x6b\x5b\ -\x47\x49\x54\x47\x87\xb0\xe8\x7a\xa0\xc0\xa6\xdd\xe5\x42\x99\x2c\ -\xc2\x7f\x7e\xfe\x79\xd6\xc6\xe1\x24\x8e\xc3\xff\x14\xe5\x43\x17\ -\x96\x9e\xe7\x18\xa2\x79\xb1\x05\xb5\x47\xb3\xbe\x7b\x92\xc4\xe1\ -\xa2\x28\xd7\x51\x3d\x4b\xd7\xe0\xec\xee\x8a\xe7\xaf\x4f\xeb\x0c\ -\x02\xb4\x27\x1c\x31\xbb\xb0\x3e\x0c\xba\x1f\xb6\xb4\xfb\x0b\x9f\ -\x8b\xb7\x5e\x49\xbc\x4e\x9d\x90\xff\xaf\x3a\xcd\xb2\x5f\xdc\x24\ -\xfd\x2e\xd8\x0f\x9a\xd6\x99\x9d\x35\x73\xee\x3f\xbb\x55\xf8\xed\ -\x32\xda\x45\xfa\x83\x55\x4e\xfc\xce\x0c\x4d\x6b\x79\x30\xcf\x51\ -\xb0\xf4\x16\xce\xa2\xb9\xcd\xa6\xa3\xbf\x3b\xa2\x77\x46\x5d\x96\ -\xc5\x76\xb3\x06\xd7\x68\xc5\x7b\xb3\x82\xcb\xf4\x5b\x5b\xfd\x9c\ -\x01\xbd\xd9\x6a\xc2\x4f\xa4\x79\xee\x17\xb0\xa8\xf0\x53\x14\x09\ -\xd1\x36\x50\xbb\x9f\x84\x74\xdf\x2c\xb7\x99\x0d\xed\xa3\x05\xbf\ -\x4b\xee\xab\xba\x2c\x1e\x6c\x2f\xbc\x6f\xee\x1d\x2e\xe4\x58\x88\ -\x40\x30\x46\x68\xd7\x9f\xa5\xb9\x05\xed\xc2\xf9\xb6\xae\x87\x7d\ -\xbf\x41\x1c\x84\xa0\x70\xde\x0d\x08\xc1\x51\xdb\x32\x03\xd7\xa9\ -\x43\xd1\xf5\x1d\xf4\x68\x3b\x92\x08\xb6\xb2\xb2\x8c\x9e\xc3\xbc\ -\xc8\xed\xb0\xb7\x58\x2c\x2a\x5b\x87\xe4\x7e\x1d\x95\x0f\xb6\xdc\ -\xd3\x1f\xd3\x2a\x9d\xa7\x99\x1b\xa2\xf9\xcc\xec\x7d\x92\x56\x1b\ -\x30\x4f\x98\xe6\x4e\x8d\xfb\xe2\xd1\x96\x8b\xac\xd8\xf5\x74\x9b\ -\x47\xf0\x42\xf3\x28\x7e\x58\x36\xfa\x85\x51\x0c\xbb\xd1\x36\x8b\ -\x6a\x7b\x38\x44\x00\x22\x67\x56\xa6\x05\x41\x1c\x09\x44\x90\xee\ -\x89\x5d\xec\x49\x6c\x78\xc0\xd9\xe1\x0e\xa4\x0b\x39\xca\xb0\xd4\ -\x52\x90\x83\xc8\x93\xbb\x93\xc2\xc6\x28\x33\x48\x95\x20\xc8\xa4\ -\xc1\x01\xc4\xf0\xa1\x82\xa8\xcb\x28\xaf\x9c\x4f\x43\x04\x45\x75\ -\x99\x3e\xfd\x40\xb0\x92\x4a\x51\x21\xc7\x88\xe0\x40\x32\xa9\x03\ -\x6a\xc6\x64\x4c\xe1\x47\x7e\x3c\x1c\xd6\x6f\xf4\x82\xc5\x42\x2d\ -\x58\xf4\x5e\x2f\x20\x46\xc3\xca\x95\xfe\xf6\x88\x7f\x47\x74\xaf\ -\xb9\xec\xd0\xc3\x2e\x7a\xc1\x29\xfa\x70\x64\xf2\x80\x99\x40\x5d\ -\x42\x5f\x68\x26\x8d\x18\xa2\xcf\x30\x87\x23\x94\x99\x23\xf4\x99\ -\xc6\x5a\x6b\x00\xf7\x2a\xfc\x86\x2b\x2e\x29\x01\xcc\x31\x17\x9a\ -\x7f\xc0\xff\x47\xc0\x3f\xb8\xe9\xfc\x4a\x07\xd0\xd8\x04\x80\xe3\ -\x99\x03\x04\x01\xf8\xc0\x37\x70\x00\x97\x55\xbc\xc9\x01\x8c\x91\ -\xf2\x9d\x0e\xf0\x1e\xdc\xff\x40\x84\xaf\x1f\x2c\x3d\x06\x00\xfb\ -\x3f\x3c\x2a\x20\x67\xa6\x92\xa9\x31\x35\x98\x19\x41\x89\xf6\xb8\ -\xc2\x44\x69\xaa\xc7\x4c\x61\xf7\x66\xc6\x63\x12\x13\xc2\x8c\xe1\ -\x63\xae\x31\xd5\x34\x90\xca\x63\x98\x06\x01\xe7\x06\xf8\x60\x7b\ -\x37\x1c\x4e\x89\x8b\xc3\x7d\x79\xe9\xb8\x91\xee\x77\x5e\xad\xb8\ -\xac\xd0\x65\x29\x90\x19\xc6\xee\xf9\xc0\xfe\x3b\x61\xcf\x01\x22\ -\x40\x4b\x89\x31\x04\xa8\x90\x42\x31\xe5\x05\x0c\x93\x80\x68\x00\ -\x90\x07\xd8\x08\x26\x84\xf6\x84\xc1\x46\xcb\x40\x8c\x85\x82\xc8\ -\x84\x02\x2a\xf0\xc0\x33\xa8\xd0\x46\x2b\xe7\x0f\x90\x03\x48\x29\ -\x2f\x0e\x77\x0d\xfb\x77\x22\xbf\xc7\xfa\x08\xbb\x37\x40\xf9\x62\ -\x0e\xd7\x20\x7a\x0e\x65\xf7\x05\x39\x09\xe1\x44\x72\x97\x5b\xee\ -\x1f\x79\xcd\x17\x8e\xa1\x18\x9a\x7d\xed\xec\xe4\xb6\x39\xad\xc7\ -\x02\xca\x60\x30\x23\xe7\x1e\xe5\x98\x13\x45\x8d\x18\x23\x0a\xd9\ -\x0f\xa5\x46\x79\x02\x83\x81\xe1\xdf\x18\x09\x4c\xb8\x94\xc6\x78\ -\x88\x81\x1e\x5c\x1b\xc3\xc6\x48\xe1\x40\x18\xc2\xb8\x87\x34\x86\ -\xca\x16\x1a\x63\x00\x25\x30\x01\x40\x41\x9b\x6c\x4a\x48\x3d\x0e\ -\x5c\x90\xd2\x40\x9c\x20\xe1\xec\xc9\xb5\x30\xaf\x63\x10\x7f\x9c\ -\xbd\xff\xaf\xb3\x97\xbf\xf3\xec\xa5\x6e\xbb\xd6\x4a\x0f\x8f\x5e\ -\x70\x2c\x2d\x14\x1d\xfc\x07\xde\x77\xcf\xbd\xbe\x5f\x01\xf6\x67\ -\xc7\x1f\x89\x53\x0f\xf8\x9d\xc5\x57\x00\xec\x81\x36\xf2\x28\xfb\ -\x32\x00\xaa\x61\x8a\x5c\xcf\xbe\xbe\x69\xf5\xf5\xe1\x02\x5f\xef\ -\x02\xe8\xac\x06\xfb\x9d\x4e\x20\x21\x31\x13\xc2\x48\x3a\x74\x02\ -\x38\xd7\xe1\x38\x10\x83\xc2\xec\xeb\x9d\xe0\x23\x0d\xfb\xa6\x69\ -\x18\x64\x4b\x0a\xe0\x62\x63\xc8\x0b\x04\xd5\x8a\x79\x92\x62\x67\ -\x7b\xc5\xc6\x54\x63\x48\xbb\xa5\xe1\x7d\xd6\x20\x9b\xec\x0a\x52\ -\x6b\x46\x3d\x1a\xe0\x40\x09\xce\x99\xcb\xb6\x21\xd9\x56\x17\xc6\ -\x7a\x39\x03\x7b\x73\xfe\x35\xf1\x97\xb3\xbb\x89\xbb\x8e\x9c\xdd\ -\xfd\x0f\x63\x62\xcf\x20\ +\x00\x27\xf1\x78\x9c\xed\x59\xdd\x6f\xdb\x36\x10\x7f\xcf\x5f\xa1\ +\xa9\x2f\x1b\x66\x51\xfc\x14\x49\xc5\xce\x30\xac\x28\x30\x60\x7b\ +\xd9\x3a\xec\xb1\x90\x25\xda\xd6\x22\x4b\x86\x24\xc7\x4e\xff\xfa\ +\x1d\x65\x49\x96\x1d\xc7\xc9\x9a\x74\x03\xe6\xc8\x48\x6d\xf1\x3e\ +\x78\xbc\xfb\x1d\x79\xc7\x8e\x7f\xd8\x2e\x33\xe7\xce\x94\x55\x5a\ +\xe4\x13\x97\x20\xec\x3a\x26\x8f\x8b\x24\xcd\xe7\x13\xf7\x8f\x8f\ +\x1f\x3c\xe5\x3a\x55\x1d\xe5\x49\x94\x15\xb9\x99\xb8\x79\xe1\xfe\ +\x70\x73\x35\xfe\xc6\xf3\x9c\x9f\x4a\x13\xd5\x26\x71\x36\x69\xbd\ +\x70\x7e\xce\x6f\xab\x38\x5a\x19\xe7\xdb\x45\x5d\xaf\x42\xdf\xdf\ +\x6c\x36\x28\x6d\x07\x51\x51\xce\xfd\xef\x1c\xcf\xbb\xb9\xba\x1a\ +\x57\x77\xf3\x2b\xc7\x71\x60\xde\xbc\x0a\x93\x78\xe2\xb6\x02\xab\ +\x75\x99\x35\x8c\x49\xec\x9b\xcc\x2c\x4d\x5e\x57\x3e\x41\xc4\x77\ +\xf7\xec\xf1\x9e\x3d\xb6\xb3\xa7\x77\x26\x2e\x96\xcb\x22\xaf\x1a\ +\xc9\xbc\x7a\x37\x60\x2e\x93\x59\xcf\x6d\xad\xd9\xb0\x86\x89\x68\ +\xad\x7d\x4c\x7d\x4a\x3d\xe0\xf0\xaa\xfb\xbc\x8e\xb6\xde\xa1\x28\ +\xd8\x78\x4a\x94\x62\x8c\x7d\xa0\xed\x39\x9f\xc7\x15\x56\xe0\xd0\ +\x15\xfc\xf5\xec\xdd\x00\xaa\x8a\x75\x19\x9b\x19\xc8\x19\x94\x9b\ +\xda\x7f\xff\xf1\x7d\x4f\xf4\x30\x4a\xea\x64\xa0\xa6\xf3\xe7\xc1\ +\xac\x07\x4e\xce\xa3\xa5\xa9\x56\x51\x6c\x2a\xbf\x1b\x6f\xe4\x37\ +\x69\x52\x2f\x26\x6e\xc0\x57\xdb\xe6\x7d\x61\xd2\xf9\xa2\x1e\x0c\ +\xa4\xc9\xc4\x05\x9b\xa9\x22\x41\xf3\x3e\x80\x04\xd9\x31\xb4\xea\ +\xc2\x9e\x82\x11\x57\x88\x21\xe2\x94\x5a\xa9\x9d\x54\x67\x79\x98\ +\x14\xb1\x35\x65\xe2\xfe\x58\xc6\x8b\x4f\x7f\x46\x59\xf6\xe9\x63\ +\x69\x0c\xb2\x6e\xb9\x01\xce\x71\x62\x66\x95\x95\xd8\xcd\x6c\xdf\ +\x60\x6a\xd5\xd0\x80\xda\x4f\xb6\x82\xc9\x56\x26\xb6\x81\xde\x71\ +\x0f\xe6\xa8\xef\xad\x27\x0e\x59\xd9\xce\x5d\xce\x81\xc1\xab\x4f\ +\x5b\xb0\xd6\x09\x1d\x46\xe1\x1f\x72\x92\xe3\x7e\xc7\x41\x20\x76\ +\xf0\x85\x4f\xf2\x7c\xb6\xfe\x3a\xa3\xa6\xb5\xc0\x2b\xca\x74\x9e\ +\x82\x83\x1a\x3e\x4a\x10\x6b\x9e\x43\x19\x58\xf4\x60\x6d\x54\x51\ +\xee\x3a\xfe\x33\x56\x7f\x24\xc8\x02\x4a\x9f\x36\x04\x23\x61\x17\ +\xd5\x1a\x72\x6c\xca\xe1\x0a\x49\xc3\x29\x5e\xe4\xa8\xd6\xdd\xc7\ +\x6a\x9e\x8a\xdc\x97\x3a\xc0\xd3\x17\xee\x02\xc1\x2e\xdc\x01\x52\ +\x5c\xb8\x03\xb4\xbc\x6c\x07\x48\x7a\xc2\x86\x8b\x72\x00\xbf\xf0\ +\x73\x40\x06\xfc\xc2\x1d\xa0\x2e\x7c\x13\x54\x38\xb8\x78\x07\x78\ +\x17\x5e\x09\x28\xf6\x7f\x4b\x82\xb1\x6f\x9b\xa3\xe6\x57\x2f\x60\ +\x5b\xab\xe4\x2e\x35\x9b\x7d\x07\x35\x8d\x2a\xd3\x6a\x5e\x45\x73\ +\xe8\x8a\xb3\xa2\x9c\xb8\xef\x66\xcd\xd3\x12\xa6\x45\x99\x98\xb2\ +\x23\x05\xcd\x73\x40\x2a\xa0\x73\x4c\xeb\xfb\xdd\x3d\xc0\xd5\x91\ +\x13\x41\x6b\x4f\xc7\xa7\xe9\xd5\x22\x4a\x8a\xcd\xc4\xa5\xc7\xc4\ +\xcf\x45\xb1\x9c\xb8\x02\x09\x6c\x1f\x72\x4c\x8e\xc1\x43\x5c\x20\ +\x4c\x45\xc0\x1f\x12\x61\x3e\x2a\x91\x22\x1a\x93\xe0\x01\x71\x5d\ +\x96\x26\xaf\xbd\x2c\xba\x37\xb0\xa8\xe6\xab\xd3\x50\x2d\x8a\xcd\ +\xbc\xb4\xce\xa9\xcb\xb5\x39\x96\x84\x0e\x75\x6d\xef\x18\xbc\x75\ +\x9e\xd6\xd0\xc7\xb7\x7d\xf0\x80\xc3\xca\x7a\xd3\x69\xb1\x3d\xad\ +\xa0\xca\xa3\xd5\x19\xb2\xa5\x78\xab\xa8\x5e\x54\x67\xe8\x79\x91\ +\x98\x47\xe8\xbd\x7a\xcf\x24\x73\xe3\x2d\xd3\x64\x55\xa4\x79\xfd\ +\x24\xf7\x13\x8c\xc5\xf4\x2f\x48\x95\x73\x86\xb5\x1c\x67\x4c\xdb\ +\xa4\x39\x84\xd9\x6b\xef\x14\x08\x55\x0f\xc0\xd0\x72\x74\xb7\x0c\ +\x52\xa8\x47\x38\x6c\x6a\x3c\x42\xb2\x30\xd4\x8f\xd0\x96\xd1\x36\ +\x5d\xa6\x9f\x4d\x62\xc5\xdb\x3c\x59\x9a\x3a\x4a\xa2\x3a\xda\xe7\ +\x44\x37\x02\xdd\x35\xe9\x6e\x16\xca\x64\x16\xfe\xf6\xfe\xc3\x4d\ +\x9b\x84\xe3\x38\x0e\xff\x2c\xca\xdb\x2e\x27\x1d\xc7\x32\x44\xd3\ +\x62\x0d\x66\xbb\x37\xfd\xf0\x38\x89\xc3\x59\x51\x2e\xa3\xfa\x26\ +\x5d\x02\xd2\xed\xfd\xce\xf7\xdb\x65\x06\xd9\xd9\x13\x0e\x98\x6d\ +\x4e\xef\x95\xee\xd4\x96\x66\x77\xdb\x73\xf2\xca\x2b\x89\x97\xa9\ +\x15\xf2\x7f\xaf\xd3\x2c\xfb\xd9\x4e\xd2\x6f\x81\xbd\xd2\xb4\xce\ +\xcc\x7e\x70\xec\xb7\xd6\xb7\x6b\xf3\x07\x8b\x1b\xfb\xdd\xea\x9b\ +\xb7\xf9\xde\x2b\x07\x39\xd2\x3b\x36\x8b\xa6\x26\x9b\xb8\xbf\x58\ +\xa2\xf3\x80\x3a\x2f\x8b\xf5\x6a\x09\x88\x68\xc5\x7b\x6f\x02\x52\ +\xfa\xed\xac\xbe\xcf\x80\xde\x6c\x2f\xe1\xbb\x26\xd1\xf1\xf5\x0c\ +\xd6\x12\xbe\x8b\x22\xce\xdb\x17\xaf\xdd\x43\x42\xb2\x7b\x2d\xd7\ +\x99\x09\xcd\x9d\x01\xb8\x25\xd7\x55\x5d\x16\xb7\xa6\x17\xde\xbd\ +\xee\x70\x16\x32\xc4\x79\xc0\x29\xc5\xa4\x1b\xcf\xd2\xdc\x80\x75\ +\xe1\x74\x5d\xd7\xc3\xb1\xbf\x00\xfe\x21\x18\x9c\x77\x0a\x21\x27\ +\x6a\x53\x66\x80\x98\x3a\xe4\xdd\xd8\xde\x8e\x76\x20\x89\x60\xfb\ +\x2a\xcb\xe8\x3e\xcc\x8b\xdc\x0c\x47\x8b\xd9\xac\x32\x75\x88\xaf\ +\x97\x51\x79\x6b\xca\x1d\xfd\x2e\xad\xd2\x69\x9a\x59\x15\xcd\xcf\ +\xcc\x5c\x27\x69\xb5\x02\xf7\x84\x69\x6e\xcd\xb8\x2e\xee\x4c\x39\ +\xcb\x8a\x4d\x4f\x37\x79\x04\x5f\xde\x34\x8a\x6f\xe7\x8d\x7d\x61\ +\x14\xc3\x26\xb4\xce\xa2\xda\xec\x0f\x0e\x08\x91\x75\x2b\x55\x1c\ +\x7b\xcc\xe3\x1e\xf6\x54\x4f\xec\x52\x4e\x20\xcd\x02\x46\xf7\xf7\ +\x1e\x5d\xa6\x11\x8a\x84\x12\x1c\xef\x45\xb6\xf6\x1e\x0a\x69\x2d\ +\xf5\xa0\x3c\x82\xdc\x12\x1a\x05\x90\xba\xfb\xae\xa1\x2e\xa3\xbc\ +\xb2\x50\x86\xc4\x89\xea\x32\xdd\x7e\x8b\x91\x14\x52\x12\x2e\x46\ +\x1e\x46\x81\xa0\x42\x05\x44\x8f\xf0\x88\xc0\x1f\xfe\x6e\x7f\x40\ +\x3f\x13\x05\xbb\xb3\xe8\xa5\x28\xc0\x5a\xc1\xca\xa5\xd4\xed\xa3\ +\x5e\x3f\xf4\x5f\x31\xcc\xe7\xb0\x3b\x84\xda\x49\x38\x1c\xc3\x80\ +\x72\xc4\x02\xaa\x03\x79\x0a\x06\x5c\x51\xa1\xf9\x10\x06\x14\x31\ +\x42\x08\xf0\x0f\x61\x40\x15\x52\x4a\x41\x94\xcf\xe2\x40\x33\xc9\ +\x04\xc1\x10\x7c\xc4\xb8\x62\x6f\x38\xf8\x4f\x71\x30\xb8\xef\xfc\ +\x42\x24\x28\xa4\x03\x08\xe8\x03\x24\x04\x01\x80\xe1\x15\x90\x60\ +\xcb\x8b\x67\x20\x21\x96\xf6\xf3\x42\x24\xbc\x24\xee\xff\x61\x84\ +\xcf\x1f\x35\x7d\x0c\x20\xec\xbf\x3a\x84\x23\xca\x89\xa0\x72\x44\ +\x34\xa2\x9a\x13\xac\x1c\x26\x11\x96\x8a\xa8\x11\xd4\xc6\xf6\x9b\ +\x6a\x87\x42\x09\x8d\xa9\xd6\x6c\xc4\x14\x22\x8a\x04\x42\x3a\x14\ +\x91\x20\x60\x4c\x03\x1f\x6c\xf8\x9a\xc1\xb9\x71\x52\xdd\xe7\xc7\ +\x0e\x20\x61\xff\x1e\xf6\x2c\xb6\x3c\xb4\xe5\x0a\x94\x88\xb1\x7d\ +\xde\x62\xff\x95\x62\xcf\x20\x44\x10\x2d\xc9\x47\x90\xa0\x5c\x70\ +\x49\xa5\x13\x50\x84\x03\xac\x20\x80\x2c\x40\x9a\x53\xce\x95\xc3\ +\x35\xd2\x0a\xfa\xa7\x11\x97\x90\x99\x94\xca\xc0\x01\x64\x10\xae\ +\xb4\x92\x16\x0f\x50\x15\x08\x21\x4e\xaa\x3b\x17\xfb\x17\x46\x7e\ +\x17\xeb\x83\xd8\x3d\x23\x94\x8f\x56\x75\x4d\x44\x1f\x86\xb2\xfb\ +\x05\x55\x0a\x66\x58\x30\x5b\x6d\xee\x1e\x71\x0e\x0b\x87\xa1\x18\ +\xba\x7d\x69\xfd\x64\xb7\x39\xa5\x46\x1c\x9a\x61\x70\x23\x63\x0e\ +\x61\x88\x61\x49\x34\x1f\x79\x04\xea\x21\x42\xb4\x74\x38\x02\x07\ +\xc3\x67\xe4\x71\x84\x99\x10\x5a\x3b\x1e\x05\x3b\x98\xd2\x9a\x8e\ +\x3c\x89\x02\xae\x31\x65\x8e\xa7\x10\xa3\x50\xc0\xea\x11\x04\x25\ +\xd0\x01\x84\x82\x34\xf5\x15\x17\x6a\x14\xd8\x24\x25\x01\x3f\x8a\ +\x84\xf5\x27\x53\x5c\x3f\x1d\x83\xf8\xed\x10\xfe\xd7\x0f\x61\xf6\ +\xc2\x43\x98\xd8\x7d\x5b\x49\x35\x3c\x83\x01\x61\x8a\x4b\x32\xf8\ +\xff\xbc\xaf\x5e\x8d\xc9\xc8\x7e\x5e\xab\x37\xeb\xf2\x8e\x5f\x12\ +\x10\x3c\x7e\x0c\x85\x7f\xd8\xa0\x05\xc0\x1e\x28\x2d\x0e\xea\x31\ +\x0d\xd1\xd5\x54\xe2\xf3\xf5\xd8\xab\x76\x68\x6f\x58\x78\x05\x2c\ +\x78\x0f\xfa\xb4\x7f\x88\x06\x01\x35\x1b\xe7\x5a\x90\x21\x1a\xe0\ +\xc8\x87\x93\x82\x0f\x9a\xb7\x2f\x47\xc3\x5b\x85\xf6\xaa\x15\x1a\ +\x14\x52\x12\xc2\x45\x47\x50\x32\x70\xa2\x24\x75\x04\x41\xd6\xf7\ +\x92\x8e\x88\x42\x50\x91\x0b\xcd\xfa\x82\x42\x34\x85\x17\x54\xdd\ +\x94\x38\x24\x40\x81\xe4\x8c\x51\x5b\x88\x43\x1d\x2e\x4f\xe8\x7a\ +\xbc\x38\x7b\x76\x69\x36\xf6\xe7\x37\x57\x63\x7b\x65\x79\x73\xf5\ +\x37\x0f\x85\xd5\xfb\ \x00\x00\x11\xff\ \x3c\ \x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ @@ -10066,6 +10193,130 @@ qt_resource_data = "\ \x9a\x32\x44\x99\x70\x39\x33\x94\xd2\xeb\xa7\x55\xab\x4f\x8c\xe1\ \x70\xaa\x5e\x6a\x8c\x9b\xd9\xea\xf6\xea\xc6\x24\x6c\xb7\x57\xff\ \x06\x6a\xf1\x08\x6d\ +\x00\x00\x07\x91\ +\x00\ +\x00\x36\x0d\x78\x9c\xed\x5b\xdd\x6f\xdb\x38\x12\x7f\xcf\x5f\xa1\ +\x53\x5e\x5a\x9c\x25\xf3\x4b\x14\xa9\xda\x59\x1c\xae\xd8\xc3\x02\ +\x77\x38\x60\xdb\xe2\x1e\x0b\x59\xa2\x6d\x6d\x64\xd1\x90\xe4\xd8\ +\xee\x5f\x7f\x43\x59\x5f\x76\xe4\xa4\xe9\xe6\xa1\x17\x9d\x83\x24\ +\xd2\xcc\x90\x1c\xfe\x66\x38\x33\x94\xe8\xd9\x2f\x87\x4d\x6a\x3d\ +\xa8\xbc\x48\x74\x36\xb7\xb1\x8b\x6c\x4b\x65\x91\x8e\x93\x6c\x35\ +\xb7\xbf\x7c\xfe\xd5\x11\xb6\x55\x94\x61\x16\x87\xa9\xce\xd4\xdc\ +\xce\xb4\xfd\xcb\xdd\xcd\xec\x2f\x8e\x63\xfd\x3d\x57\x61\xa9\x62\ +\x6b\x9f\x94\x6b\xeb\xb7\xec\xbe\x88\xc2\xad\xb2\xde\xad\xcb\x72\ +\x1b\x4c\xa7\xfb\xfd\xde\x4d\x6a\xa2\xab\xf3\xd5\xf4\xbd\xe5\x38\ +\x77\x37\x37\xb3\xe2\x61\x75\x63\x59\x16\x8c\x9b\x15\x41\x1c\xcd\ +\xed\xba\xc1\x76\x97\xa7\x95\x60\x1c\x4d\x55\xaa\x36\x2a\x2b\x8b\ +\x29\x76\xf1\xd4\xee\xc4\xa3\x4e\x3c\x32\xa3\x27\x0f\x2a\xd2\x9b\ +\x8d\xce\x8a\xaa\x65\x56\xdc\xf6\x84\xf3\x78\xd9\x4a\x1b\x6d\xf6\ +\xb4\x12\xc2\x52\xca\x29\x22\x53\x42\x1c\x90\x70\x8a\x63\x56\x86\ +\x07\xe7\xbc\x29\xe8\x38\xd4\x94\x20\x84\xa6\xc0\xeb\x24\xbf\x4f\ +\x2a\x38\xa4\x00\xc5\x55\x65\x2a\x6e\x7f\x74\x80\x7f\x0b\xbf\x6d\ +\x83\x86\xe0\x16\x7a\x97\x47\x6a\x09\x2d\x95\x9b\xa9\x72\xfa\xf1\ +\xf3\xc7\x96\xe9\x20\x37\x2e\xe3\x5e\x37\x0d\xfa\x67\xe3\x9e\x99\ +\x24\x0b\x37\xaa\xd8\x86\x91\x2a\xa6\x0d\xbd\x6a\xbf\x4f\xe2\x72\ +\x3d\xb7\x39\xdb\x1e\xaa\xfb\xb5\x4a\x56\xeb\xb2\x47\x48\xe2\xb9\ +\x0d\x33\x24\x02\xf3\xea\xbe\xe7\x40\xf8\x24\x50\x77\x17\xb4\x1c\ +\xe4\x32\xe1\x52\x17\x5b\xb9\x14\xe2\xd4\xaa\xd1\x3c\x88\x75\x64\ +\x54\x99\xdb\x7f\xcb\xa3\xf5\xd7\xdf\xb5\x5e\xba\x06\xbf\x3b\x10\ +\x9a\xc5\x6a\x59\x18\xe1\xd3\xa0\xe6\x0e\x46\x15\x15\x0f\xb8\x80\ +\x9c\x0a\xf3\x7f\xe4\x61\x9c\x80\xbf\x9c\xe4\x4e\x92\xe7\x1c\xca\ +\x05\xae\xdb\x40\xab\xa2\xd4\xdb\x46\xb6\x9e\x0c\x50\x28\x97\xbe\ +\xdd\x91\xf5\x72\x59\x28\x98\x34\xea\xd1\x8a\xf2\x98\xaa\x93\xb4\ +\x13\xe9\x54\xe7\xc1\xed\xb2\xfa\x7c\xa8\x48\x1a\xb0\x4c\xca\x63\ +\x80\x3f\xd8\xd6\xf4\xca\x68\x03\x5d\x88\x85\xf9\x79\xd4\xc5\x63\ +\x55\xb0\x3d\xa4\xb5\xf0\xda\xd1\x66\xd3\xf3\x69\xd7\xd4\xd6\x1a\ +\x5b\xb0\xc6\x56\x45\x66\xdd\x34\x3d\xb5\x46\x28\x8f\xc6\x55\xce\ +\x45\x69\xdc\x8e\xd8\x59\x74\xfb\xf5\x00\xa8\x58\x81\x45\x09\xfc\ +\xc1\x83\x12\xc7\x93\x04\x86\xa5\x00\xff\xd0\xa0\xcc\x37\xe3\x50\ +\x4f\x74\x53\x6b\xe0\xe8\x3c\x59\x25\xe0\x41\x95\x1c\xc1\x2e\xad\ +\x3e\xe7\x6d\x00\x8c\xde\xdc\x88\x20\xac\xc3\xe4\xa9\xd9\x5f\x34\ +\xa4\x9c\x90\xe7\x15\x41\xae\x67\x26\x55\x2b\x72\xa9\xca\xf9\x0c\ +\x71\x25\xe9\xfd\x29\xa0\x6a\xb8\x2f\xbb\x79\xce\x72\x3f\x0a\x80\ +\x23\x47\x0e\x81\x47\x47\x0e\x80\xef\x8d\x1c\x80\x5e\x22\x18\x25\ +\x00\x3e\x19\xd0\x61\x54\x00\xb0\x91\xe7\x01\x9f\xb3\x91\x03\x20\ +\x46\x1e\x04\x05\xe2\xa3\x07\xc0\x19\x79\x25\x20\xe8\xc8\x17\x01\ +\xc7\x23\x0f\x83\x00\x80\x23\x46\x0e\x01\x1b\x79\x14\x00\x00\xc6\ +\x1e\x08\xb9\x3f\xf2\x7a\x10\x00\x70\x46\x9e\x0b\x7c\xf4\x1d\x0f\ +\xa9\xde\x38\x00\x63\xcf\x05\x3e\x7b\x83\x45\xf1\x36\x2c\x4b\x95\ +\x67\x4d\xbb\xfa\xf6\x73\x1e\x66\xc5\x52\xe7\x9b\xb9\xbd\x09\xcb\ +\x3c\x39\xbc\x43\x2e\x87\x6d\x21\xf5\x89\x98\x38\xc8\x15\x58\x10\ +\x89\x3d\x6f\x42\x5c\xe6\xf9\x82\x62\x36\xc1\xae\x10\x8c\x79\x1e\ +\x9b\x38\x84\x03\x15\x71\xc4\x27\x58\xb8\x44\x32\xc9\xfc\xf7\xe7\ +\x8f\x6b\x4f\xa3\x78\x84\x76\x1a\x57\x2f\x42\x82\x75\xae\x96\x73\ +\xfb\xf6\x13\x8c\xb9\x2d\xf0\x57\xec\x0c\x94\x60\x91\x4e\x53\x30\ +\xc9\xdc\x0e\xd3\x7d\x78\x2c\x7e\xc8\x98\x1e\x21\x6f\xb0\xb8\xbb\ +\x30\x66\x2b\x58\x94\x3a\xba\x37\x08\x54\xb8\xaa\xc2\xc2\xc1\xf9\ +\xf3\xf3\x21\xbc\x9f\x72\x05\xee\x83\x23\x30\x3a\x71\xb0\x8b\x10\ +\xc4\x06\x51\x79\x02\xe1\x58\xf8\x02\xae\x28\xc6\xcc\x63\x62\x42\ +\x5d\xe6\x73\x24\x85\x0f\x57\x1e\x65\x92\xd0\xce\x0f\x9a\xf7\x4a\ +\x9d\x22\xf5\x9b\x27\x72\xa9\xc1\x97\x2c\x29\x8b\xb9\xbd\x2b\x54\ +\xfe\xc9\xbc\xb0\xfa\x77\xf6\xa5\x50\xcf\xbb\x45\xfb\x0e\x26\x07\ +\x6a\x23\x7d\x9a\xae\xa1\x30\x26\x68\x6f\xb6\x9d\x42\xa4\x47\xab\ +\x55\xea\xbf\x7b\x01\x3b\xc2\x02\xf0\x7a\x94\xc3\xe0\x7b\xa2\x65\ +\x92\xa6\xc1\x22\x0d\xa3\xfb\x0f\x45\x99\xeb\x7b\x15\x64\x3a\x53\ +\xbd\xb7\x35\xf5\xec\x7e\xcc\x77\xdf\xe2\x73\xfa\x17\x84\xa2\xef\ +\xf5\x3f\xe9\x02\x89\x0a\x3c\x11\xae\xe4\x92\x08\xc4\xae\x06\xa2\ +\x9e\x2f\x5c\x09\x45\x03\xd1\xff\xb5\x42\xd1\x5b\x2c\xb1\x5f\x21\ +\x18\xf1\x51\x05\x23\xf4\xd3\x04\xa3\x97\xac\x44\x0f\x53\x2a\x48\ +\x05\x3e\xa7\x98\x48\x69\xc0\xc7\x50\x2c\x20\x6a\xae\x18\x14\x0a\ +\x3e\xd8\x86\x49\xd7\xe7\xc4\xe3\x86\x2d\x3d\xc6\x05\xba\x56\x13\ +\x48\x3e\xbc\x10\xfb\x6b\x75\x60\xb9\xbc\xce\x52\x14\x6f\xb0\xc6\ +\x7d\xfd\xb8\x6a\x2a\x3c\x4a\x39\x88\x4e\x30\x14\x83\xc2\xc7\xf2\ +\x7a\x85\xd7\x33\xd6\xb5\x1a\xef\x45\xf6\x7c\x8d\x22\xa7\x37\xe0\ +\x18\x22\x0b\xeb\x45\xd2\xff\x9d\xd8\xc2\x00\x7b\x26\x04\x37\x1b\ +\x0e\x4e\x60\xb7\x21\x98\x84\x6d\x86\xe7\x41\x70\xe1\x3e\x5c\x31\ +\x8a\xa9\xe4\x13\xe2\xbb\x92\x09\x66\xf6\x20\xd4\xa5\x88\x33\x8f\ +\x0f\x3b\x23\xa5\xe8\x39\x57\x1c\x28\xab\x5e\x25\xb0\x50\xf2\xff\ +\x0c\xdf\x21\x33\x84\xf7\x18\xd6\x21\xfd\x69\x56\xe1\x8b\x7c\x97\ +\x8f\xfb\xd9\x97\x47\xc5\x1b\x5c\xbc\x2f\x01\x80\xe1\x37\xe8\x01\ +\x57\x8e\x8f\x5e\x5b\xdf\x83\x89\x63\xe0\xa0\x69\x1f\xc3\x4b\xb6\ +\xec\xd6\xf1\x01\xcf\x6d\xea\xbb\x42\x42\x96\xeb\x0e\x1c\x1d\x81\ +\xca\xcc\x69\x59\xe6\xf7\x5e\x3a\x1c\xc8\xdc\xe6\xc4\x45\x4c\xf8\ +\x7e\x17\x30\x8f\x86\x8a\x5c\xa8\xb0\x30\xee\x7a\x58\xd5\x83\x3d\ +\x1d\xc5\x1a\xa9\xa1\x68\x4b\x18\x21\x3e\xc2\xf2\x94\x76\x99\x87\ +\x7d\x49\x26\x55\xa5\xcf\x29\x82\x74\x0b\x12\xc4\x87\x34\x4b\xbc\ +\x89\xe7\x72\xc4\x24\xf2\xc4\x84\x11\x17\x88\x98\x8a\xf7\x35\xc0\ +\xb3\xa9\x39\xae\x5b\x5d\xb5\x16\x31\xe7\x7c\xe3\x87\x44\xed\x6f\ +\x5a\x84\x16\x61\xab\xd5\x36\x5c\xa9\xea\x50\x2c\xe0\x7a\x3a\x58\ +\x5b\x33\x16\x3a\x8f\x55\xde\xb0\x78\xf5\x39\x63\xd5\xe7\x66\x4f\ +\x47\xd8\x6f\x2e\xbc\x14\x7a\x6d\xf9\x68\x98\x5f\xac\xc3\x58\xef\ +\xbb\x50\xdc\x32\xbf\x69\x0d\xc8\x50\xa8\x70\x25\x12\xfe\x23\x76\ +\x04\x2e\xe8\x60\xd8\xcf\x10\xea\xfb\xec\x11\xd7\x28\xc4\x5c\x28\ +\x8d\x05\xc1\x8f\x98\xbb\x3c\x07\xfc\x9d\x34\x3c\x2a\x98\x55\xf5\ +\xaf\x11\x2a\xd6\x7a\xbf\xca\x0d\x3a\x65\xbe\x53\x97\x2d\x63\x1d\ +\xed\xcc\xf9\x78\x67\x77\xb2\x70\x7d\x2a\xbb\x27\x61\xda\x3a\x8b\ +\x85\x3e\x0c\x77\x50\x64\xe1\xf6\x09\xb6\xe1\x38\x90\x2c\xd6\xc5\ +\x13\xfc\x4c\xc7\xea\x0a\xbf\xed\xde\x51\xf1\x4a\x39\x9b\x24\xde\ +\xea\x24\x2b\x9f\x95\x7e\x46\x50\x2f\xfe\x80\xd5\xf8\x94\x62\xb5\ +\xc4\x13\xaa\xed\x93\x0c\xec\xec\x34\x59\x96\x88\x47\xde\x50\x4b\ +\x34\xb9\xd9\xf7\xc4\x15\x89\x5e\x12\xbe\x64\x19\xb3\xcb\x2b\xbc\ +\x4d\x78\x48\x36\xc9\x37\x15\x9b\xe6\xf5\x42\xd9\xa8\x32\x8c\xc3\ +\x32\xec\x16\x45\x43\x21\xc6\x71\xea\x68\x95\xc7\xcb\xe0\xf7\x8f\ +\xbf\xb6\x55\x46\x14\x05\xff\xd1\xf9\x7d\x57\x07\x18\x81\x70\xa1\ +\x77\xa0\x76\x5b\x8b\x98\x23\xf4\x51\x60\xd6\x77\x58\xde\x25\x1b\ +\x70\x75\xf3\xdd\x84\xbf\x1e\x36\x29\x2c\xcf\x96\x71\x26\x6c\xa2\ +\x66\xd7\xe9\xa9\xdb\x5c\x9d\xbe\x7b\x30\xf8\x75\x8d\x38\xda\x24\ +\xa6\xd1\xf4\x53\x09\x25\xc8\x6f\x66\x90\xde\x01\xf8\xba\xd3\xa4\ +\x4c\xd5\x5d\x35\xe6\xe9\xb2\x99\xc5\xb4\x9e\x46\x53\xa4\xf4\x66\ +\x39\x9b\x36\x30\x54\x77\xab\x0e\x9e\xb3\xc5\xd2\x22\x9c\x86\x0b\ +\x95\xce\xed\x7f\x1a\xa6\xf5\x88\xbb\xca\xf5\x6e\xbb\x01\xd7\xa8\ +\x9b\xdb\x5d\x09\xbb\x6e\x33\x47\xaf\x92\xba\xe5\x0b\xf3\xf3\xc1\ +\xdc\xf4\xce\xe5\xd7\xa5\xd5\x2d\xaa\x3e\xf5\xed\xc9\xa1\x02\xda\ +\xdc\x9a\xa8\x0f\x83\x06\x8b\x5d\x59\xf6\x69\x7f\x80\x7b\x07\xa0\ +\x47\x16\x37\x54\x40\x4e\xe5\x29\x78\x44\x19\xb0\x86\x76\x39\x98\ +\x13\x87\x10\x9f\xf2\x3c\x3c\x9e\x2a\xba\x46\x5b\x00\xe2\x5f\x16\ +\x81\xb0\x4c\x25\xf2\xf9\x84\x79\xae\x27\xb8\x8f\x88\x05\xa1\x58\ +\x20\xe9\x49\xa8\x91\xa9\x8b\x89\xe7\x21\x6c\x31\x09\x1b\x23\xe9\ +\x63\x7f\x22\x5d\x09\xc1\x4c\x52\x8b\x40\x1c\xc7\xb0\xa5\x22\x13\ +\x02\x61\xdc\x83\x2c\x44\xad\x6f\x97\xdb\xa6\x35\x91\x68\x20\xfb\ +\x46\x3a\x83\x29\x96\x3a\x77\x20\x8e\x3d\x84\xe5\x2e\x57\xfd\xa2\ +\xb4\x0b\xf8\x00\xb8\xf1\x0d\x58\x8f\x91\xf9\x9c\x6d\x1d\x06\x71\ +\x07\xc7\x7a\xf7\x28\xab\x4a\xef\xfd\xcf\x6e\x88\x01\x80\x4d\xc6\ +\x26\x98\x51\x3a\x21\xdc\x3c\xf2\x82\x0c\x62\x51\x0f\x68\x3e\x24\ +\xf7\x89\x07\x56\x32\x89\xfb\x7b\xed\x20\xe4\xe0\xe3\xe7\x3f\x65\ +\x87\xd9\x74\x75\x77\x33\x33\x21\xe1\xee\xe6\xbf\x41\x63\xea\xe4\ +\ \x00\x00\x06\xdd\ \x00\ \x00\x22\x8f\x78\x9c\xed\x59\xdb\x6e\xe3\x46\x12\x7d\xf7\x57\xf4\ @@ -10327,6 +10578,10 @@ qt_resource_name = "\ \x00\x72\x00\x63\x00\x68\x00\x5f\x00\x53\x00\x70\x00\x6c\x00\x69\x00\x74\x00\x4d\x00\x65\x00\x73\x00\x68\x00\x2e\x00\x73\x00\x76\ \x00\x67\ \x00\x0d\ +\x07\x4a\x92\xc7\ +\x00\x41\ +\x00\x72\x00\x63\x00\x68\x00\x5f\x00\x52\x00\x6f\x00\x6f\x00\x66\x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x0d\ \x01\xb7\x92\xa7\ \x00\x41\ \x00\x72\x00\x63\x00\x68\x00\x5f\x00\x53\x00\x69\x00\x74\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\ @@ -10373,6 +10628,11 @@ qt_resource_name = "\ \x00\x41\ \x00\x72\x00\x63\x00\x68\x00\x5f\x00\x46\x00\x6c\x00\x6f\x00\x6f\x00\x72\x00\x5f\x00\x54\x00\x72\x00\x65\x00\x65\x00\x2e\x00\x73\ \x00\x76\x00\x67\ +\x00\x12\ +\x08\x61\x2a\xa7\ +\x00\x41\ +\x00\x72\x00\x63\x00\x68\x00\x5f\x00\x52\x00\x6f\x00\x6f\x00\x66\x00\x5f\x00\x54\x00\x72\x00\x65\x00\x65\x00\x2e\x00\x73\x00\x76\ +\x00\x67\ \x00\x14\ \x02\xc8\x0e\x47\ \x00\x41\ @@ -10382,8 +10642,8 @@ qt_resource_name = "\ qt_resource_struct = "\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x01\ -\x00\x00\x00\x10\x00\x02\x00\x00\x00\x01\x00\x00\x00\x2d\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x18\x00\x00\x00\x15\ +\x00\x00\x00\x10\x00\x02\x00\x00\x00\x01\x00\x00\x00\x2f\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1a\x00\x00\x00\x15\ \x00\x00\x00\x1a\x00\x02\x00\x00\x00\x11\x00\x00\x00\x04\ \x00\x00\x01\xd8\x00\x00\x00\x00\x00\x01\x00\x01\x60\x78\ \x00\x00\x00\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x55\x20\ @@ -10402,29 +10662,31 @@ qt_resource_struct = "\ \x00\x00\x01\x8a\x00\x00\x00\x00\x00\x01\x00\x01\x1d\x6e\ \x00\x00\x00\xba\x00\x00\x00\x00\x00\x01\x00\x00\x6c\x7e\ \x00\x00\x00\x38\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x05\x2c\x00\x01\x00\x00\x00\x01\x00\x02\x43\x52\ -\x00\x00\x04\x38\x00\x00\x00\x00\x00\x01\x00\x02\x05\x83\ -\x00\x00\x03\x16\x00\x00\x00\x00\x00\x01\x00\x01\xb7\x11\ -\x00\x00\x05\xcc\x00\x01\x00\x00\x00\x01\x00\x02\x6e\xe4\ -\x00\x00\x04\xfe\x00\x01\x00\x00\x00\x01\x00\x02\x3c\x80\ -\x00\x00\x03\x50\x00\x01\x00\x00\x00\x01\x00\x01\xc5\x80\ -\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x01\xd9\x07\ +\x00\x00\x05\x4c\x00\x01\x00\x00\x00\x01\x00\x02\x4b\x1c\ +\x00\x00\x04\x58\x00\x00\x00\x00\x00\x01\x00\x02\x0d\x4d\ +\x00\x00\x03\x16\x00\x00\x00\x00\x00\x01\x00\x01\xb7\x13\ +\x00\x00\x06\x16\x00\x01\x00\x00\x00\x01\x00\x02\x7e\x42\ +\x00\x00\x05\x1e\x00\x01\x00\x00\x00\x01\x00\x02\x44\x4a\ +\x00\x00\x03\x50\x00\x01\x00\x00\x00\x01\x00\x01\xc5\x82\ +\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x01\xd9\x09\ \x00\x00\x02\xba\x00\x01\x00\x00\x00\x01\x00\x01\x9c\x71\ -\x00\x00\x04\x78\x00\x00\x00\x00\x00\x01\x00\x02\x1f\x5d\ +\x00\x00\x04\x98\x00\x00\x00\x00\x00\x01\x00\x02\x27\x27\ +\x00\x00\x04\x38\x00\x01\x00\x00\x00\x01\x00\x02\x05\x85\ \x00\x00\x02\x98\x00\x01\x00\x00\x00\x01\x00\x01\x93\x78\ -\x00\x00\x03\x7e\x00\x01\x00\x00\x00\x01\x00\x01\xce\xd8\ +\x00\x00\x05\xec\x00\x01\x00\x00\x00\x01\x00\x02\x76\xad\ +\x00\x00\x03\x7e\x00\x01\x00\x00\x00\x01\x00\x01\xce\xda\ \x00\x00\x02\x4e\x00\x01\x00\x00\x00\x01\x00\x01\x82\xd0\ \x00\x00\x02\x78\x00\x01\x00\x00\x00\x01\x00\x01\x8c\x78\ -\x00\x00\x04\xa8\x00\x01\x00\x00\x00\x01\x00\x02\x2e\xcb\ -\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x01\xf5\x02\ -\x00\x00\x04\xd6\x00\x01\x00\x00\x00\x01\x00\x02\x34\x1b\ -\x00\x00\x05\x56\x00\x00\x00\x00\x00\x01\x00\x02\x4a\x2d\ -\x00\x00\x03\xc6\x00\x01\x00\x00\x00\x01\x00\x01\xde\x1e\ -\x00\x00\x05\xa0\x00\x01\x00\x00\x00\x01\x00\x02\x66\x6a\ -\x00\x00\x05\x80\x00\x01\x00\x00\x00\x01\x00\x02\x5c\x30\ -\x00\x00\x04\x58\x00\x01\x00\x00\x00\x01\x00\x02\x19\x45\ +\x00\x00\x04\xc8\x00\x01\x00\x00\x00\x01\x00\x02\x36\x95\ +\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x01\xf5\x04\ +\x00\x00\x04\xf6\x00\x01\x00\x00\x00\x01\x00\x02\x3b\xe5\ +\x00\x00\x05\x76\x00\x00\x00\x00\x00\x01\x00\x02\x51\xf6\ +\x00\x00\x03\xc6\x00\x01\x00\x00\x00\x01\x00\x01\xde\x20\ +\x00\x00\x05\xc0\x00\x01\x00\x00\x00\x01\x00\x02\x6e\x33\ +\x00\x00\x05\xa0\x00\x01\x00\x00\x00\x01\x00\x02\x63\xf9\ +\x00\x00\x04\x78\x00\x01\x00\x00\x00\x01\x00\x02\x21\x0f\ \x00\x00\x02\xec\x00\x00\x00\x00\x00\x01\x00\x01\xa4\xb3\ -\x00\x00\x03\xf0\x00\x00\x00\x00\x00\x01\x00\x01\xe6\x06\ +\x00\x00\x03\xf0\x00\x00\x00\x00\x00\x01\x00\x01\xe6\x08\ \x00\x00\x02\x1a\x00\x01\x00\x00\x00\x01\x00\x01\x7b\x80\ \x00\x00\x01\xf2\x00\x01\x00\x00\x00\x01\x00\x01\x76\xac\ " diff --git a/src/Mod/Arch/CMakeLists.txt b/src/Mod/Arch/CMakeLists.txt index a7522a413..fcfd728bb 100644 --- a/src/Mod/Arch/CMakeLists.txt +++ b/src/Mod/Arch/CMakeLists.txt @@ -20,6 +20,7 @@ SET(Arch_SRCS ArchWindow.py ArchAxis.py ArchVRM.py + ArchRoof.py ) SOURCE_GROUP("" FILES ${Arch_SRCS}) diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 066ee12b8..52bf67165 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -61,7 +61,7 @@ class ArchWorkbench(Workbench): self.archtools = ["Arch_Wall","Arch_Structure","Arch_Cell", "Arch_Floor","Arch_Building","Arch_Site", "Arch_Window","Arch_Axis", - "Arch_SectionPlane","Arch_Add","Arch_Remove"] + "Arch_SectionPlane","Arch_Roof","Arch_Add","Arch_Remove"] self.drafttools = ["Draft_Line","Draft_Wire","Draft_Rectangle", "Draft_Polygon","Draft_Arc", "Draft_Circle","Draft_Dimension", diff --git a/src/Mod/Arch/Makefile.am b/src/Mod/Arch/Makefile.am index 61917f8f7..e30ec2a6a 100644 --- a/src/Mod/Arch/Makefile.am +++ b/src/Mod/Arch/Makefile.am @@ -27,7 +27,8 @@ data_DATA = \ ArchWindow.py \ ArchCommands.py \ ArchAxis.py \ - ArchVRM.py + ArchVRM.py \ + ArchRoof.py CLEANFILES = $(BUILT_SOURCES) diff --git a/src/WindowsInstaller/ModArch.wxi b/src/WindowsInstaller/ModArch.wxi index 094c7c617..f8bdd05c8 100644 --- a/src/WindowsInstaller/ModArch.wxi +++ b/src/WindowsInstaller/ModArch.wxi @@ -45,6 +45,7 @@ + From 03fa473ac24ceaf2946e5530fcb2d2857a2a5a68 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 18 May 2012 19:07:27 +0200 Subject: [PATCH 13/42] Mesh segmentation --- src/Mod/Mesh/App/Core/Segmentation.cpp | 14 ++++++++++++-- src/Mod/Mesh/App/Core/Segmentation.h | 8 +++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Mod/Mesh/App/Core/Segmentation.cpp b/src/Mod/Mesh/App/Core/Segmentation.cpp index 450a7a067..2e86fdb17 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.cpp +++ b/src/Mod/Mesh/App/Core/Segmentation.cpp @@ -35,6 +35,10 @@ void MeshSurfaceSegment::Initialize(unsigned long) { } +void MeshSurfaceSegment::AddFacet(const MeshFacet&) +{ +} + void MeshSurfaceSegment::AddSegment(const std::vector& segm) { if (segm.size() >= minFacets) { @@ -76,10 +80,15 @@ bool MeshDistancePlanarSegment::TestFacet (const MeshFacet& face) const return false; } - fitter->AddPoint(triangle.GetGravityPoint()); return true; } +void MeshDistancePlanarSegment::AddFacet(const MeshFacet& face) +{ + MeshGeomFacet triangle = kernel.GetFacet(face); + fitter->AddPoint(triangle.GetGravityPoint()); +} + // -------------------------------------------------------- bool MeshCurvaturePlanarSegment::TestFacet (const MeshFacet &rclFacet) const @@ -153,7 +162,7 @@ bool MeshCurvatureFreeformSegment::TestFacet (const MeshFacet &rclFacet) const // -------------------------------------------------------- -MeshSurfaceVisitor::MeshSurfaceVisitor (const MeshSurfaceSegment& segm, std::vector &indices) +MeshSurfaceVisitor::MeshSurfaceVisitor (MeshSurfaceSegment& segm, std::vector &indices) : indices(indices), segm(segm) { } @@ -172,6 +181,7 @@ bool MeshSurfaceVisitor::Visit (const MeshFacet & face, const MeshFacet &, unsigned long ulFInd, unsigned long) { indices.push_back(ulFInd); + segm.AddFacet(face); return true; } diff --git a/src/Mod/Mesh/App/Core/Segmentation.h b/src/Mod/Mesh/App/Core/Segmentation.h index 021961001..561385c1c 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.h +++ b/src/Mod/Mesh/App/Core/Segmentation.h @@ -42,6 +42,7 @@ public: virtual ~MeshSurfaceSegment() {} virtual bool TestFacet (const MeshFacet &rclFacet) const = 0; virtual void Initialize(unsigned long); + virtual void AddFacet(const MeshFacet& rclFacet); void AddSegment(const std::vector&); const std::vector& GetSegments() const { return segments; } @@ -68,8 +69,9 @@ class MeshExport MeshDistancePlanarSegment : public MeshDistanceSurfaceSegment public: MeshDistancePlanarSegment(const MeshKernel& mesh, unsigned long minFacets, float tol); virtual ~MeshDistancePlanarSegment(); - bool TestFacet (const MeshFacet &rclFacet) const; + bool TestFacet (const MeshFacet& rclFacet) const; void Initialize(unsigned long); + void AddFacet(const MeshFacet& rclFacet); protected: Base::Vector3f basepoint; @@ -134,7 +136,7 @@ private: class MeshExport MeshSurfaceVisitor : public MeshFacetVisitor { public: - MeshSurfaceVisitor (const MeshSurfaceSegment& segm, std::vector &indices); + MeshSurfaceVisitor (MeshSurfaceSegment& segm, std::vector &indices); virtual ~MeshSurfaceVisitor (); bool AllowVisit (const MeshFacet& face, const MeshFacet&, unsigned long, unsigned long, unsigned short neighbourIndex); @@ -143,7 +145,7 @@ public: protected: std::vector &indices; - const MeshSurfaceSegment& segm; + MeshSurfaceSegment& segm; }; class MeshExport MeshSegmentAlgorithm From 6d8de2f1ab8e179010d92083a5cbaa6af5555bc2 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 18 May 2012 15:59:53 -0300 Subject: [PATCH 14/42] Cleaning in the Arch module --- src/Mod/Arch/ArchSectionPlane.py | 9 ++++++--- src/Mod/Arch/ArchWindow.py | 18 ++++++++++-------- src/Mod/Arch/InitGui.py | 16 +++++++++++----- src/Mod/Arch/importIFC.py | 4 ++-- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/Mod/Arch/ArchSectionPlane.py b/src/Mod/Arch/ArchSectionPlane.py index d4ae54c21..886cbb348 100644 --- a/src/Mod/Arch/ArchSectionPlane.py +++ b/src/Mod/Arch/ArchSectionPlane.py @@ -34,7 +34,7 @@ class _CommandSectionPlane: return {'Pixmap' : 'Arch_SectionPlane', 'Accel': "S, P", 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_SectionPlane","Section Plane"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_SectionPlane","Adds a section plane object to the document")} + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_SectionPlane","Creates a section plane object, including the selected objects")} def Activated(self): sel = FreeCADGui.Selection.getSelection() @@ -47,6 +47,8 @@ class _CommandSectionPlane: for o in sel: if o.isDerivedFrom("Part::Feature"): g.append(o) + elif o.isDerivedFrom("App::DocumentObjectGroup"): + g.append(o) obj.Objects = g page = FreeCAD.ActiveDocument.addObject("Drawing::FeaturePage","Page") template = Draft.getParam("template") @@ -179,6 +181,7 @@ class _ArchDrawingView: if hasattr(obj,"Source"): if obj.Source: if obj.Source.Objects: + objs = Draft.getGroupContents(obj.Sourc.Objects) svg = '' # generating SVG @@ -188,7 +191,7 @@ class _ArchDrawingView: import ArchVRM render = ArchVRM.Renderer() render.setWorkingPlane(obj.Source.Placement) - render.addObjects(obj.Source.Objects) + render.addObjects(objs) render.cut(obj.Source.Shape) svg += render.getViewSVG(linewidth=linewidth) svg += render.getSectionSVG(linewidth=linewidth*2) @@ -197,7 +200,7 @@ class _ArchDrawingView: else: # render using the Drawing module shapes = [] - for o in obj.Source.Objects: + for o in objs: if o.isDerivedFrom("Part::Feature"): shapes.append(o.Shape) if shapes: diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 382d9e3f9..2cdf513c9 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -78,17 +78,19 @@ class _CommandWindow: return {'Pixmap' : 'Arch_Window', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Window","Window"), 'Accel': "W, N", - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Window","Creates a window object from scratch or from a selected object (wire, rectangle or sketch)")} + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Window","Creates a window object from a selected object (wire, rectangle or sketch)")} + + def IsActive(self): + if FreeCADGui.Selection.getSelection(): + return True + else: + return False def Activated(self): sel = FreeCADGui.Selection.getSelection() - FreeCAD.ActiveDocument.openTransaction("Window") - if sel: - for obj in sel: - makeWindow(obj) - else: - rect = Draft.makeRectangle(1,1) - makeWindow(rect) + FreeCAD.ActiveDocument.openTransaction("Create Window") + for obj in sel: + makeWindow(obj) FreeCAD.ActiveDocument.commitTransaction() class _Window(ArchComponent.Component): diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 52bf67165..1de87ed47 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -58,10 +58,10 @@ class ArchWorkbench(Workbench): def Initialize(self): import DraftTools,DraftGui,Arch_rc,Arch - self.archtools = ["Arch_Wall","Arch_Structure","Arch_Cell", + self.archtools = ["Arch_Wall","Arch_Structure", "Arch_Floor","Arch_Building","Arch_Site", - "Arch_Window","Arch_Axis", - "Arch_SectionPlane","Arch_Roof","Arch_Add","Arch_Remove"] + "Arch_Window","Arch_Roof","Arch_Axis", + "Arch_SectionPlane","Arch_Add","Arch_Remove"] self.drafttools = ["Draft_Line","Draft_Wire","Draft_Rectangle", "Draft_Polygon","Draft_Arc", "Draft_Circle","Draft_Dimension", @@ -100,6 +100,12 @@ class ArchWorkbench(Workbench): FreeCADGui.addWorkbench(ArchWorkbench) FreeCAD.addImportType("Industry Foundation Classes (*.ifc)","importIFC") FreeCAD.addExportType("Wavefront OBJ - Arch module (*.obj)","importOBJ") -FreeCAD.addImportType("Collada (*.dae)","importDAE") -FreeCAD.addExportType("Collada (*.dae)","importDAE") +# check for pycollada +try: + import collada +except: + FreeCAD.Console.PrintError("pycollada not found, no collada support.\n") +else: + FreeCAD.addImportType("Collada (*.dae)","importDAE") + FreeCAD.addExportType("Collada (*.dae)","importDAE") diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index f4a8f8392..7a0cf8ae0 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -108,7 +108,7 @@ def getIfcOpenShell(): return True def read(filename): - "Parses an IFC file with IfcOpenShell" + "Parses an IFC file" # parsing the IFC file t1 = time.time() @@ -186,7 +186,7 @@ def read(filename): IfcImport.CleanUp() else: - # use the internal python parser + # use only the internal python parser # getting walls for w in ifc.getEnt("IfcWallStandardCase"): From 8b191077923aea4e5afc1025967d282c2f6b2c83 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 18 May 2012 16:43:48 -0300 Subject: [PATCH 15/42] Fixed 0000708 - Draft DXF import --- src/Mod/Draft/importDXF.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index a03ec28aa..97e01db7f 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -1232,7 +1232,9 @@ def getWire(wire,nospline=False): points = [] for edge in edges: v1 = edge.Vertexes[0].Point - if (isinstance(edge.Curve,Part.Circle)): + if len(edge.Vertexes) < 2: + points.append((v1.x,v1.y,v1.z,None,None,0.0)) + elif (isinstance(edge.Curve,Part.Circle)): mp = fcgeo.findMidpoint(edge) v2 = edge.Vertexes[-1].Point c = edge.Curve.Center @@ -1251,14 +1253,12 @@ def getWire(wire,nospline=False): bul = -bul points.append((v1.x,v1.y,v1.z,None,None,bul)) elif (isinstance(edge.Curve,Part.BSplineCurve)) and (not nospline): - bul = 0.0 spline = getSplineSegs(edge) spline.pop() for p in spline: - points.append((p.x,p.y,p.z,None,None,bul)) + points.append((p.x,p.y,p.z,None,None,0.0)) else: - bul = 0.0 - points.append((v1.x,v1.y,v1.z,None,None,bul)) + points.append((v1.x,v1.y,v1.z,None,None,0.0)) if not fcgeo.isReallyClosed(wire): v = edges[-1].Vertexes[-1].Point points.append(fcvec.tup(v)) From d56e08e47fadd9006994988c69bcc7e1d05c816a Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 18 May 2012 17:43:57 -0300 Subject: [PATCH 16/42] Refining of Arch Roof tool --- src/Mod/Arch/ArchComponent.py | 2 -- src/Mod/Arch/ArchRoof.py | 21 ++++++++++++++++++--- src/Mod/Arch/ArchStructure.py | 2 ++ src/Mod/Arch/ArchWall.py | 2 ++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py index b6065fa04..c9fa5a347 100644 --- a/src/Mod/Arch/ArchComponent.py +++ b/src/Mod/Arch/ArchComponent.py @@ -260,8 +260,6 @@ class Component: "Other shapes that are appended to this wall") obj.addProperty("App::PropertyLinkList","Subtractions","Base", "Other shapes that are subtracted from this wall") - obj.addProperty("App::PropertyVector","Normal","Base", - "The normal extrusion direction of this wall (keep (0,0,0) for automatic normal)") obj.Proxy = self self.Type = "Component" self.Subvolume = None diff --git a/src/Mod/Arch/ArchRoof.py b/src/Mod/Arch/ArchRoof.py index 62850f243..37d06b58e 100644 --- a/src/Mod/Arch/ArchRoof.py +++ b/src/Mod/Arch/ArchRoof.py @@ -61,13 +61,30 @@ class _CommandRoof: sel = FreeCADGui.Selection.getSelectionEx() if sel: sel = sel[0] + obj = sel.Object if sel.HasSubObjects: if "Face" in sel.SubElementNames[0]: - obj = sel.Object idx = int(sel.SubElementNames[0][4:]) FreeCAD.ActiveDocument.openTransaction("Create Roof") makeRoof(obj,idx) FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + elif obj.isDerivedFrom("Part::Feature"): + if len(obj.Shape.Faces) == 1: + FreeCAD.ActiveDocument.openTransaction("Create Roof") + makeRoof(obj,1) + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + elif obj.isDerivedFrom("Part::Feature"): + if len(obj.Shape.Faces) == 1: + FreeCAD.ActiveDocument.openTransaction("Create Roof") + makeRoof(obj,1) + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + else: + FreeCAD.Console.PrintMessage("Unable to create a roof") + else: + FreeCAD.Console.PrintMessage("No object selected") class _Roof(ArchComponent.Component): "The Roof object" @@ -77,8 +94,6 @@ class _Roof(ArchComponent.Component): "The angle of this roof") obj.addProperty("App::PropertyInteger","Face","Base", "The face number of the base object used to build this roof") - obj.addProperty("App::PropertyLink","Base","Base", - "The base object this roof is built on") self.Type = "Structure" def execute(self,obj): diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py index 63d7b668c..cd87115eb 100644 --- a/src/Mod/Arch/ArchStructure.py +++ b/src/Mod/Arch/ArchStructure.py @@ -86,6 +86,8 @@ class _Structure(ArchComponent.Component): "The height or extrusion depth of this element. Keep 0 for automatic") obj.addProperty("App::PropertyLinkList","Axes","Base", "Axes systems this structure is built on") + obj.addProperty("App::PropertyVector","Normal","Base", + "The normal extrusion direction of this object (keep (0,0,0) for automatic normal)") self.Type = "Structure" def execute(self,obj): diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index 108edabfc..36c33e7a8 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -251,6 +251,8 @@ class _Wall(ArchComponent.Component): "The height of this wall. Keep 0 for automatic. Not used if this wall is based on a solid") obj.addProperty("App::PropertyEnumeration","Align","Base", "The alignment of this wall on its base object, if applicable") + obj.addProperty("App::PropertyVector","Normal","Base", + "The normal extrusion direction of this object (keep (0,0,0) for automatic normal)") obj.Align = ['Left','Right','Center'] self.Type = "Wall" obj.Width = 0.1 From bd43641457770d651527dc8e11b99ec090381d85 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 18 May 2012 19:01:01 -0300 Subject: [PATCH 17/42] Bugfixes in Arch --- src/Mod/Arch/ArchSectionPlane.py | 2 +- src/Mod/Arch/ArchVRM.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Mod/Arch/ArchSectionPlane.py b/src/Mod/Arch/ArchSectionPlane.py index 886cbb348..d1c1ada50 100644 --- a/src/Mod/Arch/ArchSectionPlane.py +++ b/src/Mod/Arch/ArchSectionPlane.py @@ -181,7 +181,7 @@ class _ArchDrawingView: if hasattr(obj,"Source"): if obj.Source: if obj.Source.Objects: - objs = Draft.getGroupContents(obj.Sourc.Objects) + objs = Draft.getGroupContents(obj.Source.Objects) svg = '' # generating SVG diff --git a/src/Mod/Arch/ArchVRM.py b/src/Mod/Arch/ArchVRM.py index c89776e62..f7e5988ab 100644 --- a/src/Mod/Arch/ArchVRM.py +++ b/src/Mod/Arch/ArchVRM.py @@ -177,7 +177,8 @@ class Renderer: v = self.wp.getLocalCoords(v) verts.append(v) verts.append(verts[0]) - wires.append(Part.makePolygon(verts)) + if len(verts) > 2: + wires.append(Part.makePolygon(verts)) try: sh = ArchCommands.makeFace(wires) except: From 75a9c444ede4202980eb2acfc109b5198abfc18b Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 19 May 2012 18:07:09 -0300 Subject: [PATCH 18/42] Allowed to drag&drop items on python groups too in tree --- src/Gui/Tree.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 03ca7cb2f..2c5f0ea15 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -440,20 +440,39 @@ void TreeWidget::dropEvent(QDropEvent *event) ::getGroupOfObject(obj); if (par) { // allow an object to be in one group only - QString cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").removeObject(" + QString cmd; + if (par->getTypeId().isDerivedFrom(App::DocumentObjectGroupPython::getClassTypeId())) { + // if this is a python group, call the method of its Proxy + cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").Proxy.removeObject(" "App.getDocument(\"%1\").getObject(\"%3\"))") .arg(QString::fromAscii(doc->getName())) .arg(QString::fromAscii(par->getNameInDocument())) .arg(QString::fromAscii(obj->getNameInDocument())); + } else { + cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").removeObject(" + "App.getDocument(\"%1\").getObject(\"%3\"))") + .arg(QString::fromAscii(doc->getName())) + .arg(QString::fromAscii(par->getNameInDocument())) + .arg(QString::fromAscii(obj->getNameInDocument())); + } Gui::Application::Instance->runPythonCode(cmd.toUtf8()); } // build Python command for execution - QString cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").addObject(" + QString cmd; + if (grp->getTypeId().isDerivedFrom(App::DocumentObjectGroupPython::getClassTypeId())) { + cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").Proxy.addObject(" "App.getDocument(\"%1\").getObject(\"%3\"))") .arg(QString::fromAscii(doc->getName())) .arg(QString::fromAscii(grp->getNameInDocument())) .arg(QString::fromAscii(obj->getNameInDocument())); + } else { + cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").addObject(" + "App.getDocument(\"%1\").getObject(\"%3\"))") + .arg(QString::fromAscii(doc->getName())) + .arg(QString::fromAscii(grp->getNameInDocument())) + .arg(QString::fromAscii(obj->getNameInDocument())); + } Gui::Application::Instance->runPythonCode(cmd.toUtf8()); } gui->commitCommand(); From dcc7eea7149f385b9f801ae553ebbfbf980a652d Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 19 May 2012 18:18:02 -0300 Subject: [PATCH 19/42] Made Arch groups able to receive drops from the tree --- src/Mod/Arch/ArchBuilding.py | 19 +++++++++++++++++-- src/Mod/Arch/ArchFloor.py | 16 +++++++++++++++- src/Mod/Arch/ArchSite.py | 19 +++++++++++++++++-- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/Mod/Arch/ArchBuilding.py b/src/Mod/Arch/ArchBuilding.py index 6a2cb2c33..f8ed4e8ca 100644 --- a/src/Mod/Arch/ArchBuilding.py +++ b/src/Mod/Arch/ArchBuilding.py @@ -68,12 +68,27 @@ class _Building: def __init__(self,obj): self.Type = "Building" obj.Proxy = self - + self.Object = obj + def execute(self,obj): - pass + self.Object = obj def onChanged(self,obj,prop): pass + + def addObject(self,child): + if hasattr(self,"Object"): + g = self.Object.Group + if not child in g: + g.append(child) + self.Object.Group = g + + def removeObject(self,child): + if hasattr(self,"Object"): + g = self.Object.Group + if child in g: + g.remove(child) + self.Object.Group = g class _ViewProviderBuilding: "A View Provider for the Building object" diff --git a/src/Mod/Arch/ArchFloor.py b/src/Mod/Arch/ArchFloor.py index f5b9d435e..606395961 100644 --- a/src/Mod/Arch/ArchFloor.py +++ b/src/Mod/Arch/ArchFloor.py @@ -71,13 +71,27 @@ class _Floor: "The height of this floor") self.Type = "Floor" obj.Proxy = self + self.Object = obj def execute(self,obj): - pass + self.Object = obj def onChanged(self,obj,prop): pass + def addObject(self,child): + if hasattr(self,"Object"): + g = self.Object.Group + if not child in g: + g.append(child) + self.Object.Group = g + + def removeObject(self,child): + if hasattr(self,"Object"): + g = self.Object.Group + if child in g: + g.remove(child) + self.Object.Group = g class _ViewProviderFloor: "A View Provider for the Cell object" diff --git a/src/Mod/Arch/ArchSite.py b/src/Mod/Arch/ArchSite.py index 5da538e5a..300fd09ef 100644 --- a/src/Mod/Arch/ArchSite.py +++ b/src/Mod/Arch/ArchSite.py @@ -68,13 +68,28 @@ class _Site: def __init__(self,obj): self.Type = "Site" obj.Proxy = self + self.Object = obj def execute(self,obj): - pass - + self.Object = obj + def onChanged(self,obj,prop): pass + def addObject(self,child): + if hasattr(self,"Object"): + g = self.Object.Group + if not child in g: + g.append(child) + self.Object.Group = g + + def removeObject(self,child): + if hasattr(self,"Object"): + g = self.Object.Group + if child in g: + g.remove(child) + self.Object.Group = g + class _ViewProviderSite: "A View Provider for the Site object" def __init__(self,vobj): From cd1910a7056636959c625fc956f189e8c35ec57e Mon Sep 17 00:00:00 2001 From: msocorcim Date: Sun, 20 May 2012 23:00:23 -0400 Subject: [PATCH 20/42] Add new Mod/Mesh files to Makefile.am --- src/Mod/Mesh/Gui/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mod/Mesh/Gui/Makefile.am b/src/Mod/Mesh/Gui/Makefile.am index 46158d1e1..dd4405cd7 100644 --- a/src/Mod/Mesh/Gui/Makefile.am +++ b/src/Mod/Mesh/Gui/Makefile.am @@ -35,6 +35,7 @@ libMeshGui_la_SOURCES=\ PropertyEditorMesh.cpp \ RemoveComponents.cpp \ RemoveComponents.h \ + Segmentation.cpp \ SoFCIndexedFaceSet.cpp \ SoFCMeshObject.cpp \ ViewProvider.cpp \ @@ -48,6 +49,7 @@ libMeshGui_la_SOURCES=\ include_HEADERS=\ PropertyEditorMesh.h \ + Segmentation.h \ SoFCIndexedFaceSet.h \ SoFCMeshObject.h \ ViewProvider.h \ From a94897b92e98e325220e75ffbda9238ed0f84f55 Mon Sep 17 00:00:00 2001 From: msocorcim Date: Sun, 20 May 2012 23:01:07 -0400 Subject: [PATCH 21/42] Replace Gui text View->Display mode with View->Document window --- src/Gui/CommandView.cpp | 2 +- src/Gui/DlgDisplayProperties.ui | 2 +- src/Gui/Language/FreeCAD.ts | 2 +- src/Gui/Language/FreeCAD_af.ts | 4 ++-- src/Gui/Language/FreeCAD_de.ts | 4 ++-- src/Gui/Language/FreeCAD_es.ts | 4 ++-- src/Gui/Language/FreeCAD_fi.ts | 4 ++-- src/Gui/Language/FreeCAD_fr.ts | 4 ++-- src/Gui/Language/FreeCAD_hr.ts | 4 ++-- src/Gui/Language/FreeCAD_hu.ts | 4 ++-- src/Gui/Language/FreeCAD_it.ts | 4 ++-- src/Gui/Language/FreeCAD_ja.ts | 4 ++-- src/Gui/Language/FreeCAD_nl.ts | 4 ++-- src/Gui/Language/FreeCAD_no.ts | 4 ++-- src/Gui/Language/FreeCAD_pl.ts | 4 ++-- src/Gui/Language/FreeCAD_pt.ts | 4 ++-- src/Gui/Language/FreeCAD_ru.ts | 4 ++-- src/Gui/Language/FreeCAD_se.ts | 4 ++-- src/Gui/Language/FreeCAD_uk.ts | 4 ++-- src/Gui/Language/FreeCAD_zh.ts | 4 ++-- src/Gui/TaskView/TaskAppearance.ui | 2 +- 21 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index 1de74b6c3..712131d68 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -1172,7 +1172,7 @@ StdViewDockUndockFullscreen::StdViewDockUndockFullscreen() : Command("Std_ViewDockUndockFullscreen") { sGroup = QT_TR_NOOP("Standard-View"); - sMenuText = QT_TR_NOOP("Display mode"); + sMenuText = QT_TR_NOOP("Document window"); sToolTipText= QT_TR_NOOP("Display the active view either in fullscreen, in undocked or docked mode"); sWhatsThis = "Std_ViewDockUndockFullscreen"; sStatusTip = QT_TR_NOOP("Display the active view either in fullscreen, in undocked or docked mode"); diff --git a/src/Gui/DlgDisplayProperties.ui b/src/Gui/DlgDisplayProperties.ui index 5143bf2a8..58f4b6235 100644 --- a/src/Gui/DlgDisplayProperties.ui +++ b/src/Gui/DlgDisplayProperties.ui @@ -34,7 +34,7 @@ - Display mode: + Document window: diff --git a/src/Gui/Language/FreeCAD.ts b/src/Gui/Language/FreeCAD.ts index 3b452a860..024b5a7f1 100644 --- a/src/Gui/Language/FreeCAD.ts +++ b/src/Gui/Language/FreeCAD.ts @@ -5302,7 +5302,7 @@ You either have to finish or cancel the editing in the task panel. - Display mode + Document window diff --git a/src/Gui/Language/FreeCAD_af.ts b/src/Gui/Language/FreeCAD_af.ts index 052ea4d8c..4ba0e26ca 100644 --- a/src/Gui/Language/FreeCAD_af.ts +++ b/src/Gui/Language/FreeCAD_af.ts @@ -5317,8 +5317,8 @@ You either have to finish or cancel the editing in the task panel. Standaardaansig - Display mode - Vertoningsmodus + Document window + Dokument venster Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_de.ts b/src/Gui/Language/FreeCAD_de.ts index be807a1b7..79e5131c2 100644 --- a/src/Gui/Language/FreeCAD_de.ts +++ b/src/Gui/Language/FreeCAD_de.ts @@ -5325,8 +5325,8 @@ Sie müssen entweder den Bearbeitungsvorgang fertigstellen oder mittels des Aufg Standardansicht - Display mode - Anzeige-Modus + Document window + Dokumentfenster Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_es.ts b/src/Gui/Language/FreeCAD_es.ts index 173822aa0..089b96e95 100644 --- a/src/Gui/Language/FreeCAD_es.ts +++ b/src/Gui/Language/FreeCAD_es.ts @@ -5323,8 +5323,8 @@ Tienes que finzalizar o cancelar la edición en el panel de tareas.Vista estándar - Display mode - Modo de visualización + Document window + Ventana de documento Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_fi.ts b/src/Gui/Language/FreeCAD_fi.ts index dab907d81..ec9cde9a0 100644 --- a/src/Gui/Language/FreeCAD_fi.ts +++ b/src/Gui/Language/FreeCAD_fi.ts @@ -5314,8 +5314,8 @@ You either have to finish or cancel the editing in the task panel. Standardi-Näkymä - Display mode - Näyttötila + Document window + Asiakirjan ikkuna Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_fr.ts b/src/Gui/Language/FreeCAD_fr.ts index c65a10cdf..f665da6bd 100644 --- a/src/Gui/Language/FreeCAD_fr.ts +++ b/src/Gui/Language/FreeCAD_fr.ts @@ -5319,8 +5319,8 @@ You either have to finish or cancel the editing in the task panel. Vue standard - Display mode - Mode d'affichage + Document window + Fenêtre de document Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_hr.ts b/src/Gui/Language/FreeCAD_hr.ts index 790f20982..11e5c702b 100644 --- a/src/Gui/Language/FreeCAD_hr.ts +++ b/src/Gui/Language/FreeCAD_hr.ts @@ -5311,8 +5311,8 @@ You either have to finish or cancel the editing in the task panel. Standardni pogled - Display mode - NaÄin prikaza + Document window + Dokument prozor Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_hu.ts b/src/Gui/Language/FreeCAD_hu.ts index cf6433c3a..74d0db3b5 100644 --- a/src/Gui/Language/FreeCAD_hu.ts +++ b/src/Gui/Language/FreeCAD_hu.ts @@ -5318,8 +5318,8 @@ You either have to finish or cancel the editing in the task panel. Standard-nézet - Display mode - Megjelenítési mód + Document window + Dokumentum ablak Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_it.ts b/src/Gui/Language/FreeCAD_it.ts index 64b5bd7c3..cb266b1d0 100644 --- a/src/Gui/Language/FreeCAD_it.ts +++ b/src/Gui/Language/FreeCAD_it.ts @@ -5325,8 +5325,8 @@ You either have to finish or cancel the editing in the task panel. Vista standard - Display mode - Modalità di visualizzazione + Document window + Finestra del documento Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_ja.ts b/src/Gui/Language/FreeCAD_ja.ts index 5773577fd..0406284a6 100644 --- a/src/Gui/Language/FreeCAD_ja.ts +++ b/src/Gui/Language/FreeCAD_ja.ts @@ -5319,8 +5319,8 @@ You either have to finish or cancel the editing in the task panel. 標準ビュー - Display mode - 表示モード + Document window + ドキュメントウィンドウ Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_nl.ts b/src/Gui/Language/FreeCAD_nl.ts index 0a57b99f5..ea7ae833c 100644 --- a/src/Gui/Language/FreeCAD_nl.ts +++ b/src/Gui/Language/FreeCAD_nl.ts @@ -5314,8 +5314,8 @@ You either have to finish or cancel the editing in the task panel. Standaard-aanzicht - Display mode - Weergavemodus + Document window + Documentvenster Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_no.ts b/src/Gui/Language/FreeCAD_no.ts index 948c209da..56087e8fa 100644 --- a/src/Gui/Language/FreeCAD_no.ts +++ b/src/Gui/Language/FreeCAD_no.ts @@ -5315,8 +5315,8 @@ You either have to finish or cancel the editing in the task panel. Standardvisning - Display mode - Visningsmodus + Document window + Dokument-vinduet Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_pl.ts b/src/Gui/Language/FreeCAD_pl.ts index 064d5e00e..0a428556b 100644 --- a/src/Gui/Language/FreeCAD_pl.ts +++ b/src/Gui/Language/FreeCAD_pl.ts @@ -5305,8 +5305,8 @@ You either have to finish or cancel the editing in the task panel. Normalny widok - Display mode - Tryb wyÅ›wietlania + Document window + Okno dokumentu Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_pt.ts b/src/Gui/Language/FreeCAD_pt.ts index 2ed9d6bf6..fd0cde922 100644 --- a/src/Gui/Language/FreeCAD_pt.ts +++ b/src/Gui/Language/FreeCAD_pt.ts @@ -5307,8 +5307,8 @@ You either have to finish or cancel the editing in the task panel. Vista padrão - Display mode - Modo de exibição + Document window + Janela do documento Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_ru.ts b/src/Gui/Language/FreeCAD_ru.ts index 40667e37a..b1e39e830 100644 --- a/src/Gui/Language/FreeCAD_ru.ts +++ b/src/Gui/Language/FreeCAD_ru.ts @@ -5310,8 +5310,8 @@ You either have to finish or cancel the editing in the task panel. Стандартный вид - Display mode - Режим Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ + Document window + окно документа Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_se.ts b/src/Gui/Language/FreeCAD_se.ts index 1f51d8242..9b777ffac 100644 --- a/src/Gui/Language/FreeCAD_se.ts +++ b/src/Gui/Language/FreeCAD_se.ts @@ -5324,8 +5324,8 @@ You either have to finish or cancel the editing in the task panel. Standardvy - Display mode - Visningsläge + Document window + Dokumentfönstret Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_uk.ts b/src/Gui/Language/FreeCAD_uk.ts index b9dbe9099..5e0b27cb6 100644 --- a/src/Gui/Language/FreeCAD_uk.ts +++ b/src/Gui/Language/FreeCAD_uk.ts @@ -5325,8 +5325,8 @@ You either have to finish or cancel the editing in the task panel. Стандартні виглÑди - Display mode - Режим показу + Document window + вікно документа Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_zh.ts b/src/Gui/Language/FreeCAD_zh.ts index 18e102a1e..a63f7f181 100644 --- a/src/Gui/Language/FreeCAD_zh.ts +++ b/src/Gui/Language/FreeCAD_zh.ts @@ -5313,8 +5313,8 @@ You either have to finish or cancel the editing in the task panel. 标准视图 - Display mode - æ˜¾ç¤ºæ¨¡å¼ + Document window + æ–‡æ¡£çª—å£ Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/TaskView/TaskAppearance.ui b/src/Gui/TaskView/TaskAppearance.ui index 795549469..e775af457 100644 --- a/src/Gui/TaskView/TaskAppearance.ui +++ b/src/Gui/TaskView/TaskAppearance.ui @@ -33,7 +33,7 @@ - Display mode: + Document window: From a87f55812575975a9328c0abc29381b96c11cf3f Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 21 May 2012 14:08:57 +0200 Subject: [PATCH 22/42] Workaround for linker error with MSVC --- src/Gui/Tree.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 2c5f0ea15..ba3672d8c 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -431,6 +431,7 @@ void TreeWidget::dropEvent(QDropEvent *event) // Open command App::Document* doc = grp->getDocument(); Gui::Document* gui = Gui::Application::Instance->getDocument(doc); + Base::Type DOGPython = Base::Type::fromName("App::DocumentObjectGroupPython"); gui->openCommand("Move object"); for (QList::Iterator it = items.begin(); it != items.end(); ++it) { // get document object @@ -441,7 +442,7 @@ void TreeWidget::dropEvent(QDropEvent *event) if (par) { // allow an object to be in one group only QString cmd; - if (par->getTypeId().isDerivedFrom(App::DocumentObjectGroupPython::getClassTypeId())) { + if (par->getTypeId().isDerivedFrom(DOGPython)) { // if this is a python group, call the method of its Proxy cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").Proxy.removeObject(" "App.getDocument(\"%1\").getObject(\"%3\"))") @@ -460,7 +461,7 @@ void TreeWidget::dropEvent(QDropEvent *event) // build Python command for execution QString cmd; - if (grp->getTypeId().isDerivedFrom(App::DocumentObjectGroupPython::getClassTypeId())) { + if (grp->getTypeId().isDerivedFrom(DOGPython)) { cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").Proxy.addObject(" "App.getDocument(\"%1\").getObject(\"%3\"))") .arg(QString::fromAscii(doc->getName())) From d6b6f6b37956a6f9a4f98745c2715ea00c5aba0c Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 21 May 2012 15:02:51 +0200 Subject: [PATCH 23/42] Mesh segmentation --- src/Mod/Mesh/App/Core/Segmentation.cpp | 26 +++++--------- src/Mod/Mesh/App/Core/Segmentation.h | 28 ++++++++++----- src/Mod/Mesh/App/Mesh.cpp | 50 +++++++------------------- src/Mod/Mesh/App/MeshPy.xml | 6 ++-- src/Mod/Mesh/App/MeshPyImp.cpp | 7 ++-- src/Mod/Mesh/Gui/Segmentation.cpp | 2 +- src/Mod/Mesh/Gui/Segmentation.ui | 23 ++++++++++-- 7 files changed, 67 insertions(+), 75 deletions(-) diff --git a/src/Mod/Mesh/App/Core/Segmentation.cpp b/src/Mod/Mesh/App/Core/Segmentation.cpp index 2e86fdb17..01d99fb11 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.cpp +++ b/src/Mod/Mesh/App/Core/Segmentation.cpp @@ -108,22 +108,12 @@ bool MeshCurvatureCylindricalSegment::TestFacet (const MeshFacet &rclFacet) cons { for (int i=0; i<3; i++) { const CurvatureInfo& ci = info[rclFacet._aulPoints[i]]; - if (ci.fMaxCurvature > ci.fMinCurvature) { - // convexe - if (fabs(ci.fMinCurvature) > tolerance) - return false; - float diff = ci.fMaxCurvature - curvature; - if (fabs(diff) > tolerance) - return false; - } - else { - // concave - if (fabs(ci.fMaxCurvature) > tolerance) - return false; - float diff = ci.fMinCurvature + curvature; - if (fabs(diff) > tolerance) - return false; - } + float fMax = std::max(fabs(ci.fMaxCurvature), fabs(ci.fMinCurvature)); + float fMin = std::min(fabs(ci.fMaxCurvature), fabs(ci.fMinCurvature)); + if (fMin > toleranceMin) + return false; + if (fabs(fMax - curvature) > toleranceMax) + return false; } return true; @@ -151,9 +141,9 @@ bool MeshCurvatureFreeformSegment::TestFacet (const MeshFacet &rclFacet) const { for (int i=0; i<3; i++) { const CurvatureInfo& ci = info[rclFacet._aulPoints[i]]; - if (fabs(ci.fMinCurvature-c2) > tolerance) + if (fabs(ci.fMinCurvature-c2) > toleranceMin) return false; - if (fabs(ci.fMaxCurvature-c1) > tolerance) + if (fabs(ci.fMaxCurvature-c1) > toleranceMax) return false; } diff --git a/src/Mod/Mesh/App/Core/Segmentation.h b/src/Mod/Mesh/App/Core/Segmentation.h index 561385c1c..c894147ad 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.h +++ b/src/Mod/Mesh/App/Core/Segmentation.h @@ -84,53 +84,63 @@ protected: class MeshExport MeshCurvatureSurfaceSegment : public MeshSurfaceSegment { public: - MeshCurvatureSurfaceSegment(const std::vector& ci, unsigned long minFacets, float tol) - : MeshSurfaceSegment(minFacets), info(ci), tolerance(tol) {} + MeshCurvatureSurfaceSegment(const std::vector& ci, unsigned long minFacets) + : MeshSurfaceSegment(minFacets), info(ci) {} protected: const std::vector& info; - float tolerance; }; class MeshExport MeshCurvaturePlanarSegment : public MeshCurvatureSurfaceSegment { public: MeshCurvaturePlanarSegment(const std::vector& ci, unsigned long minFacets, float tol) - : MeshCurvatureSurfaceSegment(ci, minFacets, tol) {} + : MeshCurvatureSurfaceSegment(ci, minFacets), tolerance(tol) {} virtual bool TestFacet (const MeshFacet &rclFacet) const; + +private: + float tolerance; }; class MeshExport MeshCurvatureCylindricalSegment : public MeshCurvatureSurfaceSegment { public: - MeshCurvatureCylindricalSegment(const std::vector& ci, unsigned long minFacets, float tol, float radius) - : MeshCurvatureSurfaceSegment(ci, minFacets, tol) { curvature = 1/radius;} + MeshCurvatureCylindricalSegment(const std::vector& ci, unsigned long minFacets, + float tolMin, float tolMax, float radius) + : MeshCurvatureSurfaceSegment(ci, minFacets), toleranceMin(tolMin), toleranceMax(tolMax) { curvature = 1/radius;} virtual bool TestFacet (const MeshFacet &rclFacet) const; private: float curvature; + float toleranceMin; + float toleranceMax; }; class MeshExport MeshCurvatureSphericalSegment : public MeshCurvatureSurfaceSegment { public: MeshCurvatureSphericalSegment(const std::vector& ci, unsigned long minFacets, float tol, float radius) - : MeshCurvatureSurfaceSegment(ci, minFacets, tol) { curvature = 1/radius;} + : MeshCurvatureSurfaceSegment(ci, minFacets), tolerance(tol) { curvature = 1/radius;} virtual bool TestFacet (const MeshFacet &rclFacet) const; private: float curvature; + float tolerance; }; class MeshExport MeshCurvatureFreeformSegment : public MeshCurvatureSurfaceSegment { public: - MeshCurvatureFreeformSegment(const std::vector& ci, unsigned long minFacets, float tol, float c1, float c2) - : MeshCurvatureSurfaceSegment(ci, minFacets, tol), c1(c1), c2(c2) {} + MeshCurvatureFreeformSegment(const std::vector& ci, unsigned long minFacets, + float tolMin, float tolMax, float c1, float c2) + : MeshCurvatureSurfaceSegment(ci, minFacets), c1(c1), c2(c2), + toleranceMin(tolMin), toleranceMax(tolMax) {} virtual bool TestFacet (const MeshFacet &rclFacet) const; private: float c1, c2; + float toleranceMin; + float toleranceMax; }; class MeshExport MeshSurfaceVisitor : public MeshFacetVisitor diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index 89f85856a..dec5da73b 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -44,6 +44,7 @@ #include "Core/TopoAlgorithm.h" #include "Core/Evaluation.h" #include "Core/Degeneration.h" +#include "Core/Segmentation.h" #include "Core/SetOperations.h" #include "Core/Visitor.h" @@ -1426,48 +1427,21 @@ std::vector MeshObject::getSegmentsFromType(MeshObject::Type type, cons float dev, unsigned long minFacets) const { std::vector segm; - unsigned long startFacet; if (this->_kernel.CountFacets() == 0) return segm; - // reset VISIT flags - MeshCore::MeshAlgorithm cAlgo(this->_kernel); - if (aSegment.isEmpty()) { - cAlgo.ResetFacetFlag(MeshCore::MeshFacet::VISIT); + MeshCore::MeshSegmentAlgorithm finder(this->_kernel); + MeshCore::MeshDistanceSurfaceSegment* surf; + surf = new MeshCore::MeshDistancePlanarSegment(this->_kernel, minFacets, dev); + std::vector surfaces; + surfaces.push_back(surf); + finder.FindSegments(surfaces); + + const std::vector& data = surf->GetSegments(); + for (std::vector::const_iterator it = data.begin(); it != data.end(); ++it) { + segm.push_back(Segment(const_cast(this), *it, false)); } - else { - cAlgo.SetFacetFlag(MeshCore::MeshFacet::VISIT); - cAlgo.ResetFacetsFlag(aSegment.getIndices(), MeshCore::MeshFacet::VISIT); - } - - const MeshCore::MeshFacetArray& rFAry = this->_kernel.GetFacets(); - MeshCore::MeshFacetArray::_TConstIterator iTri = rFAry.begin(); - MeshCore::MeshFacetArray::_TConstIterator iBeg = rFAry.begin(); - MeshCore::MeshFacetArray::_TConstIterator iEnd = rFAry.end(); - - // start from the first not visited facet - cAlgo.CountFacetFlag(MeshCore::MeshFacet::VISIT); - iTri = std::find_if(iTri, iEnd, std::bind2nd(MeshCore::MeshIsNotFlag(), - MeshCore::MeshFacet::VISIT)); - startFacet = iTri - iBeg; - - while (startFacet != ULONG_MAX) { - // collect all facets of the same geometry - std::vector indices; - indices.push_back(startFacet); - MeshCore::MeshPlaneVisitor pv(this->_kernel, startFacet, dev, indices); - this->_kernel.VisitNeighbourFacets(pv, startFacet); - - iTri = std::find_if(iTri, iEnd, std::bind2nd(MeshCore::MeshIsNotFlag(), - MeshCore::MeshFacet::VISIT)); - if (iTri < iEnd) - startFacet = iTri - iBeg; - else - startFacet = ULONG_MAX; - if (indices.size() > minFacets) - segm.push_back(Segment(const_cast(this), indices, false)); - } - + delete surf; return segm; } diff --git a/src/Mod/Mesh/App/MeshPy.xml b/src/Mod/Mesh/App/MeshPy.xml index f29a59730..116979807 100644 --- a/src/Mod/Mesh/App/MeshPy.xml +++ b/src/Mod/Mesh/App/MeshPy.xml @@ -382,10 +382,10 @@ plane if none of its neighours is coplanar. getSegmentsByCurvature(list) -> list The argument list gives a list if tuples where it defines the preferred maximum curvature, -the preferred minumum curvature, the tolerance and the number of minimum faces for the segment. +the preferred minumum curvature, the tolerances and the number of minimum faces for the segment. Example: -c=(1.0, 0.0, 0.1, 500) # search for a cylinder with radius 1.0 -p=(0.0, 0.0, 0.1, 500) # search for a plane +c=(1.0, 0.0, 0.1, 0.1, 500) # search for a cylinder with radius 1.0 +p=(0.0, 0.0, 0.1, 0.1, 500) # search for a plane mesh.getSegmentsByCurvature([c,p]) diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp index dd1f0e3e1..a2a1e6302 100644 --- a/src/Mod/Mesh/App/MeshPyImp.cpp +++ b/src/Mod/Mesh/App/MeshPyImp.cpp @@ -1399,9 +1399,10 @@ PyObject* MeshPy::getSegmentsByCurvature(PyObject *args) Py::Tuple t(*it); float c1 = (float)Py::Float(t[0]); float c2 = (float)Py::Float(t[1]); - float tol = (float)Py::Float(t[2]); - int num = (int)Py::Int(t[3]); - segm.push_back(new MeshCore::MeshCurvatureFreeformSegment(meshCurv.GetCurvature(), num, tol, c1, c2)); + float tol1 = (float)Py::Float(t[2]); + float tol2 = (float)Py::Float(t[3]); + int num = (int)Py::Int(t[4]); + segm.push_back(new MeshCore::MeshCurvatureFreeformSegment(meshCurv.GetCurvature(), num, tol1, tol2, c1, c2)); } finder.FindSegments(segm); diff --git a/src/Mod/Mesh/Gui/Segmentation.cpp b/src/Mod/Mesh/Gui/Segmentation.cpp index 962d65f2e..223479c56 100644 --- a/src/Mod/Mesh/Gui/Segmentation.cpp +++ b/src/Mod/Mesh/Gui/Segmentation.cpp @@ -76,7 +76,7 @@ void Segmentation::accept() std::vector segm; if (ui->groupBoxCyl->isChecked()) { segm.push_back(new MeshCore::MeshCurvatureCylindricalSegment - (meshCurv.GetCurvature(), ui->numCyl->value(), ui->tolCyl->value(), ui->radCyl->value())); + (meshCurv.GetCurvature(), ui->numCyl->value(), ui->tol1Cyl->value(), ui->tol2Cyl->value(), ui->radCyl->value())); } if (ui->groupBoxSph->isChecked()) { segm.push_back(new MeshCore::MeshCurvatureSphericalSegment diff --git a/src/Mod/Mesh/Gui/Segmentation.ui b/src/Mod/Mesh/Gui/Segmentation.ui index 129c89873..b6ce13bd8 100644 --- a/src/Mod/Mesh/Gui/Segmentation.ui +++ b/src/Mod/Mesh/Gui/Segmentation.ui @@ -106,12 +106,12 @@ - Tolerance + Tolerance (Flat) - + 0.100000000000000 @@ -121,13 +121,30 @@ + + + Tolerance (Curved) + + + + + + + 0.100000000000000 + + + 0.100000000000000 + + + + Minimum number of faces - + 100000 From 87f1e93feaf208561e1bd190d7661e9791f1b9bd Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 21 May 2012 15:53:46 +0200 Subject: [PATCH 24/42] Mesh segmentation --- src/Mod/Mesh/App/Core/Segmentation.h | 6 ++++++ src/Mod/Mesh/Gui/Segmentation.cpp | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Mod/Mesh/App/Core/Segmentation.h b/src/Mod/Mesh/App/Core/Segmentation.h index c894147ad..1b29f4bff 100644 --- a/src/Mod/Mesh/App/Core/Segmentation.h +++ b/src/Mod/Mesh/App/Core/Segmentation.h @@ -41,6 +41,7 @@ public: : minFacets(minFacets) {} virtual ~MeshSurfaceSegment() {} virtual bool TestFacet (const MeshFacet &rclFacet) const = 0; + virtual const char* GetType() const = 0; virtual void Initialize(unsigned long); virtual void AddFacet(const MeshFacet& rclFacet); void AddSegment(const std::vector&); @@ -70,6 +71,7 @@ public: MeshDistancePlanarSegment(const MeshKernel& mesh, unsigned long minFacets, float tol); virtual ~MeshDistancePlanarSegment(); bool TestFacet (const MeshFacet& rclFacet) const; + const char* GetType() const { return "Plane"; } void Initialize(unsigned long); void AddFacet(const MeshFacet& rclFacet); @@ -97,6 +99,7 @@ public: MeshCurvaturePlanarSegment(const std::vector& ci, unsigned long minFacets, float tol) : MeshCurvatureSurfaceSegment(ci, minFacets), tolerance(tol) {} virtual bool TestFacet (const MeshFacet &rclFacet) const; + virtual const char* GetType() const { return "Plane"; } private: float tolerance; @@ -109,6 +112,7 @@ public: float tolMin, float tolMax, float radius) : MeshCurvatureSurfaceSegment(ci, minFacets), toleranceMin(tolMin), toleranceMax(tolMax) { curvature = 1/radius;} virtual bool TestFacet (const MeshFacet &rclFacet) const; + virtual const char* GetType() const { return "Cylinder"; } private: float curvature; @@ -122,6 +126,7 @@ public: MeshCurvatureSphericalSegment(const std::vector& ci, unsigned long minFacets, float tol, float radius) : MeshCurvatureSurfaceSegment(ci, minFacets), tolerance(tol) { curvature = 1/radius;} virtual bool TestFacet (const MeshFacet &rclFacet) const; + virtual const char* GetType() const { return "Sphere"; } private: float curvature; @@ -136,6 +141,7 @@ public: : MeshCurvatureSurfaceSegment(ci, minFacets), c1(c1), c2(c2), toleranceMin(tolMin), toleranceMax(tolMax) {} virtual bool TestFacet (const MeshFacet &rclFacet) const; + virtual const char* GetType() const { return "Freeform"; } private: float c1, c2; diff --git a/src/Mod/Mesh/Gui/Segmentation.cpp b/src/Mod/Mesh/Gui/Segmentation.cpp index 223479c56..de2b81d48 100644 --- a/src/Mod/Mesh/Gui/Segmentation.cpp +++ b/src/Mod/Mesh/Gui/Segmentation.cpp @@ -24,12 +24,14 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include #endif #include "Segmentation.h" #include "ui_Segmentation.h" #include #include +#include #include #include @@ -89,18 +91,32 @@ void Segmentation::accept() finder.FindSegments(segm); App::Document* document = App::GetApplication().getActiveDocument(); + document->openTransaction("Segmentation"); + + std::string internalname = "Segments_"; + internalname += myMesh->getNameInDocument(); + App::DocumentObjectGroup* group = static_cast(document->addObject + ("App::DocumentObjectGroup", internalname.c_str())); + std::string labelname = "Segments "; + labelname += myMesh->Label.getValue(); + group->Label.setValue(labelname); for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { const std::vector& data = (*it)->GetSegments(); for (std::vector::const_iterator jt = data.begin(); jt != data.end(); ++jt) { Mesh::MeshObject* segment = mesh->meshFromSegment(*jt); - Mesh::Feature* feaSegm = static_cast(document->addObject("Mesh::Feature", "Segment")); + Mesh::Feature* feaSegm = static_cast(group->addObject("Mesh::Feature", "Segment")); Mesh::MeshObject* feaMesh = feaSegm->Mesh.startEditing(); feaMesh->swap(*segment); feaSegm->Mesh.finishEditing(); delete segment; + + std::stringstream label; + label << feaSegm->Label.getValue() << " (" << (*it)->GetType() << ")"; + feaSegm->Label.setValue(label.str()); } delete (*it); } + document->commitTransaction(); } void Segmentation::changeEvent(QEvent *e) From 27de3f76f4c400ba00e1178b175b1173f07b0217 Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 21 May 2012 18:27:30 +0200 Subject: [PATCH 25/42] 0000712: Cad Navigation Zoom with Ctrl + causes shapes to pan off screen --- src/Gui/CommandView.cpp | 16 +++------------- src/Gui/NavigationStyle.cpp | 10 ++++++++++ src/Gui/NavigationStyle.h | 2 ++ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index 712131d68..33da94c7c 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -59,6 +59,7 @@ #include "DemoMode.h" #include "TextureMapping.h" #include "Utilities.h" +#include "NavigationStyle.h" #include #include @@ -1817,13 +1818,7 @@ void StdViewZoomIn::activated(int iMsg) View3DInventor* view = qobject_cast(getMainWindow()->activeWindow()); if ( view ) { View3DInventorViewer* viewer = view->getViewer(); - - // send an event to the GL widget to use the internal View3DInventorViewer::zoom() method - // do only one step to zoom in - SoMouseButtonEvent e; - e.setButton(SoMouseButtonEvent::BUTTON5); - e.setState(SoMouseButtonEvent::DOWN); - viewer->sendSoEvent(&e); + viewer->navigationStyle()->zoomIn(); } } @@ -1857,12 +1852,7 @@ void StdViewZoomOut::activated(int iMsg) View3DInventor* view = qobject_cast(getMainWindow()->activeWindow()); if (view) { View3DInventorViewer* viewer = view->getViewer(); - // send an event to the GL widget to use the internal View3DInventorViewer::zoom() method - // do only one step to zoom out - SoMouseButtonEvent e; - e.setButton(SoMouseButtonEvent::BUTTON4); - e.setState(SoMouseButtonEvent::DOWN); - viewer->sendSoEvent(&e); + viewer->navigationStyle()->zoomOut(); } } diff --git a/src/Gui/NavigationStyle.cpp b/src/Gui/NavigationStyle.cpp index 192cb7ae5..30f5ecf40 100644 --- a/src/Gui/NavigationStyle.cpp +++ b/src/Gui/NavigationStyle.cpp @@ -721,6 +721,16 @@ void NavigationStyle::zoomByCursor(const SbVec2f & thispos, const SbVec2f & prev zoom(viewer->getCamera(), (thispos[1] - prevpos[1]) * 10.0f/*20.0f*/); } +void NavigationStyle::zoomIn() +{ + zoom(viewer->getCamera(), -this->zoomStep); +} + +void NavigationStyle::zoomOut() +{ + zoom(viewer->getCamera(), this->zoomStep); +} + void NavigationStyle::doZoom(SoCamera* camera, SbBool forward, const SbVec2f& pos) { SbBool zoomAtCur = this->zoomAtCursor; diff --git a/src/Gui/NavigationStyle.h b/src/Gui/NavigationStyle.h index 7644a7340..b6d4e20e6 100644 --- a/src/Gui/NavigationStyle.h +++ b/src/Gui/NavigationStyle.h @@ -115,6 +115,8 @@ public: void setZoomStep(float); void setZoomAtCursor(SbBool); SbBool isZoomAtCursor() const; + void zoomIn(); + void zoomOut(); void updateAnimation(); void redraw(); From d3fecc2b5e3f3ae1a1994d5e24f9e3d94d24dab8 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Mon, 21 May 2012 22:35:18 -0300 Subject: [PATCH 26/42] unified yorik's email --- src/Mod/Draft/DraftGui.py | 2 +- src/Mod/Draft/Init.py | 2 +- src/Mod/Draft/InitGui.py | 2 +- src/Mod/Draft/draftlibs/fcgeo.py | 2 +- src/Mod/Draft/draftlibs/fcvec.py | 2 +- src/Mod/Draft/importDXF.py | 4 ++-- src/Mod/Draft/importOCA.py | 4 ++-- src/Mod/Draft/importSVG.py | 2 +- src/Mod/Draft/macros.py | 2 +- src/Tools/offlinedoc/buildpdf.py | 2 +- src/Tools/offlinedoc/buildqhelp.py | 2 +- src/Tools/offlinedoc/buildwikiindex.py | 2 +- src/Tools/offlinedoc/downloadwiki.py | 2 +- src/Tools/updateTranslations.py | 2 +- src/Tools/wiki2qhelp.py | 2 +- 15 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 02c6c57d4..752abb76b 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Mod/Draft/Init.py b/src/Mod/Draft/Init.py index 5069e5fd6..47fd3dc98 100644 --- a/src/Mod/Draft/Init.py +++ b/src/Mod/Draft/Init.py @@ -1,6 +1,6 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index 1bcbadbc8..84d0b9b86 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -1,6 +1,6 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Mod/Draft/draftlibs/fcgeo.py b/src/Mod/Draft/draftlibs/fcgeo.py index bf9f53e18..ccacbf62c 100755 --- a/src/Mod/Draft/draftlibs/fcgeo.py +++ b/src/Mod/Draft/draftlibs/fcgeo.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * #* Copyright (c) 2009, 2010 * -#* Yorik van Havre , Ken Cline * +#* Yorik van Havre , Ken Cline * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Mod/Draft/draftlibs/fcvec.py b/src/Mod/Draft/draftlibs/fcvec.py index 0f3358cfc..1f10a2c7e 100644 --- a/src/Mod/Draft/draftlibs/fcvec.py +++ b/src/Mod/Draft/draftlibs/fcvec.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * #* Copyright (c) 2009, 2010 * -#* Yorik van Havre , Ken Cline * +#* Yorik van Havre , Ken Cline * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index 97e01db7f..2c0474f8e 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -3,7 +3,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (GPL) * @@ -24,7 +24,7 @@ #*************************************************************************** __title__="FreeCAD Draft Workbench - DXF importer/exporter" -__author__ = "Yorik van Havre " +__author__ = "Yorik van Havre " __url__ = ["http://yorik.orgfree.com","http://free-cad.sourceforge.net"] ''' diff --git a/src/Mod/Draft/importOCA.py b/src/Mod/Draft/importOCA.py index 6324ce710..58131d830 100644 --- a/src/Mod/Draft/importOCA.py +++ b/src/Mod/Draft/importOCA.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU General Public License (GPL) * @@ -22,7 +22,7 @@ #*************************************************************************** __title__="FreeCAD Draft Workbench - OCA importer/exporter" -__author__ = "Yorik van Havre " +__author__ = "Yorik van Havre " __url__ = ["http://yorik.orgfree.com","http://free-cad.sourceforge.net"] ''' diff --git a/src/Mod/Draft/importSVG.py b/src/Mod/Draft/importSVG.py index 5de678d51..b49d4735c 100644 --- a/src/Mod/Draft/importSVG.py +++ b/src/Mod/Draft/importSVG.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Mod/Draft/macros.py b/src/Mod/Draft/macros.py index a2668dad8..2b106d19f 100644 --- a/src/Mod/Draft/macros.py +++ b/src/Mod/Draft/macros.py @@ -1,6 +1,6 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Tools/offlinedoc/buildpdf.py b/src/Tools/offlinedoc/buildpdf.py index ff9f53a15..c6dbf246f 100755 --- a/src/Tools/offlinedoc/buildpdf.py +++ b/src/Tools/offlinedoc/buildpdf.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Tools/offlinedoc/buildqhelp.py b/src/Tools/offlinedoc/buildqhelp.py index 4325ed915..77fa1bcae 100755 --- a/src/Tools/offlinedoc/buildqhelp.py +++ b/src/Tools/offlinedoc/buildqhelp.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Tools/offlinedoc/buildwikiindex.py b/src/Tools/offlinedoc/buildwikiindex.py index f7cee86c8..e685aed48 100755 --- a/src/Tools/offlinedoc/buildwikiindex.py +++ b/src/Tools/offlinedoc/buildwikiindex.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Tools/offlinedoc/downloadwiki.py b/src/Tools/offlinedoc/downloadwiki.py index 50f88a2eb..4fc0bdadf 100755 --- a/src/Tools/offlinedoc/downloadwiki.py +++ b/src/Tools/offlinedoc/downloadwiki.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Tools/updateTranslations.py b/src/Tools/updateTranslations.py index 5e3e991be..695a2f633 100755 --- a/src/Tools/updateTranslations.py +++ b/src/Tools/updateTranslations.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Library General Public License (LGPL) * diff --git a/src/Tools/wiki2qhelp.py b/src/Tools/wiki2qhelp.py index 09c47139a..dc52f3815 100755 --- a/src/Tools/wiki2qhelp.py +++ b/src/Tools/wiki2qhelp.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Library General Public License (LGPL) * From 335d6cdfdb673ff48525c97b363dae0d0f54b26b Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Tue, 22 May 2012 11:45:40 -0300 Subject: [PATCH 27/42] Renamed Draft fcvec and fcgeo modules Draft/draftlibs/fcvec becomes Draft/DraftVecUtils Draft/draftlibs/fcgeo becomes Draft/DraftGeomUtils --- src/Doc/sphinx/Draft.rst | 13 +- src/Mod/Arch/ArchAxis.py | 4 +- src/Mod/Arch/ArchCommands.py | 16 +- src/Mod/Arch/ArchRoof.py | 14 +- src/Mod/Arch/ArchSectionPlane.py | 8 +- src/Mod/Arch/ArchStructure.py | 12 +- src/Mod/Arch/ArchVRM.py | 29 +- src/Mod/Arch/ArchWall.py | 42 ++- src/Mod/Arch/ArchWindow.py | 12 +- src/Mod/Arch/importIFC.py | 5 +- src/Mod/Arch/importOBJ.py | 5 +- src/Mod/Draft/CMakeLists.txt | 4 +- src/Mod/Draft/Draft.py | 202 +++++++------- .../{draftlibs/fcgeo.py => DraftGeomUtils.py} | 0 src/Mod/Draft/DraftSnap.py | 42 ++- src/Mod/Draft/DraftTools.py | 251 +++++++++--------- src/Mod/Draft/DraftTrackers.py | 49 ++-- .../{draftlibs/fcvec.py => DraftVecUtils.py} | 0 src/Mod/Draft/Makefile.am | 4 +- src/Mod/Draft/WorkingPlane.py | 33 ++- src/Mod/Draft/importDXF.py | 70 ++--- src/Mod/Draft/importOCA.py | 13 +- src/Mod/Draft/importSVG.py | 32 ++- src/WindowsInstaller/ModDraft.wxi | 4 +- 24 files changed, 413 insertions(+), 451 deletions(-) rename src/Mod/Draft/{draftlibs/fcgeo.py => DraftGeomUtils.py} (100%) rename src/Mod/Draft/{draftlibs/fcvec.py => DraftVecUtils.py} (100%) diff --git a/src/Doc/sphinx/Draft.rst b/src/Doc/sphinx/Draft.rst index 2b4101780..4479028b1 100644 --- a/src/Doc/sphinx/Draft.rst +++ b/src/Doc/sphinx/Draft.rst @@ -12,10 +12,15 @@ The Draft module offer several convenient functions to work with simple objects. .. automodule:: DraftSnap :members: -The draftlibs contain two submodules, widely used throughout the Draft module: fcvec, which contains useful methods for dealing with vectors, and fcgeo, which offers many tools for working with Part shape objects. +The Draft module also contains two submodules, widely used throughout the Draft and Arch modules: DraftVecUtils, which contains useful methods for dealing with vectors, and DraftGeomUtils, which offers many tools for working with OpenCascade geometry. -.. automodule:: draftlibs.fcvec +.. automodule:: DraftVecUtils :members: -.. automodule:: draftlibs.fcgeo - :members: \ No newline at end of file +.. automodule:: DraftGeomUtils + :members: + +The Draft module also features a module that contains trackers, special objects made to display 3D temporary geometry in the 3D scene, that have no real existence in the FreeCAD document. + +.. automodule:: DraftTrackers + :members: diff --git a/src/Mod/Arch/ArchAxis.py b/src/Mod/Arch/ArchAxis.py index a56a50ff2..37cdf9f54 100644 --- a/src/Mod/Arch/ArchAxis.py +++ b/src/Mod/Arch/ArchAxis.py @@ -21,9 +21,7 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Draft,math - -from draftlibs import fcvec +import FreeCAD,FreeCADGui,Draft,math,DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore, QtGui from pivy import coin diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index 5802e5e0a..2ebfad0d0 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -21,8 +21,7 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Draft,ArchComponent -from draftlibs import fcvec +import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore @@ -170,7 +169,7 @@ def makeFace(wires,method=2,cleanup=False): # cleaning up rubbish in wires if cleanup: for i in range(len(wires)): - wires[i] = fcgeo.removeInterVertices(wires[i]) + wires[i] = DraftGeomUtils.removeInterVertices(wires[i]) print "garbage removed" for w in wires: # we assume that the exterior boundary is that one with @@ -210,8 +209,7 @@ def meshToShape(obj,mark=True): mark is True (default), non-solid objects will be marked in red''' name = obj.Name - import Part,MeshPart - from draftlibs import fcgeo + import Part, MeshPart, DraftGeomUtils if "Mesh" in obj.PropertiesList: faces = [] mesh = obj.Mesh @@ -249,12 +247,12 @@ def meshToShape(obj,mark=True): def removeShape(objs,mark=True): '''takes an arch object (wall or structure) built on a cubic shape, and removes the inner shape, keeping its length, width and height as parameters.''' - from draftlibs import fcgeo + import DraftGeomUtils if not isinstance(objs,list): objs = [objs] for obj in objs: - if fcgeo.isCubic(obj.Shape): - dims = fcgeo.getCubicDimensions(obj.Shape) + if DraftGeomUtils.isCubic(obj.Shape): + dims = DraftGeomUtils.getCubicDimensions(obj.Shape) if dims: name = obj.Name tp = Draft.getType(obj) @@ -270,7 +268,7 @@ def removeShape(objs,mark=True): length = dims[1] width = dims[2] v1 = Vector(length/2,0,0) - v2 = fcvec.neg(v1) + v2 = DraftVecUtils.neg(v1) v1 = dims[0].multVec(v1) v2 = dims[0].multVec(v2) line = Draft.makeLine(v1,v2) diff --git a/src/Mod/Arch/ArchRoof.py b/src/Mod/Arch/ArchRoof.py index 37d06b58e..31515afbc 100644 --- a/src/Mod/Arch/ArchRoof.py +++ b/src/Mod/Arch/ArchRoof.py @@ -21,8 +21,7 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Draft,ArchComponent -from draftlibs import fcvec +import FreeCAD,FreeCADGui,Draft,ArchComponent, DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore @@ -104,8 +103,7 @@ class _Roof(ArchComponent.Component): self.createGeometry(obj) def createGeometry(self,obj): - import Part,math - from draftlibs import fcgeo + import Part, math, DraftGeomUtils pl = obj.Placement if obj.Base and obj.Face and obj.Angle: @@ -116,14 +114,14 @@ class _Roof(ArchComponent.Component): c = round(math.tan(math.radians(obj.Angle)),Draft.precision()) norm = f.normalAt(0,0) d = f.BoundBox.DiagonalLength - edges = fcgeo.sortEdges(f.Edges) + edges = DraftGeomUtils.sortEdges(f.Edges) l = len(edges) edges.append(edges[0]) shps = [] for i in range(l): - v = fcgeo.vec(fcgeo.angleBisection(edges[i],edges[i+1])) + v = DraftGeomUtils.vec(DraftGeomUtils.angleBisection(edges[i],edges[i+1])) v.normalize() - bis = v.getAngle(fcgeo.vec(edges[i])) + bis = v.getAngle(DraftGeomUtils.vec(edges[i])) delta = 1/math.cos(bis) v.multiply(delta) n = (FreeCAD.Vector(norm)).multiply(c) @@ -137,7 +135,7 @@ class _Roof(ArchComponent.Component): c = c.removeSplitter() if not c.isNull(): obj.Shape = c - if not fcgeo.isNull(pl): + if not DraftGeomUtils.isNull(pl): obj.Placement = pl class _ViewProviderRoof(ArchComponent.ViewProviderComponent): diff --git a/src/Mod/Arch/ArchSectionPlane.py b/src/Mod/Arch/ArchSectionPlane.py index d1c1ada50..59c802382 100644 --- a/src/Mod/Arch/ArchSectionPlane.py +++ b/src/Mod/Arch/ArchSectionPlane.py @@ -21,11 +21,10 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,Drawing,math,Draft,ArchCommands +import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,Drawing,math,Draft,ArchCommands, DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore from pivy import coin -from draftlibs import fcvec class _CommandSectionPlane: @@ -176,8 +175,7 @@ class _ArchDrawingView: def updateSVG(self, obj,join=False): "encapsulates a svg fragment into a transformation node" - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils if hasattr(obj,"Source"): if obj.Source: if obj.Source.Objects: @@ -207,7 +205,7 @@ class _ArchDrawingView: base = shape.pop() for sh in shapes: base = base.fuse(sh) - svgf = Drawing.projectToSVG(base,fcvec.neg(direction)) + svgf = Drawing.projectToSVG(base,DraftVecUtils.neg(direction)) if svgf: svgf = svgf.replace('stroke-width="0.35"','stroke-width="' + str(linewidth) + 'px"') svg += svgf diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py index cd87115eb..2327ad7ca 100644 --- a/src/Mod/Arch/ArchStructure.py +++ b/src/Mod/Arch/ArchStructure.py @@ -21,8 +21,7 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Draft,ArchComponent -from draftlibs import fcvec +import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore @@ -99,7 +98,7 @@ class _Structure(ArchComponent.Component): def getAxisPoints(self,obj): "returns the gridpoints of linked axes" - from draftlibs import fcgeo + import DraftGeomUtils pts = [] if len(obj.Axes) == 1: for e in obj.Axes[0].Shape.Edges: @@ -109,12 +108,11 @@ class _Structure(ArchComponent.Component): set2 = obj.Axes[1].Shape.Edges for e1 in set1: for e2 in set2: - pts.extend(fcgeo.findIntersection(e1,e2)) + pts.extend(DraftGeomUtils.findIntersection(e1,e2)) return pts def createGeometry(self,obj): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils # getting default values height = normal = None if obj.Length: @@ -187,7 +185,7 @@ class _Structure(ArchComponent.Component): obj.Shape = Part.makeCompound(fsh) else: obj.Shape = base - if not fcgeo.isNull(pl): obj.Placement = pl + if not DraftGeomUtils.isNull(pl): obj.Placement = pl class _ViewProviderStructure(ArchComponent.ViewProviderComponent): "A View Provider for the Structure object" diff --git a/src/Mod/Arch/ArchVRM.py b/src/Mod/Arch/ArchVRM.py index f7e5988ab..2de8ad0b3 100644 --- a/src/Mod/Arch/ArchVRM.py +++ b/src/Mod/Arch/ArchVRM.py @@ -23,8 +23,7 @@ "The FreeCAD Arch Vector Rendering Module" -import FreeCAD,math,Part,ArchCommands -from draftlibs import fcvec,fcgeo +import FreeCAD,math,Part,ArchCommands,DraftVecUtils,DraftGeomUtils DEBUG = True # if we want debug messages MAXLOOP = 10 # the max number of loop before abort @@ -171,7 +170,7 @@ class Renderer: norm = face[0].normalAt(0,0) for w in face[0].Wires: verts = [] - edges = fcgeo.sortEdges(w.Edges) + edges = DraftGeomUtils.sortEdges(w.Edges) for e in edges: v = e.Vertexes[0].Point v = self.wp.getLocalCoords(v) @@ -196,7 +195,7 @@ class Renderer: wires = [] for w in face[0].Wires: verts = [] - edges = fcgeo.sortEdges(w.Edges) + edges = DraftGeomUtils.sortEdges(w.Edges) for e in edges: v = e.Vertexes[0].Point verts.append(FreeCAD.Vector(v.x,v.y,0)) @@ -239,11 +238,11 @@ class Renderer: FreeCAD.Vector(bb.XMax,bb.YMax,bb.ZMax)] for c in corners: dv = c.sub(placement.Base) - um1 = fcvec.project(dv,self.wp.u).Length + um1 = DraftVecUtils.project(dv,self.wp.u).Length um = max(um,um1) - vm1 = fcvec.project(dv,self.wp.v).Length + vm1 = DraftVecUtils.project(dv,self.wp.v).Length vm = max(vm,vm1) - wm1 = fcvec.project(dv,self.wp.axis).Length + wm1 = DraftVecUtils.project(dv,self.wp.axis).Length wm = max(wm,wm1) p1 = FreeCAD.Vector(-um,vm,0) p2 = FreeCAD.Vector(um,vm,0) @@ -252,7 +251,7 @@ class Renderer: cutface = Part.makePolygon([p1,p2,p3,p4,p1]) cutface = Part.Face(cutface) cutface.Placement = placement - cutnormal = fcvec.scaleTo(self.wp.axis,wm) + cutnormal = DraftVecUtils.scaleTo(self.wp.axis,wm) cutvolume = cutface.extrude(cutnormal) shapes = [] faces = [] @@ -265,7 +264,7 @@ class Renderer: faces.append([f]+sh[1:]) sec = sol.section(cutface) if sec.Edges: - wires = fcgeo.findWires(sec.Edges) + wires = DraftGeomUtils.findWires(sec.Edges) for w in wires: sec = Part.Face(w) sections.append([sec,fill]) @@ -313,7 +312,7 @@ class Renderer: # even so, faces can still overlap if their edges cross each other for e1 in face1[0].Edges: for e2 in face2[0].Edges: - if fcgeo.findIntersection(e1,e2): + if DraftGeomUtils.findIntersection(e1,e2): return True return False @@ -354,8 +353,8 @@ class Renderer: front = 0 for v in face1[0].Vertexes: dv = v.Point.sub(face2[0].Vertexes[0].Point) - dv = fcvec.project(dv,norm) - if fcvec.isNull(dv): + dv = DraftVecUtils.project(dv,norm) + if DraftVecUtils.isNull(dv): behind += 1 front += 1 else: @@ -377,8 +376,8 @@ class Renderer: front = 0 for v in face2[0].Vertexes: dv = v.Point.sub(face1[0].Vertexes[0].Point) - dv = fcvec.project(dv,norm) - if fcvec.isNull(dv): + dv = DraftVecUtils.project(dv,norm) + if DraftVecUtils.isNull(dv): behind += 1 front += 1 else: @@ -545,7 +544,7 @@ class Renderer: def getPathData(self,w): "Returns a SVG path data string from a 2D wire" - edges = fcgeo.sortEdges(w.Edges) + edges = DraftGeomUtils.sortEdges(w.Edges) v = edges[0].Vertexes[0].Point svg = 'M '+ str(v.x) +' '+ str(v.y) + ' ' for e in edges: diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index 36c33e7a8..c26125136 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -21,8 +21,7 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Draft,ArchComponent -from draftlibs import fcvec +import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore @@ -180,13 +179,13 @@ class _CommandWall: n = FreeCAD.DraftWorkingPlane.axis bv = point.sub(b) dv = bv.cross(n) - dv = fcvec.scaleTo(dv,self.Width/2) + dv = DraftVecUtils.scaleTo(dv,self.Width/2) if self.Align == "Center": self.tracker.update([b,point]) elif self.Align == "Left": self.tracker.update([b.add(dv),point.add(dv)]) else: - dv = fcvec.neg(dv) + dv = DraftVecUtils.neg(dv) self.tracker.update([b.add(dv),point.add(dv)]) def taskbox(self): @@ -275,10 +274,10 @@ class _Wall(ArchComponent.Component): f = w f = Part.Face(f) n = f.normalAt(0,0) - v1 = fcvec.scaleTo(n,width) + v1 = DraftVecUtils.scaleTo(n,width) f.translate(v1) - v2 = fcvec.neg(v1) - v2 = fcvec.scale(v1,-2) + v2 = DraftVecUtils.neg(v1) + v2 = DraftVecUtils.scale(v1,-2) f = f.extrude(v2) if delta: f.translate(delta) @@ -290,8 +289,7 @@ class _Wall(ArchComponent.Component): if not obj.Base: return - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils flat = False if hasattr(obj.ViewObject,"DisplayMode"): @@ -304,25 +302,25 @@ class _Wall(ArchComponent.Component): def getbase(wire): "returns a full shape from a base wire" - dvec = fcgeo.vec(wire.Edges[0]).cross(normal) + dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal) dvec.normalize() if obj.Align == "Left": dvec = dvec.multiply(width) - w2 = fcgeo.offsetWire(wire,dvec) - w1 = Part.Wire(fcgeo.sortEdges(wire.Edges)) - sh = fcgeo.bind(w1,w2) + w2 = DraftGeomUtils.offsetWire(wire,dvec) + w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) + sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Right": dvec = dvec.multiply(width) - dvec = fcvec.neg(dvec) - w2 = fcgeo.offsetWire(wire,dvec) - w1 = Part.Wire(fcgeo.sortEdges(wire.Edges)) - sh = fcgeo.bind(w1,w2) + dvec = DraftVecUtils.neg(dvec) + w2 = DraftGeomUtils.offsetWire(wire,dvec) + w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) + sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Center": dvec = dvec.multiply(width/2) - w1 = fcgeo.offsetWire(wire,dvec) - dvec = fcvec.neg(dvec) - w2 = fcgeo.offsetWire(wire,dvec) - sh = fcgeo.bind(w1,w2) + w1 = DraftGeomUtils.offsetWire(wire,dvec) + dvec = DraftVecUtils.neg(dvec) + w2 = DraftGeomUtils.offsetWire(wire,dvec) + sh = DraftGeomUtils.bind(w1,w2) # fixing self-intersections sh.fix(0.1,0,1) if height and (not flat): @@ -388,7 +386,7 @@ class _Wall(ArchComponent.Component): if base: obj.Shape = base - if not fcgeo.isNull(pl): + if not DraftGeomUtils.isNull(pl): obj.Placement = pl class _ViewProviderWall(ArchComponent.ViewProviderComponent): diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 2cdf513c9..35813ddfc 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -21,8 +21,7 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Draft,ArchComponent -from draftlibs import fcvec +import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore,QtGui @@ -109,8 +108,7 @@ class _Window(ArchComponent.Component): self.createGeometry(obj) def createGeometry(self,obj): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils pl = obj.Placement if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): @@ -135,7 +133,7 @@ class _Window(ArchComponent.Component): norm = shape.normalAt(0,0) thk = float(obj.WindowParts[(i*5)+3]) if thk: - exv = fcvec.scaleTo(norm,thk) + exv = DraftVecUtils.scaleTo(norm,thk) shape = shape.extrude(exv) for w in wires: f = Part.Face(w) @@ -144,12 +142,12 @@ class _Window(ArchComponent.Component): if obj.WindowParts[(i*5)+4]: zof = float(obj.WindowParts[(i*5)+4]) if zof: - zov = fcvec.scaleTo(norm,zof) + zov = DraftVecUtils.scaleTo(norm,zof) shape.translate(zov) print shape shapes.append(shape) obj.Shape = Part.makeCompound(shapes) - if not fcgeo.isNull(pl): + if not DraftGeomUtils.isNull(pl): obj.Placement = pl class _ViewProviderWindow(ArchComponent.ViewProviderComponent): diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index 7a0cf8ae0..17dc3d166 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -21,8 +21,7 @@ #* * #*************************************************************************** -import ifcReader, FreeCAD, Arch, Draft, os, sys, time, Part -from draftlibs import fcvec +import ifcReader, FreeCAD, Arch, Draft, os, sys, time, Part, DraftVecUtils __title__="FreeCAD IFC importer" __author__ = "Yorik van Havre" @@ -448,7 +447,7 @@ def getPlacement(entity): z = getVector(entity.Axis) y = z.cross(x) loc = getVector(entity.Location) - m = fcvec.getPlaneRotation(x,y,z) + m = DraftVecUtils.getPlaneRotation(x,y,z) pl = FreeCAD.Placement(m) pl.move(loc) elif entity.type == "IFCLOCALPLACEMENT": diff --git a/src/Mod/Arch/importOBJ.py b/src/Mod/Arch/importOBJ.py index e5ddca434..4622e1adf 100644 --- a/src/Mod/Arch/importOBJ.py +++ b/src/Mod/Arch/importOBJ.py @@ -21,8 +21,7 @@ #* * #*************************************************************************** -import FreeCAD -from draftlibs import fcgeo +import FreeCAD, DraftGeomUtils if open.__module__ == '__builtin__': pythonopen = open @@ -42,7 +41,7 @@ def getIndices(shape,offset): for f in shape.Faces: fi = "" # OCC vertices are unsorted. We need to sort in the right order... - edges = fcgeo.sortEdges(f.Wire.Edges) + edges = DraftGeomUtils.sortEdges(f.Wire.Edges) print edges for e in edges: print e.Vertexes[0].Point,e.Vertexes[1].Point diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index 99e27d0f9..3d1288561 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -7,6 +7,8 @@ SET(Draft_SRCS DraftGui.py DraftSnap.py DraftTrackers.py + DraftVecUtils.py + DraftGeomUtils.py WorkingPlane.py importDXF.py importOCA.py @@ -22,8 +24,6 @@ SET(DraftLibs_SRCS draftlibs/dxfImportObjects.py draftlibs/dxfLibrary.py draftlibs/dxfReader.py - draftlibs/fcgeo.py - draftlibs/fcvec.py draftlibs/__init__.py ) SOURCE_GROUP("draftlibs" FILES ${DraftLibs_SRCS}) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 0014a4513..300bc8692 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -54,9 +54,9 @@ How it works / how to extend: - DraftTools.py: Contains the user tools of the Draft module (the commands from the Draft menu), and a couple of helpers such as the "Trackers" (temporary geometry used while drawing) - - draftlibs/fcvec.py: a vector math library, contains functions that are not + - DraftVecUtils.py: a vector math library, contains functions that are not implemented in the standard FreeCAD vector - - draftlibs/fcgeo.py: a library of misc functions to manipulate shapes. + - DraftGeomUtils.py: a library of misc functions to manipulate shapes. The Draft.py contains everything to create geometry in the scene. You should start there if you intend to modify something. Then, the DraftTools @@ -72,9 +72,8 @@ How it works / how to extend: ''' # import FreeCAD modules -import FreeCAD, math, sys, os +import FreeCAD, math, sys, os, DraftVecUtils from FreeCAD import Vector -from draftlibs import fcvec from pivy import coin if FreeCAD.GuiUp: @@ -395,8 +394,8 @@ def makeCircle(radius, placement=None, face=True, startangle=None, endangle=None ref = placement.multVec(FreeCAD.Vector(1,0,0)) v1 = (edge.Vertexes[0].Point).sub(edge.Curve.Center) v2 = (edge.Vertexes[-1].Point).sub(edge.Curve.Center) - a1 = -math.degrees(fcvec.angle(v1,ref)) - a2 = -math.degrees(fcvec.angle(v2,ref)) + a1 = -math.degrees(DraftVecUtils.angle(v1,ref)) + a2 = -math.degrees(DraftVecUtils.angle(v2,ref)) obj.FirstAngle = a1 obj.LastAngle = a2 else: @@ -514,15 +513,14 @@ def makeWire(pointslist,closed=False,placement=None,face=True,support=None): and last points are identical, the wire is closed. If face is true (and wire is closed), the wire will appear filled. Instead of a pointslist, you can also pass a Part Wire.''' - from draftlibs import fcgeo - import Part + import DraftGeomUtils, Part if not isinstance(pointslist,list): e = pointslist.Wires[0].Edges - pointslist = Part.Wire(fcgeo.sortEdges(e)) + pointslist = Part.Wire(DraftGeomUtils.sortEdges(e)) nlist = [] for v in pointslist.Vertexes: nlist.append(v.Point) - if fcgeo.isReallyClosed(pointslist): + if DraftGeomUtils.isReallyClosed(pointslist): closed = True pointslist = nlist print pointslist @@ -774,8 +772,7 @@ def fuse(object1,object2): the union of the 2 given objects. If the objects are coplanar, a special Draft Wire is used, otherwise we use a standard Part fuse.''' - from draftlibs import fcgeo - import Part + import DraftGeomUtils, Part # testing if we have holes: holes = False fshape = object1.Shape.fuse(object2.Shape) @@ -783,7 +780,7 @@ def fuse(object1,object2): for f in fshape.Faces: if len(f.Wires) > 1: holes = True - if fcgeo.isCoplanar(object1.Shape.fuse(object2.Shape).Faces) and not holes: + if DraftGeomUtils.isCoplanar(object1.Shape.fuse(object2.Shape).Faces) and not holes: obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Fusion") _Wire(obj) if gui: @@ -879,12 +876,12 @@ def array(objectslist,arg1,arg2,arg3,arg4=None): typecheck([(xvector,Vector), (yvector,Vector), (xnum,int), (ynum,int)], "rectArray") if not isinstance(objectslist,list): objectslist = [objectslist] for xcount in range(xnum): - currentxvector=fcvec.scale(xvector,xcount) + currentxvector=DraftVecUtils.scale(xvector,xcount) if not xcount==0: move(objectslist,currentxvector,True) for ycount in range(ynum): currentxvector=FreeCAD.Base.Vector(currentxvector) - currentyvector=currentxvector.add(fcvec.scale(yvector,ycount)) + currentyvector=currentxvector.add(DraftVecUtils.scale(yvector,ycount)) if not ycount==0: move(objectslist,currentyvector,True) def polarArray(objectslist,center,angle,num): @@ -918,7 +915,7 @@ def rotate(objectslist,angle,center=Vector(0,0,0),axis=Vector(0,0,1),copy=False) newobj = obj if (obj.isDerivedFrom("Part::Feature")): shape = obj.Shape.copy() - shape.rotate(fcvec.tup(center), fcvec.tup(axis), angle) + shape.rotate(DraftVecUtils.tup(center), DraftVecUtils.tup(axis), angle) newobj.Shape = shape elif (obj.isDerivedFrom("App::Annotation")): if axis.normalize() == Vector(1,0,0): @@ -939,7 +936,7 @@ def rotate(objectslist,angle,center=Vector(0,0,0),axis=Vector(0,0,1),copy=False) elif hasattr(obj,"Placement"): shape = Part.Shape() shape.Placement = obj.Placement - shape.rotate(fcvec.tup(center), fcvec.tup(axis), angle) + shape.rotate(DraftVecUtils.tup(center), DraftVecUtils.tup(axis), angle) newobj.Placement = shape.Placement if copy: formatObject(newobj,obj) @@ -972,7 +969,7 @@ def scale(objectslist,delta=Vector(1,1,1),center=Vector(0,0,0),copy=False,legacy sh = sh.transformGeometry(m) corr = Vector(center.x,center.y,center.z) corr.scale(delta.x,delta.y,delta.z) - corr = fcvec.neg(corr.sub(center)) + corr = DraftVecUtils.neg(corr.sub(center)) sh.translate(corr) if getType(obj) == "Rectangle": p = [] @@ -982,8 +979,8 @@ def scale(objectslist,delta=Vector(1,1,1),center=Vector(0,0,0),copy=False,legacy diag = p[2].sub(p[0]) bb = p[1].sub(p[0]) bh = p[3].sub(p[0]) - nb = fcvec.project(diag,bb) - nh = fcvec.project(diag,bh) + nb = DraftVecUtils.project(diag,bb) + nh = DraftVecUtils.project(diag,bh) if obj.Length < 0: l = -nb.Length else: l = nb.Length if obj.Height < 0: h = -nh.Length @@ -1016,7 +1013,7 @@ def scale(objectslist,delta=Vector(1,1,1),center=Vector(0,0,0),copy=False,legacy obj.Scale = delta corr = Vector(center.x,center.y,center.z) corr.scale(delta.x,delta.y,delta.z) - corr = fcvec.neg(corr.sub(center)) + corr = DraftVecUtils.neg(corr.sub(center)) p = obj.Placement p.move(corr) obj.Placement = p @@ -1037,8 +1034,7 @@ def offset(obj,delta,copy=False,bind=False,sym=False,occ=False): and the offsetted wires will be bound by their endpoints, forming a face if sym is True, bind must be true too, and the offset is made on both sides, the total width being the given delta length.''' - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils def getRect(p,obj): "returns length,heigh,placement" @@ -1047,8 +1043,8 @@ def offset(obj,delta,copy=False,bind=False,sym=False,occ=False): diag = p[2].sub(p[0]) bb = p[1].sub(p[0]) bh = p[3].sub(p[0]) - nb = fcvec.project(diag,bb) - nh = fcvec.project(diag,bh) + nb = DraftVecUtils.project(diag,bb) + nh = DraftVecUtils.project(diag,bh) if obj.Length < 0: l = -nb.Length else: l = nb.Length if obj.Height < 0: h = -nh.Length @@ -1058,7 +1054,7 @@ def offset(obj,delta,copy=False,bind=False,sym=False,occ=False): def getRadius(obj,delta): "returns a new radius for a regular polygon" an = math.pi/obj.FacesNumber - nr = fcvec.rotate(delta,-an) + nr = DraftVecUtils.rotate(delta,-an) nr.multiply(1/math.cos(an)) nr = obj.Shape.Vertexes[0].Point.add(nr) nr = nr.sub(obj.Placement.Base) @@ -1075,18 +1071,18 @@ def offset(obj,delta,copy=False,bind=False,sym=False,occ=False): else: if sym: d1 = delta.multiply(0.5) - d2 = fcvec.neg(d1) - n1 = fcgeo.offsetWire(obj.Shape,d1) - n2 = fcgeo.offsetWire(obj.Shape,d2) + d2 = DraftVecUtils.neg(d1) + n1 = DraftGeomUtils.offsetWire(obj.Shape,d1) + n2 = DraftGeomUtils.offsetWire(obj.Shape,d2) else: - newwire = fcgeo.offsetWire(obj.Shape,delta) - p = fcgeo.getVerts(newwire) + newwire = DraftGeomUtils.offsetWire(obj.Shape,delta) + p = DraftGeomUtils.getVerts(newwire) if occ: newobj = FreeCAD.ActiveDocument.addObject("Part::Feature","Offset") - newobj.Shape = fcgeo.offsetWire(obj.Shape,delta,occ=True) + newobj.Shape = DraftGeomUtils.offsetWire(obj.Shape,delta,occ=True) formatObject(newobj,obj) elif bind: - if not fcgeo.isReallyClosed(obj.Shape): + if not DraftGeomUtils.isReallyClosed(obj.Shape): if sym: s1 = n1 s2 = n2 @@ -1161,8 +1157,7 @@ def draftify(objectslist,makeblock=False): '''draftify(objectslist,[makeblock]): turns each object of the given list (objectslist can also be a single object) into a Draft parametric wire. If makeblock is True, multiple objects will be grouped in a block''' - from draftlibs import fcgeo - import Part + import DraftGeomUtils, Part if not isinstance(objectslist,list): objectslist = [objectslist] @@ -1170,7 +1165,7 @@ def draftify(objectslist,makeblock=False): for obj in objectslist: if obj.isDerivedFrom('Part::Feature'): for w in obj.Shape.Wires: - if fcgeo.hasCurves(w): + if DraftGeomUtils.hasCurves(w): if (len(w.Edges) == 1) and isinstance(w.Edges[0].Curve,Part.Circle): nobj = makeCircle(w.Edges[0]) else: @@ -1199,8 +1194,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct with the given linewidth and fontsize (used if the given object contains any text). You can also supply an arbitrary projection vector. the scale parameter allows to scale linewidths down, so they are resolution-independant.''' - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils svg = "" linewidth = linewidth/scale fontsize = (fontsize/scale)/2 @@ -1209,7 +1203,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct if isinstance(direction,FreeCAD.Vector): if direction != Vector(0,0,0): plane = WorkingPlane.plane() - plane.alignToPointAndAxis(Vector(0,0,0),fcvec.neg(direction),0) + plane.alignToPointAndAxis(Vector(0,0,0),DraftVecUtils.neg(direction),0) elif isinstance(direction,WorkingPlane.plane): plane = direction @@ -1240,10 +1234,10 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct def getProj(vec): if not plane: return vec - nx = fcvec.project(vec,plane.u) + nx = DraftVecUtils.project(vec,plane.u) lx = nx.Length if abs(nx.getAngle(plane.u)) > 0.1: lx = -lx - ny = fcvec.project(vec,plane.v) + ny = DraftVecUtils.project(vec,plane.v) ly = ny.Length if abs(ny.getAngle(plane.v)) > 0.1: ly = -ly return Vector(lx,ly,0) @@ -1255,7 +1249,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct def getPath(edges): svg =' dmax): - p1 = p2.add(fcvec.scaleTo(proj,dmax)) - p4 = p3.add(fcvec.scaleTo(proj,dmax)) - midpoint = p2.add(fcvec.scale(p3.sub(p2),0.5)) + p1 = p2.add(DraftVecUtils.scaleTo(proj,dmax)) + p4 = p3.add(DraftVecUtils.scaleTo(proj,dmax)) + midpoint = p2.add(DraftVecUtils.scale(p3.sub(p2),0.5)) if not proj: - ed = fcgeo.vec(base) + ed = DraftGeomUtils.vec(base) proj = ed.cross(Vector(0,0,1)) if not proj: norm = Vector(0,0,1) - else: norm = fcvec.neg(p3.sub(p2).cross(proj)) - if not fcvec.isNull(norm): + else: norm = DraftVecUtils.neg(p3.sub(p2).cross(proj)) + if not DraftVecUtils.isNull(norm): norm.normalize() va = get3DView().getViewDirection() if va.getAngle(norm) < math.pi/2: - norm = fcvec.neg(norm) + norm = DraftVecUtils.neg(norm) u = p3.sub(p2) u.normalize() c = get3DView().getCameraNode() r = c.orientation.getValue() ru = Vector(r.multVec(coin.SbVec3f(1,0,0)).getValue()) - if ru.getAngle(u) > math.pi/2: u = fcvec.neg(u) + if ru.getAngle(u) > math.pi/2: u = DraftVecUtils.neg(u) v = norm.cross(u) - offset = fcvec.scaleTo(v,obj.ViewObject.FontSize*.2) + offset = DraftVecUtils.scaleTo(v,obj.ViewObject.FontSize*.2) if obj.ViewObject: if hasattr(obj.ViewObject,"DisplayMode"): if obj.ViewObject.DisplayMode == "3D": - offset = fcvec.neg(offset) + offset = DraftVecUtils.neg(offset) if hasattr(obj.ViewObject,"TextPosition"): if obj.ViewObject.TextPosition == Vector(0,0,0): tbase = midpoint.add(offset) @@ -1839,7 +1831,7 @@ class _ViewProviderDimension: tbase = obj.ViewObject.TextPosition else: tbase = midpoint.add(offset) - rot = FreeCAD.Placement(fcvec.getPlaneRotation(u,v,norm)).Rotation.Q + rot = FreeCAD.Placement(DraftVecUtils.getPlaneRotation(u,v,norm)).Rotation.Q return p1,p2,p3,p4,tbase,norm,rot def attach(self, obj): @@ -1858,7 +1850,7 @@ class _ViewProviderDimension: self.text.string = self.text3d.string = '' self.textpos = coin.SoTransform() self.textpos.translation.setValue([tbase.x,tbase.y,tbase.z]) - tm = fcvec.getPlaneRotation(p3.sub(p2),norm) + tm = DraftVecUtils.getPlaneRotation(p3.sub(p2),norm) rm = coin.SbRotation() self.textpos.rotation = rm label = coin.SoSeparator() @@ -1917,11 +1909,11 @@ class _ViewProviderDimension: # arc linked dimension e = obj.Base.Shape.Edges[obj.LinkedVertices[0]] c = e.Curve.Center - bray = fcvec.scaleTo(obj.Dimline.sub(c),e.Curve.Radius) + bray = DraftVecUtils.scaleTo(obj.Dimline.sub(c),e.Curve.Radius) if obj.LinkedVertices[1] == 1: v1 = c else: - v1 = c.add(fcvec.neg(bray)) + v1 = c.add(DraftVecUtils.neg(bray)) v2 = c.add(bray) else: # linear linked dimension @@ -1952,8 +1944,8 @@ class _ViewProviderDimension: else: ts = (len(text)*obj.ViewObject.FontSize)/4 rm = ((p3.sub(p2)).Length/2)-ts - p2a = p2.add(fcvec.scaleTo(p3.sub(p2),rm)) - p2b = p3.add(fcvec.scaleTo(p2.sub(p3),rm)) + p2a = p2.add(DraftVecUtils.scaleTo(p3.sub(p2),rm)) + p2b = p3.add(DraftVecUtils.scaleTo(p2.sub(p3),rm)) self.coords.point.setValues([[p1.x,p1.y,p1.z], [p2.x,p2.y,p2.z], [p2a.x,p2a.y,p2a.z], @@ -2149,15 +2141,14 @@ class _ViewProviderAngularDimension: self.onChanged(vobj,"FontName") def calcGeom(self,obj): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils rad = (obj.Dimline.sub(obj.Center)).Length cir = Part.makeCircle(rad,obj.Center,Vector(0,0,1),obj.FirstAngle,obj.LastAngle) - cp = fcgeo.findMidpoint(cir.Edges[0]) + cp = DraftGeomUtils.findMidpoint(cir.Edges[0]) rv = cp.sub(obj.Center) - rv = fcvec.scaleTo(rv,rv.Length + obj.ViewObject.FontSize*.2) + rv = DraftVecUtils.scaleTo(rv,rv.Length + obj.ViewObject.FontSize*.2) tbase = obj.Center.add(rv) - trot = fcvec.angle(rv)-math.pi/2 + trot = DraftVecUtils.angle(rv)-math.pi/2 if (trot > math.pi/2) or (trot < -math.pi/2): trot = trot + math.pi s = getParam("dimorientation") @@ -2276,8 +2267,7 @@ class _Rectangle: self.createGeometry(fp) def createGeometry(self,fp): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils plm = fp.Placement p1 = Vector(0,0,0) p2 = Vector(p1.x+fp.Length,p1.y,p1.z) @@ -2286,7 +2276,7 @@ class _Rectangle: shape = Part.makePolygon([p1,p2,p3,p4,p1]) if "FilletRadius" in fp.PropertiesList: if fp.FilletRadius != 0: - w = fcgeo.filletWire(shape,fp.FilletRadius) + w = DraftGeomUtils.filletWire(shape,fp.FilletRadius) if w: shape = w shape = Part.Face(shape) @@ -2399,8 +2389,7 @@ class _Wire: fp.Points = pts def createGeometry(self,fp): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils plm = fp.Placement if fp.Base and (not fp.Tool): if fp.Base.isDerivedFrom("Sketcher::SketchObject"): @@ -2416,8 +2405,8 @@ class _Wire: sh1 = fp.Base.Shape.copy() sh2 = fp.Tool.Shape.copy() shape = sh1.fuse(sh2) - if fcgeo.isCoplanar(shape.Faces): - shape = fcgeo.concatenate(shape) + if DraftGeomUtils.isCoplanar(shape.Faces): + shape = DraftGeomUtils.concatenate(shape) fp.Shape = shape p = [] for v in shape.Vertexes: p.append(v.Point) @@ -2430,7 +2419,7 @@ class _Wire: shape = Part.makePolygon(fp.Points+[fp.Points[0]]) if "FilletRadius" in fp.PropertiesList: if fp.FilletRadius != 0: - w = fcgeo.filletWire(shape,fp.FilletRadius) + w = DraftGeomUtils.filletWire(shape,fp.FilletRadius) if w: shape = w shape = Part.Face(shape) @@ -2444,7 +2433,7 @@ class _Wire: shape = Part.Wire(edges) if "FilletRadius" in fp.PropertiesList: if fp.FilletRadius != 0: - w = fcgeo.filletWire(shape,fp.FilletRadius) + w = DraftGeomUtils.filletWire(shape,fp.FilletRadius) if w: shape = w fp.Shape = shape @@ -2510,8 +2499,7 @@ class _Polygon: self.createGeometry(fp) def createGeometry(self,fp): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils plm = fp.Placement angle = (math.pi*2)/fp.FacesNumber if fp.DrawMode == 'inscribed': @@ -2526,7 +2514,7 @@ class _Polygon: shape = Part.makePolygon(pts) if "FilletRadius" in fp.PropertiesList: if fp.FilletRadius != 0: - w = fcgeo.filletWire(shape,fp.FilletRadius) + w = DraftGeomUtils.filletWire(shape,fp.FilletRadius) if w: shape = w shape = Part.Face(shape) @@ -2690,16 +2678,15 @@ class _Shape2DView: self.createGeometry(obj) def createGeometry(self,obj): - import Drawing - from draftlibs import fcgeo + import Drawing, DraftGeomUtils pl = obj.Placement if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): - if not fcvec.isNull(obj.Projection): + if not DraftVecUtils.isNull(obj.Projection): [visibleG0,visibleG1,hiddenG0,hiddenG1] = Drawing.project(obj.Base.Shape,obj.Projection) if visibleG0: obj.Shape = visibleG0 - if not fcgeo.isNull(pl): + if not DraftGeomUtils.isNull(pl): obj.Placement = pl class _Array: @@ -2745,7 +2732,7 @@ class _Array: self.createGeometry(obj) def createGeometry(self,obj): - from draftlibs import fcgeo + import DraftGeomUtils if obj.Base: pl = obj.Placement if obj.ArrayType == "ortho": @@ -2753,21 +2740,21 @@ class _Array: else: sh = self.polarArray(obj.Base.Shape,obj.Center,obj.Angle,obj.NumberPolar,obj.Axis) obj.Shape = sh - if not fcgeo.isNull(pl): + if not DraftGeomUtils.isNull(pl): obj.Placement = pl def rectArray(self,shape,xvector,yvector,xnum,ynum): import Part base = [shape.copy()] for xcount in range(xnum): - currentxvector=fcvec.scale(xvector,xcount) + currentxvector=DraftVecUtils.scale(xvector,xcount) if not xcount==0: nshape = shape.copy() nshape.translate(currentxvector) base.append(nshape) for ycount in range(ynum): currentxvector=FreeCAD.Vector(currentxvector) - currentyvector=currentxvector.add(fcvec.scale(yvector,ycount)) + currentyvector=currentxvector.add(DraftVecUtils.scale(yvector,ycount)) if not ycount==0: nshape = shape.copy() nshape.translate(currentyvector) @@ -2781,7 +2768,7 @@ class _Array: for i in range(num): currangle = fraction + (i*fraction) nshape = shape.copy() - nshape.rotate(fcvec.tup(center), fcvec.tup(axis), currangle) + nshape.rotate(DraftVecUtils.tup(center), DraftVecUtils.tup(axis), currangle) base.append(nshape) return Part.makeCompound(base) @@ -2845,8 +2832,7 @@ class _Clone: self.createGeometry(obj) def createGeometry(self,obj): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils pl = obj.Placement shapes = [] for o in obj.Objects: @@ -2859,7 +2845,7 @@ class _Clone: shapes.append(sh) if shapes: obj.Shape = Part.makeCompound(shapes) - if not fcgeo.isNull(pl): + if not DraftGeomUtils.isNull(pl): obj.Placement = pl class _ViewProviderDraftPart(_ViewProviderDraft): diff --git a/src/Mod/Draft/draftlibs/fcgeo.py b/src/Mod/Draft/DraftGeomUtils.py similarity index 100% rename from src/Mod/Draft/draftlibs/fcgeo.py rename to src/Mod/Draft/DraftGeomUtils.py diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index 50a0b19ba..1479a6568 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -26,9 +26,8 @@ __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -import FreeCAD, FreeCADGui, math, Draft, DraftGui, DraftTrackers +import FreeCAD, FreeCADGui, math, Draft, DraftGui, DraftTrackers, DraftVecUtils from DraftGui import todo,getMainWindow -from draftlibs import fcvec from FreeCAD import Vector from pivy import coin from PyQt4 import QtCore,QtGui @@ -110,9 +109,8 @@ class Snapper: be True to constrain the point against the closest working plane axis. Screenpos can be a list, a tuple or a coin.SbVec2s object.""" - global Part,fcgeo - import Part - from draftlibs import fcgeo + global Part, DraftGeomUtils + import Part, DraftGeomUtils if not hasattr(self,"toolbar"): self.makeSnapToolBar() @@ -355,7 +353,7 @@ class Snapper: for e in edges: if isinstance(e.Curve,Part.Line): np = self.getPerpendicular(e,point) - if not fcgeo.isPtOnEdge(np,e): + if not DraftGeomUtils.isPtOnEdge(np,e): if (np.sub(point)).Length < self.radius: if self.isEnabled('extension'): if np != e.Vertexes[0].Point: @@ -372,7 +370,7 @@ class Snapper: else: if self.isEnabled('parallel'): if last: - de = Part.Line(last,last.add(fcgeo.vec(e))).toShape() + de = Part.Line(last,last.add(DraftGeomUtils.vec(e))).toShape() np = self.getPerpendicular(de,point) if (np.sub(point)).Length < self.radius: if self.tracker: @@ -398,13 +396,13 @@ class Snapper: FreeCAD.Vector(0,0,1)] for a in self.polarAngles: if a == 90: - vecs.extend([ax[0],fcvec.neg(ax[0])]) - vecs.extend([ax[1],fcvec.neg(ax[1])]) + vecs.extend([ax[0],DraftVecUtils.neg(ax[0])]) + vecs.extend([ax[1],DraftVecUtils.neg(ax[1])]) else: - v = fcvec.rotate(ax[0],math.radians(a),ax[2]) - vecs.extend([v,fcvec.neg(v)]) - v = fcvec.rotate(ax[1],math.radians(a),ax[2]) - vecs.extend([v,fcvec.neg(v)]) + v = DraftVecUtils.rotate(ax[0],math.radians(a),ax[2]) + vecs.extend([v,DraftVecUtils.neg(v)]) + v = DraftVecUtils.rotate(ax[1],math.radians(a),ax[2]) + vecs.extend([v,DraftVecUtils.neg(v)]) for v in vecs: de = Part.Line(last,last.add(v)).toShape() np = self.getPerpendicular(de,point) @@ -457,7 +455,7 @@ class Snapper: snaps = [] if self.isEnabled("midpoint"): if isinstance(shape,Part.Edge): - mp = fcgeo.findMidpoint(shape) + mp = DraftGeomUtils.findMidpoint(shape) if mp: snaps.append([mp,'midpoint',mp]) return snaps @@ -472,7 +470,7 @@ class Snapper: np = self.getPerpendicular(shape,last) elif isinstance(shape.Curve,Part.Circle): dv = last.sub(shape.Curve.Center) - dv = fcvec.scaleTo(dv,shape.Curve.Radius) + dv = DraftVecUtils.scaleTo(dv,shape.Curve.Radius) np = (shape.Curve.Center).add(dv) elif isinstance(shape.Curve,Part.BSplineCurve): pr = shape.Curve.parameter(last) @@ -493,7 +491,7 @@ class Snapper: if self.constraintAxis: tmpEdge = Part.Line(last,last.add(self.constraintAxis)).toShape() # get the intersection points - pt = fcgeo.findIntersection(tmpEdge,shape,True,True) + pt = DraftGeomUtils.findIntersection(tmpEdge,shape,True,True) if pt: for p in pt: snaps.append([p,'ortho',p]) @@ -506,14 +504,14 @@ class Snapper: tmpEdge1 = Part.Line(last,last.add(self.constraintAxis)).toShape() tmpEdge2 = Part.Line(self.extLine.p1(),self.extLine.p2()).toShape() # get the intersection points - pt = fcgeo.findIntersection(tmpEdge1,tmpEdge2,True,True) + pt = DraftGeomUtils.findIntersection(tmpEdge1,tmpEdge2,True,True) if pt: return [pt[0],'ortho',pt[0]] if eline: try: tmpEdge2 = Part.Line(self.extLine.p1(),self.extLine.p2()).toShape() # get the intersection points - pt = fcgeo.findIntersection(eline,tmpEdge2,True,True) + pt = DraftGeomUtils.findIntersection(eline,tmpEdge2,True,True) if pt: return [pt[0],'ortho',pt[0]] except: @@ -526,7 +524,7 @@ class Snapper: if self.isEnabled("intersection") and self.isEnabled("extension"): if e1 and e2: # get the intersection points - pts = fcgeo.findIntersection(e1,e2,True,True) + pts = DraftGeomUtils.findIntersection(e1,e2,True,True) if pts: for p in pts: snaps.append([p,'intersection',p]) @@ -569,7 +567,7 @@ class Snapper: if (not self.maxEdges) or (len(obj.Shape.Edges) <= self.maxEdges): for e in obj.Shape.Edges: # get the intersection points - pt = fcgeo.findIntersection(e,shape) + pt = DraftGeomUtils.findIntersection(e,shape) if pt: for p in pt: snaps.append([p,'intersection',p]) @@ -597,7 +595,7 @@ class Snapper: def getPerpendicular(self,edge,pt): "returns a point on an edge, perpendicular to the given point" dv = pt.sub(edge.Vertexes[0].Point) - nv = fcvec.project(dv,fcgeo.vec(edge)) + nv = DraftVecUtils.project(dv,DraftGeomUtils.vec(edge)) np = (edge.Vertexes[0].Point).add(nv) return np @@ -690,7 +688,7 @@ class Snapper: self.constraintAxis = FreeCAD.DraftWorkingPlane.axis # calculating constrained point - cdelta = fcvec.project(delta,self.constraintAxis) + cdelta = DraftVecUtils.project(delta,self.constraintAxis) npoint = self.basepoint.add(cdelta) # setting constrain line diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index ad61cf65d..bde2ad4a7 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -29,9 +29,8 @@ __url__ = "http://free-cad.sourceforge.net" # Generic stuff #--------------------------------------------------------------------------- -import os, FreeCAD, FreeCADGui, WorkingPlane, math, re, importSVG, Draft, Draft_rc +import os, FreeCAD, FreeCADGui, WorkingPlane, math, re, importSVG, Draft, Draft_rc, DraftVecUtils from functools import partial -from draftlibs import fcvec from FreeCAD import Vector from DraftGui import todo,QtCore,QtGui from DraftSnap import * @@ -283,7 +282,7 @@ class SelectPlane: self.display('side') self.finish() elif arg == "currentView": - viewDirection = fcvec.neg(self.view.getViewDirection()) + viewDirection = DraftVecUtils.neg(self.view.getViewDirection()) plane.alignToPointAndAxis(Vector(0,0,0), viewDirection, self.offset) self.display(viewDirection) self.finish() @@ -327,9 +326,8 @@ class Creator: def Activated(self,name="None"): if FreeCAD.activeDraftCommand: FreeCAD.activeDraftCommand.finish() - global Part, fcgeo - import Part - from draftlibs import fcgeo + global Part, DraftGeomUtils + import Part, DraftGeomUtils self.ui = None self.call = None self.doc = None @@ -348,7 +346,7 @@ class Creator: self.ui.show() rot = self.view.getCameraNode().getField("orientation").getValue() upv = Vector(rot.multVec(coin.SbVec3f(0,1,0)).getValue()) - plane.setup(fcvec.neg(self.view.getViewDirection()), Vector(0,0,0), upv) + plane.setup(DraftVecUtils.neg(self.view.getViewDirection()), Vector(0,0,0), upv) self.node = [] self.pos = [] self.constrain = None @@ -721,12 +719,12 @@ class Rectangle(Creator): p1 = self.node[0] p3 = self.node[-1] diagonal = p3.sub(p1) - p2 = p1.add(fcvec.project(diagonal, plane.v)) - p4 = p1.add(fcvec.project(diagonal, plane.u)) + p2 = p1.add(DraftVecUtils.project(diagonal, plane.v)) + p4 = p1.add(DraftVecUtils.project(diagonal, plane.u)) length = p4.sub(p1).Length - if abs(fcvec.angle(p4.sub(p1),plane.u,plane.axis)) > 1: length = -length + if abs(DraftVecUtils.angle(p4.sub(p1),plane.u,plane.axis)) > 1: length = -length height = p2.sub(p1).Length - if abs(fcvec.angle(p2.sub(p1),plane.v,plane.axis)) > 1: height = -height + if abs(DraftVecUtils.angle(p2.sub(p1),plane.v,plane.axis)) > 1: height = -height p = plane.getRotation() p.move(p1) try: @@ -847,10 +845,10 @@ class Arc(Creator): point,ctrlPoint,info = getPoint(self,arg) # this is to make sure radius is what you see on screen self.ui.cross(True) - if self.center and fcvec.dist(point,self.center) > 0: - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): - point = point.add(fcvec.neg(viewdelta)) + if self.center and DraftVecUtils.dist(point,self.center) > 0: + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): + point = point.add(DraftVecUtils.neg(viewdelta)) if (self.step == 0): # choose center if hasMod(arg,MODALT): if not self.altdown: @@ -864,12 +862,12 @@ class Arc(Creator): self.ui.switchUi(False) elif (self.step == 1): # choose radius if len(self.tangents) == 2: - cir = fcgeo.circleFrom2tan1pt(self.tangents[0], self.tangents[1], point) - self.center = fcgeo.findClosestCircle(point,cir).Center + cir = DraftGeomUtils.circleFrom2tan1pt(self.tangents[0], self.tangents[1], point) + self.center = DraftGeomUtils.findClosestCircle(point,cir).Center self.arctrack.setCenter(self.center) elif self.tangents and self.tanpoints: - cir = fcgeo.circleFrom1tan2pt(self.tangents[0], self.tanpoints[0], point) - self.center = fcgeo.findClosestCircle(point,cir).Center + cir = DraftGeomUtils.circleFrom1tan2pt(self.tangents[0], self.tanpoints[0], point) + self.center = DraftGeomUtils.findClosestCircle(point,cir).Center self.arctrack.setCenter(self.center) if hasMod(arg,MODALT): if not self.altdown: @@ -880,20 +878,20 @@ class Arc(Creator): num = int(info['Component'].lstrip('Edge'))-1 ed = ob.Shape.Edges[num] if len(self.tangents) == 2: - cir = fcgeo.circleFrom3tan(self.tangents[0], self.tangents[1], ed) - cl = fcgeo.findClosestCircle(point,cir) + cir = DraftGeomUtils.circleFrom3tan(self.tangents[0], self.tangents[1], ed) + cl = DraftGeomUtils.findClosestCircle(point,cir) self.center = cl.Center self.rad = cl.Radius self.arctrack.setCenter(self.center) else: - self.rad = self.center.add(fcgeo.findDistance(self.center,ed).sub(self.center)).Length + self.rad = self.center.add(DraftGeomUtils.findDistance(self.center,ed).sub(self.center)).Length else: - self.rad = fcvec.dist(point,self.center) + self.rad = DraftVecUtils.dist(point,self.center) else: if self.altdown: self.ui.cross(True) self.altdown = False - self.rad = fcvec.dist(point,self.center) + self.rad = DraftVecUtils.dist(point,self.center) self.ui.setRadiusValue(self.rad) self.arctrack.setRadius(self.rad) # Draw constraint tracker line. @@ -907,11 +905,11 @@ class Arc(Creator): self.linetrack.p2(point) self.linetrack.on() elif (self.step == 2): # choose first angle - currentrad = fcvec.dist(point,self.center) + currentrad = DraftVecUtils.dist(point,self.center) if currentrad != 0: - angle = fcvec.angle(plane.u, point.sub(self.center), plane.axis) + angle = DraftVecUtils.angle(plane.u, point.sub(self.center), plane.axis) else: angle = 0 - self.linetrack.p2(fcvec.scaleTo(point.sub(self.center),self.rad).add(self.center)) + self.linetrack.p2(DraftVecUtils.scaleTo(point.sub(self.center),self.rad).add(self.center)) # Draw constraint tracker line. if hasMod(arg,MODCONSTRAIN): self.constraintrack.p1(point) @@ -922,11 +920,11 @@ class Arc(Creator): self.ui.setRadiusValue(math.degrees(angle)) self.firstangle = angle else: # choose second angle - currentrad = fcvec.dist(point,self.center) + currentrad = DraftVecUtils.dist(point,self.center) if currentrad != 0: - angle = fcvec.angle(plane.u, point.sub(self.center), plane.axis) + angle = DraftVecUtils.angle(plane.u, point.sub(self.center), plane.axis) else: angle = 0 - self.linetrack.p2(fcvec.scaleTo(point.sub(self.center),self.rad).add(self.center)) + self.linetrack.p2(DraftVecUtils.scaleTo(point.sub(self.center),self.rad).add(self.center)) # Draw constraint tracker line. if hasMod(arg,MODCONSTRAIN): self.constraintrack.p1(point) @@ -942,10 +940,10 @@ class Arc(Creator): if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): point,ctrlPoint,info = getPoint(self,arg) # this is to make sure radius is what you see on screen - if self.center and fcvec.dist(point,self.center) > 0: - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): - point = point.add(fcvec.neg(viewdelta)) + if self.center and DraftVecUtils.dist(point,self.center) > 0: + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): + point = point.add(DraftVecUtils.neg(viewdelta)) if (self.step == 0): # choose center self.support = getSupport(arg) if hasMod(arg,MODALT): @@ -990,7 +988,7 @@ class Arc(Creator): self.ui.labelRadius.setText("Aperture") self.step = 3 # scale center->point vector for proper display - u = fcvec.scaleTo(point.sub(self.center), self.rad) + u = DraftVecUtils.scaleTo(point.sub(self.center), self.rad) self.arctrack.setStartAngle(self.firstangle) msg(translate("draft", "Pick aperture:\n")) else: # choose second angle @@ -1036,15 +1034,15 @@ class Arc(Creator): if (self.step == 1): self.rad = rad if len(self.tangents) == 2: - cir = fcgeo.circleFrom2tan1rad(self.tangents[0], self.tangents[1], rad) + cir = DraftGeomUtils.circleFrom2tan1rad(self.tangents[0], self.tangents[1], rad) if self.center: - self.center = fcgeo.findClosestCircle(self.center,cir).Center + self.center = DraftGeomUtils.findClosestCircle(self.center,cir).Center else: self.center = cir[-1].Center elif self.tangents and self.tanpoints: - cir = fcgeo.circleFrom1tan1pt1rad(self.tangents[0],self.tanpoints[0],rad) + cir = DraftGeomUtils.circleFrom1tan1pt1rad(self.tangents[0],self.tanpoints[0],rad) if self.center: - self.center = fcgeo.findClosestCircle(self.center,cir).Center + self.center = DraftGeomUtils.findClosestCircle(self.center,cir).Center else: self.center = cir[-1].Center if self.closedCircle: @@ -1061,9 +1059,9 @@ class Arc(Creator): elif (self.step == 2): self.ui.labelRadius.setText(str(translate("draft", "Aperture"))) self.firstangle = math.radians(rad) - if fcvec.equals(plane.axis, Vector(1,0,0)): u = Vector(0,self.rad,0) - else: u = fcvec.scaleTo(Vector(1,0,0).cross(plane.axis), self.rad) - urotated = fcvec.rotate(u, math.radians(rad), plane.axis) + if DraftVecUtils.equals(plane.axis, Vector(1,0,0)): u = Vector(0,self.rad,0) + else: u = DraftVecUtils.scaleTo(Vector(1,0,0).cross(plane.axis), self.rad) + urotated = DraftVecUtils.rotate(u, math.radians(rad), plane.axis) self.arctrack.setStartAngle(self.firstangle) self.step = 3 self.ui.radiusValue.setText("") @@ -1139,10 +1137,10 @@ class Polygon(Creator): point,ctrlPoint,info = getPoint(self,arg) # this is to make sure radius is what you see on screen self.ui.cross(True) - if self.center and fcvec.dist(point,self.center) > 0: - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): - point = point.add(fcvec.neg(viewdelta)) + if self.center and DraftVecUtils.dist(point,self.center) > 0: + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): + point = point.add(DraftVecUtils.neg(viewdelta)) if (self.step == 0): # choose center if hasMod(arg,MODALT): if not self.altdown: @@ -1156,12 +1154,12 @@ class Polygon(Creator): self.ui.switchUi(False) else: # choose radius if len(self.tangents) == 2: - cir = fcgeo.circleFrom2tan1pt(self.tangents[0], self.tangents[1], point) - self.center = fcgeo.findClosestCircle(point,cir).Center + cir = DraftGeomUtils.circleFrom2tan1pt(self.tangents[0], self.tangents[1], point) + self.center = DraftGeomUtils.findClosestCircle(point,cir).Center self.arctrack.setCenter(self.center) elif self.tangents and self.tanpoints: - cir = fcgeo.circleFrom1tan2pt(self.tangents[0], self.tanpoints[0], point) - self.center = fcgeo.findClosestCircle(point,cir).Center + cir = DraftGeomUtils.circleFrom1tan2pt(self.tangents[0], self.tanpoints[0], point) + self.center = DraftGeomUtils.findClosestCircle(point,cir).Center self.arctrack.setCenter(self.center) if hasMod(arg,MODALT): if not self.altdown: @@ -1173,20 +1171,20 @@ class Polygon(Creator): num = int(snapped['Component'].lstrip('Edge'))-1 ed = ob.Shape.Edges[num] if len(self.tangents) == 2: - cir = fcgeo.circleFrom3tan(self.tangents[0], self.tangents[1], ed) - cl = fcgeo.findClosestCircle(point,cir) + cir = DraftGeomUtils.circleFrom3tan(self.tangents[0], self.tangents[1], ed) + cl = DraftGeomUtils.findClosestCircle(point,cir) self.center = cl.Center self.rad = cl.Radius self.arctrack.setCenter(self.center) else: - self.rad = self.center.add(fcgeo.findDistance(self.center,ed).sub(self.center)).Length + self.rad = self.center.add(DraftGeomUtils.findDistance(self.center,ed).sub(self.center)).Length else: - self.rad = fcvec.dist(point,self.center) + self.rad = DraftVecUtils.dist(point,self.center) else: if self.altdown: self.ui.cross(True) self.altdown = False - self.rad = fcvec.dist(point,self.center) + self.rad = DraftVecUtils.dist(point,self.center) self.ui.setRadiusValue(self.rad) self.arctrack.setRadius(self.rad) # Draw constraint tracker line. @@ -1203,10 +1201,10 @@ class Polygon(Creator): if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): point,ctrlPoint,info = getPoint(self,arg) # this is to make sure radius is what you see on screen - if self.center and fcvec.dist(point,self.center) > 0: - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): - point = point.add(fcvec.neg(viewdelta)) + if self.center and DraftVecUtils.dist(point,self.center) > 0: + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): + point = point.add(DraftVecUtils.neg(viewdelta)) if (self.step == 0): # choose center if not self.node: self.support = getSupport(arg) if hasMod(arg,MODALT): @@ -1265,15 +1263,15 @@ class Polygon(Creator): "this function gets called by the toolbar when valid radius have been entered there" self.rad = rad if len(self.tangents) == 2: - cir = fcgeo.circleFrom2tan1rad(self.tangents[0], self.tangents[1], rad) + cir = DraftGeomUtils.circleFrom2tan1rad(self.tangents[0], self.tangents[1], rad) if self.center: - self.center = fcgeo.findClosestCircle(self.center,cir).Center + self.center = DraftGeomUtils.findClosestCircle(self.center,cir).Center else: self.center = cir[-1].Center elif self.tangents and self.tanpoints: - cir = fcgeo.circleFrom1tan1pt1rad(self.tangents[0],self.tanpoints[0],rad) + cir = DraftGeomUtils.circleFrom1tan1pt1rad(self.tangents[0],self.tanpoints[0],rad) if self.center: - self.center = fcgeo.findClosestCircle(self.center,cir).Center + self.center = DraftGeomUtils.findClosestCircle(self.center,cir).Center else: self.center = cir[-1].Center self.drawPolygon() @@ -1485,7 +1483,7 @@ class Dimension(Creator): r = point.sub(self.center) self.arctrack.setRadius(r.Length) a = self.arctrack.getAngle(point) - pair = fcgeo.getBoundaryAngles(a,self.pts) + pair = DraftGeomUtils.getBoundaryAngles(a,self.pts) if not (pair[0] < a < pair[1]): self.angledata = [4*math.pi-pair[0],2*math.pi-pair[1]] else: @@ -1496,14 +1494,14 @@ class Dimension(Creator): self.altdown = False self.ui.switchUi(False) if self.dir: - point = self.node[0].add(fcvec.project(point.sub(self.node[0]),self.dir)) + point = self.node[0].add(DraftVecUtils.project(point.sub(self.node[0]),self.dir)) if len(self.node) == 2: if self.arcmode and self.edges: cen = self.edges[0].Curve.Center rad = self.edges[0].Curve.Radius baseray = point.sub(cen) - v2 = fcvec.scaleTo(baseray,rad) - v1 = fcvec.neg(v2) + v2 = DraftVecUtils.scaleTo(baseray,rad) + v1 = DraftVecUtils.neg(v2) if shift: self.node = [cen,cen.add(v2)] self.arcmode = "radius" @@ -1574,7 +1572,7 @@ class Dimension(Creator): # there is already a snapped edge, so we start angular dimension self.edges.append(ed) self.node.extend([v1,v2]) # self.node now has the 4 endpoints - c = fcgeo.findIntersection(self.node[0], + c = DraftGeomUtils.findIntersection(self.node[0], self.node[1], self.node[2], self.node[3], @@ -1593,7 +1591,7 @@ class Dimension(Creator): self.dimtrack.on() else: if self.dir: - point = self.node[0].add(fcvec.project(point.sub(self.node[0]),self.dir)) + point = self.node[0].add(DraftVecUtils.project(point.sub(self.node[0]),self.dir)) self.node.append(point) print "node",self.node self.dimtrack.update(self.node) @@ -1610,7 +1608,7 @@ class Dimension(Creator): # for unlinked arc mode: # if self.arcmode: # v = self.node[1].sub(self.node[0]) - # v = fcvec.scale(v,0.5) + # v = DraftVecUtils.scale(v,0.5) # cen = self.node[0].add(v) # self.node = [self.node[0],self.node[1],cen] self.createObject() @@ -1651,9 +1649,8 @@ class Modifier: def Activated(self,name="None"): if FreeCAD.activeDraftCommand: FreeCAD.activeDraftCommand.finish() - global Part, fcgeo - import Part - from draftlibs import fcgeo + global Part, DraftGeomUtils + import Part, DraftGeomUtils self.ui = None self.call = None self.commitList = [] @@ -1667,7 +1664,7 @@ class Modifier: FreeCADGui.draftToolBar.show() rot = self.view.getCameraNode().getField("orientation").getValue() upv = Vector(rot.multVec(coin.SbVec3f(0,1,0)).getValue()) - plane.setup(fcvec.neg(self.view.getViewDirection()), Vector(0,0,0), upv) + plane.setup(DraftVecUtils.neg(self.view.getViewDirection()), Vector(0,0,0), upv) self.node = [] self.ui.sourceCmd = self self.constrain = None @@ -1931,10 +1928,10 @@ class Rotate(Modifier): point,ctrlPoint,info = getPoint(self,arg) self.ui.cross(True) # this is to make sure radius is what you see on screen - if self.center and fcvec.dist(point,self.center): - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): - point = point.add(fcvec.neg(viewdelta)) + if self.center and DraftVecUtils.dist(point,self.center): + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): + point = point.add(DraftVecUtils.neg(viewdelta)) if self.extendedCopy: if not hasMod(arg,MODALT): self.step = 3 @@ -1942,9 +1939,9 @@ class Rotate(Modifier): if (self.step == 0): pass elif (self.step == 1): - currentrad = fcvec.dist(point,self.center) + currentrad = DraftVecUtils.dist(point,self.center) if (currentrad != 0): - angle = fcvec.angle(plane.u, point.sub(self.center), plane.axis) + angle = DraftVecUtils.angle(plane.u, point.sub(self.center), plane.axis) else: angle = 0 self.linetrack.p2(point) # Draw constraint tracker line. @@ -1959,16 +1956,16 @@ class Rotate(Modifier): self.ui.radiusValue.setFocus() self.ui.radiusValue.selectAll() elif (self.step == 2): - currentrad = fcvec.dist(point,self.center) + currentrad = DraftVecUtils.dist(point,self.center) if (currentrad != 0): - angle = fcvec.angle(plane.u, point.sub(self.center), plane.axis) + angle = DraftVecUtils.angle(plane.u, point.sub(self.center), plane.axis) else: angle = 0 if (angle < self.firstangle): sweep = (2*math.pi-self.firstangle)+angle else: sweep = angle - self.firstangle self.arctrack.setApertureAngle(sweep) - self.ghost.trans.rotation.setValue(coin.SbVec3f(fcvec.tup(plane.axis)),sweep) + self.ghost.trans.rotation.setValue(coin.SbVec3f(DraftVecUtils.tup(plane.axis)),sweep) self.linetrack.p2(point) # Draw constraint tracker line. if hasMod(arg,MODCONSTRAIN): @@ -1984,9 +1981,9 @@ class Rotate(Modifier): elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): point,ctrlPoint,info = getPoint(self,arg) - if self.center and fcvec.dist(point,self.center): - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): point = point.add(fcvec.neg(viewdelta)) + if self.center and DraftVecUtils.dist(point,self.center): + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): point = point.add(DraftVecUtils.neg(viewdelta)) if (self.step == 0): self.center = point self.node = [point] @@ -2002,16 +1999,16 @@ class Rotate(Modifier): self.planetrack.set(point) elif (self.step == 1): self.ui.labelRadius.setText("Rotation") - self.rad = fcvec.dist(point,self.center) + self.rad = DraftVecUtils.dist(point,self.center) self.arctrack.on() self.arctrack.setStartPoint(point) self.ghost.on() self.step = 2 msg(translate("draft", "Pick rotation angle:\n")) else: - currentrad = fcvec.dist(point,self.center) + currentrad = DraftVecUtils.dist(point,self.center) angle = point.sub(self.center).getAngle(plane.u) - if fcvec.project(point.sub(self.center), plane.v).getAngle(plane.v) > 1: + if DraftVecUtils.project(point.sub(self.center), plane.v).getAngle(plane.v) > 1: angle = -angle if (angle < self.firstangle): sweep = (2*math.pi-self.firstangle)+angle @@ -2127,33 +2124,33 @@ class Offset(Modifier): self.ui.cross(True) point,ctrlPoint,info = getPoint(self,arg) if hasMod(arg,MODCONSTRAIN) and self.constrainSeg: - dist = fcgeo.findPerpendicular(point,self.shape,self.constrainSeg[1]) + dist = DraftGeomUtils.findPerpendicular(point,self.shape,self.constrainSeg[1]) e = self.shape.Edges[self.constrainSeg[1]] self.constraintrack.p1(e.Vertexes[0].Point) self.constraintrack.p2(point.add(dist[0])) self.constraintrack.on() else: - dist = fcgeo.findPerpendicular(point,self.shape.Edges) + dist = DraftGeomUtils.findPerpendicular(point,self.shape.Edges) self.constraintrack.off() if dist: self.ghost.on() if self.mode == "Wire": - d = fcvec.neg(dist[0]) - v1 = fcgeo.getTangent(self.shape.Edges[0],point) - v2 = fcgeo.getTangent(self.shape.Edges[dist[1]],point) - a = -fcvec.angle(v1,v2) - self.dvec = fcvec.rotate(d,a,plane.axis) + d = DraftVecUtils.neg(dist[0]) + v1 = DraftGeomUtils.getTangent(self.shape.Edges[0],point) + v2 = DraftGeomUtils.getTangent(self.shape.Edges[dist[1]],point) + a = -DraftVecUtils.angle(v1,v2) + self.dvec = DraftVecUtils.rotate(d,a,plane.axis) occmode = self.ui.occOffset.isChecked() - self.ghost.update(fcgeo.offsetWire(self.shape,self.dvec,occ=occmode),forceclosed=occmode) + self.ghost.update(DraftGeomUtils.offsetWire(self.shape,self.dvec,occ=occmode),forceclosed=occmode) elif self.mode == "BSpline": - d = fcvec.neg(dist[0]) + d = DraftVecUtils.neg(dist[0]) e = self.shape.Edges[0] - basetan = fcgeo.getTangent(e,point) + basetan = DraftGeomUtils.getTangent(e,point) self.npts = [] for p in self.sel.Points: - currtan = fcgeo.getTangent(e,p) - a = -fcvec.angle(currtan,basetan) - self.dvec = fcvec.rotate(d,a,plane.axis) + currtan = DraftGeomUtils.getTangent(e,p) + a = -DraftVecUtils.angle(currtan,basetan) + self.dvec = DraftVecUtils.rotate(d,a,plane.axis) self.npts.append(p.add(self.dvec)) self.ghost.update(self.npts) elif self.mode == "Circle": @@ -2329,12 +2326,12 @@ class Upgrade(Modifier): u = faces.pop(0) for f in faces: u = u.fuse(f) - if fcgeo.isCoplanar(faces): + if DraftGeomUtils.isCoplanar(faces): if self.sel[0].ViewObject.DisplayMode == "Wireframe": f = False else: f = True - u = fcgeo.concatenate(u) + u = DraftGeomUtils.concatenate(u) if not curves: # several coplanar and non-curved faces: they can becoem a Draft wire msg(translate("draft", "Found several objects or faces: making a parametric face\n")) @@ -2384,7 +2381,7 @@ class Upgrade(Modifier): else: # only closed wires for w in wires: - if fcgeo.isPlanar(w): + if DraftGeomUtils.isPlanar(w): f = Part.Face(w) faces.append(f) else: @@ -2405,7 +2402,7 @@ class Upgrade(Modifier): edges = openwires[0].Edges if len(edges) > 1: edges.append(Part.Line(p1,p0).toShape()) - w = Part.Wire(fcgeo.sortEdges(edges)) + w = Part.Wire(DraftGeomUtils.sortEdges(edges)) if len(edges) == 1: if len(w.Vertexes) == 2: msg(translate("draft", "Found 1 open edge: making a line\n")) @@ -2433,7 +2430,7 @@ class Upgrade(Modifier): for e in ob.Shape.Edges: edges.append(e) newob = None - nedges = fcgeo.sortEdges(edges[:]) + nedges = DraftGeomUtils.sortEdges(edges[:]) # for e in nedges: print "debug: ",e.Curve,e.Vertexes[0].Point,e.Vertexes[-1].Point w = Part.Wire(nedges) if len(w.Edges) == len(edges): @@ -2643,7 +2640,7 @@ class Trimex(Modifier): self.extrudeMode = False if self.obj.Shape.Wires: self.edges = self.obj.Shape.Wires[0].Edges - self.edges = fcgeo.sortEdges(self.edges) + self.edges = DraftGeomUtils.sortEdges(self.edges) else: self.edges = self.obj.Shape.Edges self.ghost = [] @@ -2707,7 +2704,7 @@ class Trimex(Modifier): "redraws the ghost in extrude mode" self.newpoint = self.obj.Shape.Faces[0].CenterOfMass dvec = self.point.sub(self.newpoint) - if not shift: delta = fcvec.project(dvec,self.normal) + if not shift: delta = DraftVecUtils.project(dvec,self.normal) else: delta = dvec if self.force: ratio = self.force/delta.Length @@ -2733,7 +2730,7 @@ class Trimex(Modifier): for e in self.edges: vlist.append(e.Vertexes[0].Point) vlist.append(self.edges[-1].Vertexes[-1].Point) if shift: npoint = self.activePoint - else: npoint = fcgeo.findClosest(point,vlist) + else: npoint = DraftGeomUtils.findClosest(point,vlist) if npoint > len(self.edges)/2: reverse = True if alt: reverse = not reverse self.activePoint = npoint @@ -2758,16 +2755,16 @@ class Trimex(Modifier): snapped = self.doc.getObject(snapped['Object']) pts = [] for e in snapped.Shape.Edges: - int = fcgeo.findIntersection(edge,e,True,True) + int = DraftGeomUtils.findIntersection(edge,e,True,True) if int: pts.extend(int) if pts: - point = pts[fcgeo.findClosest(point,pts)] + point = pts[DraftGeomUtils.findClosest(point,pts)] # modifying active edge if isinstance(edge.Curve,Part.Line): - perp = fcgeo.vec(edge).cross(Vector(0,0,1)) + perp = DraftGeomUtils.vec(edge).cross(Vector(0,0,1)) chord = v1.sub(point) - proj = fcvec.project(chord,perp) + proj = DraftVecUtils.project(chord,perp) self.newpoint = Vector.add(point,proj) dist = v1.sub(self.newpoint).Length ghost.p1(self.newpoint) @@ -2776,15 +2773,15 @@ class Trimex(Modifier): if real: if self.force: ray = self.newpoint.sub(v1) - ray = fcvec.scale(ray,self.force/ray.Length) + ray = DraftVecUtils.scale(ray,self.force/ray.Length) self.newpoint = Vector.add(v1,ray) newedges.append(Part.Line(self.newpoint,v2).toShape()) else: center = edge.Curve.Center rad = edge.Curve.Radius - ang1 = fcvec.angle(v2.sub(center)) - ang2 = fcvec.angle(point.sub(center)) - self.newpoint=Vector.add(center,fcvec.rotate(Vector(rad,0,0),-ang2)) + ang1 = DraftVecUtils.angle(v2.sub(center)) + ang2 = DraftVecUtils.angle(point.sub(center)) + self.newpoint=Vector.add(center,DraftVecUtils.rotate(Vector(rad,0,0),-ang2)) self.ui.labelRadius.setText("Angle") dist = math.degrees(-ang2) # if ang1 > ang2: ang1,ang2 = ang2,ang1 @@ -2796,11 +2793,11 @@ class Trimex(Modifier): if real: if self.force: angle = math.radians(self.force) - newray = fcvec.rotate(Vector(rad,0,0),-angle) + newray = DraftVecUtils.rotate(Vector(rad,0,0),-angle) self.newpoint = Vector.add(center,newray) chord = self.newpoint.sub(v2) perp = chord.cross(Vector(0,0,1)) - scaledperp = fcvec.scaleTo(perp,rad) + scaledperp = DraftVecUtils.scaleTo(perp,rad) midpoint = Vector.add(center,scaledperp) newedges.append(Part.Arc(self.newpoint,midpoint,v2).toShape()) ghost.on() @@ -2815,8 +2812,8 @@ class Trimex(Modifier): ghost.p1(edge.Vertexes[0].Point) ghost.p2(edge.Vertexes[-1].Point) else: - ang1 = fcvec.angle(edge.Vertexes[0].Point.sub(center)) - ang2 = fcvec.angle(edge.Vertexes[-1].Point.sub(center)) + ang1 = DraftVecUtils.angle(edge.Vertexes[0].Point.sub(center)) + ang2 = DraftVecUtils.angle(edge.Vertexes[-1].Point.sub(center)) # if ang1 > ang2: ang1,ang2 = ang2,ang1 ghost.setEndAngle(-ang2) ghost.setStartAngle(-ang1) @@ -2961,7 +2958,7 @@ class Scale(Modifier): self.ghost.trans.scaleFactor.setValue([delta.x,delta.y,delta.z]) corr = Vector(self.node[0].x,self.node[0].y,self.node[0].z) corr.scale(delta.x,delta.y,delta.z) - corr = fcvec.neg(corr.sub(self.node[0])) + corr = DraftVecUtils.neg(corr.sub(self.node[0])) self.ghost.trans.translation.setValue([corr.x,corr.y,corr.z]) if self.extendedCopy: if not hasMod(arg,MODALT): self.finish() @@ -3166,9 +3163,9 @@ class Edit(Modifier): self.editpoints.append(self.obj.Shape.Vertexes[2].Point) v = self.obj.Shape.Vertexes self.bx = v[1].Point.sub(v[0].Point) - if self.obj.Length < 0: self.bx = fcvec.neg(self.bx) + if self.obj.Length < 0: self.bx = DraftVecUtils.neg(self.bx) self.by = v[2].Point.sub(v[1].Point) - if self.obj.Height < 0: self.by = fcvec.neg(self.by) + if self.obj.Height < 0: self.by = DraftVecUtils.neg(self.by) elif Draft.getType(self.obj) == "Polygon": self.editpoints.append(self.obj.Placement.Base) self.editpoints.append(self.obj.Shape.Vertexes[0].Point) @@ -3292,8 +3289,8 @@ class Edit(Modifier): self.obj.Placement = p elif self.editing == 1: diag = v.sub(self.obj.Placement.Base) - nx = fcvec.project(diag,self.bx) - ny = fcvec.project(diag,self.by) + nx = DraftVecUtils.project(diag,self.bx) + ny = DraftVecUtils.project(diag,self.by) ax = nx.Length ay = ny.Length if ax and ay: diff --git a/src/Mod/Draft/DraftTrackers.py b/src/Mod/Draft/DraftTrackers.py index 3cc6519d1..5223ebf66 100644 --- a/src/Mod/Draft/DraftTrackers.py +++ b/src/Mod/Draft/DraftTrackers.py @@ -25,18 +25,16 @@ __title__="FreeCAD Draft Trackers" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -import FreeCAD,FreeCADGui,math,Draft +import FreeCAD,FreeCADGui,math,Draft, DraftVecUtils from FreeCAD import Vector -from draftlibs import fcvec from pivy import coin from DraftGui import todo class Tracker: "A generic Draft Tracker, to be used by other specific trackers" def __init__(self,dotted=False,scolor=None,swidth=None,children=[],ontop=False): - global Part, fcgeo - import Part - from draftlibs import fcgeo + global Part, DraftGeomUtils + import Part, DraftGeomUtils self.ontop = ontop color = coin.SoBaseColor() color.rgb = scolor or FreeCADGui.draftToolBar.getDefaultColor("ui") @@ -161,8 +159,8 @@ class rectangleTracker(Tracker): def update(self,point): "sets the opposite (diagonal) point of the rectangle" diagonal = point.sub(self.origin) - inpoint1 = self.origin.add(fcvec.project(diagonal,self.v)) - inpoint2 = self.origin.add(fcvec.project(diagonal,self.u)) + inpoint1 = self.origin.add(DraftVecUtils.project(diagonal,self.v)) + inpoint2 = self.origin.add(DraftVecUtils.project(diagonal,self.u)) self.coords.point.set1Value(1,inpoint1.x,inpoint1.y,inpoint1.z) self.coords.point.set1Value(2,point.x,point.y,point.z) self.coords.point.set1Value(3,inpoint2.x,inpoint2.y,inpoint2.z) @@ -204,7 +202,7 @@ class rectangleTracker(Tracker): p1 = Vector(self.coords.point.getValues()[0].getValue()) p2 = Vector(self.coords.point.getValues()[2].getValue()) diag = p2.sub(p1) - return ((fcvec.project(diag,self.u)).Length,(fcvec.project(diag,self.v)).Length) + return ((DraftVecUtils.project(diag,self.u)).Length,(DraftVecUtils.project(diag,self.v)).Length) def getNormal(self): "returns the normal of the rectangle" @@ -233,23 +231,23 @@ class dimTracker(Tracker): def calc(self): import Part if (self.p1 != None) and (self.p2 != None): - points = [fcvec.tup(self.p1,True),fcvec.tup(self.p2,True),\ - fcvec.tup(self.p1,True),fcvec.tup(self.p2,True)] + points = [DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True),\ + DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True)] if self.p3 != None: p1 = self.p1 p4 = self.p2 - if fcvec.equals(p1,p4): + if DraftVecUtils.equals(p1,p4): proj = None else: base = Part.Line(p1,p4).toShape() - proj = fcgeo.findDistance(self.p3,base) + proj = DraftGeomUtils.findDistance(self.p3,base) if not proj: p2 = p1 p3 = p4 else: - p2 = p1.add(fcvec.neg(proj)) - p3 = p4.add(fcvec.neg(proj)) - points = [fcvec.tup(p1),fcvec.tup(p2),fcvec.tup(p3),fcvec.tup(p4)] + p2 = p1.add(DraftVecUtils.neg(proj)) + p3 = p4.add(DraftVecUtils.neg(proj)) + points = [DraftVecUtils.tup(p1),DraftVecUtils.tup(p2),DraftVecUtils.tup(p3),DraftVecUtils.tup(p4)] self.coords.point.setValues(0,4,points) class bsplineTracker(Tracker): @@ -340,7 +338,7 @@ class arcTracker(Tracker): center = Vector(c[0],c[1],c[2]) base = FreeCAD.DraftWorkingPlane.u rad = pt.sub(center) - return(fcvec.angle(rad,base,FreeCAD.DraftWorkingPlane.axis)) + return(DraftVecUtils.angle(rad,base,FreeCAD.DraftWorkingPlane.axis)) def getAngles(self): "returns the start and end angles" @@ -496,7 +494,7 @@ class wireTracker(Tracker): "A wire tracker" def __init__(self,wire): self.line = coin.SoLineSet() - self.closed = fcgeo.isReallyClosed(wire) + self.closed = DraftGeomUtils.isReallyClosed(wire) if self.closed: self.line.numVertices.setValue(len(wire.Vertexes)+1) else: @@ -626,11 +624,11 @@ class gridTracker(Tracker): "returns the closest node from the given point" # get the 2D coords. point = FreeCAD.DraftWorkingPlane.projectPoint(point) - u = fcvec.project(point,FreeCAD.DraftWorkingPlane.u) + u = DraftVecUtils.project(point,FreeCAD.DraftWorkingPlane.u) lu = u.Length if u.getAngle(FreeCAD.DraftWorkingPlane.u) > 1.5: lu = -lu - v = fcvec.project(point,FreeCAD.DraftWorkingPlane.v) + v = DraftVecUtils.project(point,FreeCAD.DraftWorkingPlane.v) lv = v.Length if v.getAngle(FreeCAD.DraftWorkingPlane.v) > 1.5: lv = -lv @@ -659,8 +657,7 @@ class boxTracker(Tracker): Tracker.__init__(self,children=[self.trans,m,self.cube]) def update(self,line=None,normal=None): - import WorkingPlane - from draftlibs import fcgeo + import WorkingPlane, DraftGeomUtils if not normal: normal = FreeCAD.DraftWorkingPlane.axis if line: @@ -668,10 +665,10 @@ class boxTracker(Tracker): bp = line[0] lvec = line[1].sub(line[0]) else: - lvec = fcgeo.vec(line.Shape.Edges[0]) + lvec = DraftGeomUtils.vec(line.Shape.Edges[0]) bp = line.Shape.Edges[0].Vertexes[0].Point elif self.baseline: - lvec = fcgeo.vec(self.baseline.Shape.Edges[0]) + lvec = DraftGeomUtils.vec(self.baseline.Shape.Edges[0]) bp = self.baseline.Shape.Edges[0].Vertexes[0].Point else: return @@ -679,12 +676,12 @@ class boxTracker(Tracker): self.cube.width.setValue(lvec.Length) p = WorkingPlane.getPlacementFromPoints([bp,bp.add(lvec),bp.add(right)]) self.trans.rotation.setValue(p.Rotation.Q) - bp = bp.add(fcvec.scale(lvec,0.5)) - bp = bp.add(fcvec.scaleTo(normal,self.cube.depth.getValue()/2)) + bp = bp.add(DraftVecUtils.scale(lvec,0.5)) + bp = bp.add(DraftVecUtils.scaleTo(normal,self.cube.depth.getValue()/2)) self.pos(bp) def pos(self,p): - self.trans.translation.setValue(fcvec.tup(p)) + self.trans.translation.setValue(DraftVecUtils.tup(p)) def width(self,w=None): if w: diff --git a/src/Mod/Draft/draftlibs/fcvec.py b/src/Mod/Draft/DraftVecUtils.py similarity index 100% rename from src/Mod/Draft/draftlibs/fcvec.py rename to src/Mod/Draft/DraftVecUtils.py diff --git a/src/Mod/Draft/Makefile.am b/src/Mod/Draft/Makefile.am index 2502ec4d2..f93f64cfe 100644 --- a/src/Mod/Draft/Makefile.am +++ b/src/Mod/Draft/Makefile.am @@ -13,6 +13,8 @@ data_DATA = \ DraftGui.py \ DraftSnap.py \ DraftTrackers.py \ + DraftVecUtils.py \ + DraftGeomUtils.py \ WorkingPlane.py \ importOCA.py \ importDXF.py \ @@ -28,8 +30,6 @@ nobase_data_DATA = \ draftlibs/dxfImportObjects.py \ draftlibs/dxfLibrary.py \ draftlibs/dxfReader.py \ - draftlibs/fcvec.py \ - draftlibs/fcgeo.py \ draftlibs/__init__.py CLEANFILES = $(BUILT_SOURCES) diff --git a/src/Mod/Draft/WorkingPlane.py b/src/Mod/Draft/WorkingPlane.py index b722f22ff..e41eaabf7 100644 --- a/src/Mod/Draft/WorkingPlane.py +++ b/src/Mod/Draft/WorkingPlane.py @@ -22,9 +22,8 @@ #*************************************************************************** -import FreeCAD, FreeCADGui, math +import FreeCAD, FreeCADGui, math, DraftVecUtils from FreeCAD import Vector -from draftlibs import fcvec __title__="FreeCAD Working Plane utility" __author__ = "Ken Cline" @@ -51,7 +50,7 @@ class plane: self.stored = None def __repr__(self): - return "Workplane x="+str(fcvec.rounded(self.u))+" y="+str(fcvec.rounded(self.v))+" z="+str(fcvec.rounded(self.axis)) + return "Workplane x="+str(DraftVecUtils.rounded(self.u))+" y="+str(DraftVecUtils.rounded(self.v))+" z="+str(DraftVecUtils.rounded(self.axis)) def offsetToPoint(self, p, direction=None): ''' @@ -96,10 +95,10 @@ class plane: self.doc = FreeCAD.ActiveDocument self.axis = axis; self.axis.normalize() - if (fcvec.equals(axis, Vector(1,0,0))): + if (DraftVecUtils.equals(axis, Vector(1,0,0))): self.u = Vector(0,1,0) self.v = Vector(0,0,1) - elif (fcvec.equals(axis, Vector(-1,0,0))): + elif (DraftVecUtils.equals(axis, Vector(-1,0,0))): self.u = Vector(0,-1,0) self.v = Vector(0,0,1) elif upvec: @@ -109,12 +108,12 @@ class plane: else: self.v = axis.cross(Vector(1,0,0)) self.v.normalize() - self.u = fcvec.rotate(self.v, -math.pi/2, self.axis) + self.u = DraftVecUtils.rotate(self.v, -math.pi/2, self.axis) offsetVector = Vector(axis); offsetVector.multiply(offset) self.position = point.add(offsetVector) self.weak = False # FreeCAD.Console.PrintMessage("(position = " + str(self.position) + ")\n") - # FreeCAD.Console.PrintMessage("Current workplane: x="+str(fcvec.rounded(self.u))+" y="+str(fcvec.rounded(self.v))+" z="+str(fcvec.rounded(self.axis))+"\n") + # FreeCAD.Console.PrintMessage("Current workplane: x="+str(DraftVecUtils.rounded(self.u))+" y="+str(DraftVecUtils.rounded(self.v))+" z="+str(DraftVecUtils.rounded(self.axis))+"\n") def alignToCurve(self, shape, offset): if shape.ShapeType == 'Edge': @@ -162,7 +161,7 @@ class plane: def getRotation(self): "returns a placement describing the working plane orientation ONLY" - m = fcvec.getPlaneRotation(self.u,self.v,self.axis) + m = DraftVecUtils.getPlaneRotation(self.u,self.v,self.axis) return FreeCAD.Placement(m) def getPlacement(self): @@ -197,15 +196,15 @@ class plane: def getLocalCoords(self,point): "returns the coordinates of a given point on the working plane" - xv = fcvec.project(point,self.u) + xv = DraftVecUtils.project(point,self.u) x = xv.Length if xv.getAngle(self.u) > 1: x = -x - yv = fcvec.project(point,self.v) + yv = DraftVecUtils.project(point,self.v) y = yv.Length if yv.getAngle(self.v) > 1: y = -y - zv = fcvec.project(point,self.axis) + zv = DraftVecUtils.project(point,self.axis) z = zv.Length if zv.getAngle(self.axis) > 1: z = -z @@ -213,9 +212,9 @@ class plane: def getGlobalCoords(self,point): "returns the global coordinates of the given point, taken relatively to this working plane" - vx = fcvec.scale(self.u,point.x) - vy = fcvec.scale(self.v,point.y) - vz = fcvec.scale(self.axis,point.z) + vx = DraftVecUtils.scale(self.u,point.x) + vy = DraftVecUtils.scale(self.v,point.y) + vz = DraftVecUtils.scale(self.axis,point.z) return (vx.add(vy)).add(vz) def getClosestAxis(self,point): @@ -223,9 +222,9 @@ class plane: ax = point.getAngle(self.u) ay = point.getAngle(self.v) az = point.getAngle(self.axis) - bx = point.getAngle(fcvec.neg(self.u)) - by = point.getAngle(fcvec.neg(self.v)) - bz = point.getAngle(fcvec.neg(self.axis)) + bx = point.getAngle(DraftVecUtils.neg(self.u)) + by = point.getAngle(DraftVecUtils.neg(self.v)) + bz = point.getAngle(DraftVecUtils.neg(self.axis)) b = min(ax,ay,az,bx,by,bz) if b in [ax,bx]: return "x" diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index 2c0474f8e..f71e10166 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -40,8 +40,8 @@ lines, polylines, lwpolylines, circles, arcs, texts, colors,layers (from groups) ''' -import FreeCAD, os, Part, math, re, string, Mesh, Draft -from draftlibs import fcvec, dxfColorMap, dxfLibrary, fcgeo +import FreeCAD, os, Part, math, re, string, Mesh, Draft, DraftVecUtils, DraftGeomUtils +from draftlibs import dxfColorMap, dxfLibrary from draftlibs.dxfReader import readDXF from Draft import _Dimension, _ViewProviderDimension from FreeCAD import Vector @@ -134,10 +134,10 @@ def calcBulge(v1,bulge,v2): ''' chord = v2.sub(v1) sagitta = (bulge * chord.Length)/2 - startpoint = v1.add(fcvec.scale(chord,0.5)) + startpoint = v1.add(DraftVecUtils.scale(chord,0.5)) perp = chord.cross(Vector(0,0,1)) - if not fcvec.isNull(perp): perp.normalize() - endpoint = fcvec.scale(perp,sagitta) + if not DraftVecUtils.isNull(perp): perp.normalize() + endpoint = DraftVecUtils.scale(perp,sagitta) return startpoint.add(endpoint) def getGroup(ob,exportList): @@ -218,7 +218,7 @@ class fcformat: v1 = FreeCAD.Vector(r1,g1,b1) v2 = FreeCAD.Vector(r2,g2,b2) v = v2.sub(v1) - v = fcvec.scale(v,0.5) + v = DraftVecUtils.scale(v,0.5) cv = v1.add(v) else: c1 = bparams.GetUnsigned("BackgroundColor") @@ -348,7 +348,7 @@ def drawLine(line,shapemode=False): if (len(line.points) > 1): v1=vec(line.points[0]) v2=vec(line.points[1]) - if not fcvec.equals(v1,v2): + if not DraftVecUtils.equals(v1,v2): try: if (fmt.paramstyle >= 4) and (not shapemode): return Draft.makeWire([v1,v2]) @@ -370,11 +370,11 @@ def drawPolyline(polyline,shapemode=False,num=None): v1 = vec(p1) v2 = vec(p2) verts.append(v1) - if not fcvec.equals(v1,v2): + if not DraftVecUtils.equals(v1,v2): if polyline.points[p].bulge: curves = True cv = calcBulge(v1,polyline.points[p].bulge,v2) - if fcvec.isColinear([v1,cv,v2]): + if DraftVecUtils.isColinear([v1,cv,v2]): try: edges.append(Part.Line(v1,v2).toShape()) except: warn(polyline,num) else: @@ -390,8 +390,8 @@ def drawPolyline(polyline,shapemode=False,num=None): v1 = vec(p1) v2 = vec(p2) cv = calcBulge(v1,polyline.points[-1].bulge,v2) - if not fcvec.equals(v1,v2): - if fcvec.isColinear([v1,cv,v2]): + if not DraftVecUtils.equals(v1,v2): + if DraftVecUtils.isColinear([v1,cv,v2]): try: edges.append(Part.Line(v1,v2).toShape()) except: @@ -722,11 +722,11 @@ def addText(text,attrib=False): rz = rawValue(text,31) if rx or ry or rz: xv = Vector(rx,ry,rz) - if not fcvec.isNull(xv): - ax = fcvec.neg(xv.cross(Vector(1,0,0))) - if fcvec.isNull(ax): + if not DraftVecUtils.isNull(xv): + ax = DraftVecUtils.neg(xv.cross(Vector(1,0,0))) + if DraftVecUtils.isNull(ax): ax = Vector(0,0,1) - ang = -math.degrees(fcvec.angle(xv,Vector(1,0,0),ax)) + ang = -math.degrees(DraftVecUtils.angle(xv,Vector(1,0,0),ax)) Draft.rotate(newob,ang,axis=ax) elif hasattr(text,"rotation"): if text.rotation: @@ -885,7 +885,7 @@ def processdxf(document,filename): edges = [] for s in shapes: edges.extend(s.Edges) - shapes = fcgeo.findWires(edges) + shapes = DraftGeomUtils.findWires(edges) for s in shapes: newob = addObject(s) @@ -1198,13 +1198,13 @@ def getArcData(edge): # check the midpoint seems more reliable ve1 = edge.Vertexes[0].Point ve2 = edge.Vertexes[-1].Point - ang1 = -math.degrees(fcvec.angle(ve1.sub(ce))) - ang2 = -math.degrees(fcvec.angle(ve2.sub(ce))) - ve3 = fcgeo.findMidpoint(edge) - ang3 = -math.degrees(fcvec.angle(ve3.sub(ce))) + ang1 = -math.degrees(DraftVecUtils.angle(ve1.sub(ce))) + ang2 = -math.degrees(DraftVecUtils.angle(ve2.sub(ce))) + ve3 = DraftGeomUtils.findMidpoint(edge) + ang3 = -math.degrees(DraftVecUtils.angle(ve3.sub(ce))) if (ang3 < ang1) and (ang2 < ang3): ang1, ang2 = ang2, ang1 - return fcvec.tup(ce), radius, ang1, ang2 + return DraftVecUtils.tup(ce), radius, ang1, ang2 def getSplineSegs(edge): "returns an array of vectors from a bSpline edge" @@ -1228,18 +1228,18 @@ def getSplineSegs(edge): def getWire(wire,nospline=False): "returns an array of dxf-ready points and bulges from a wire" - edges = fcgeo.sortEdges(wire.Edges) + edges = DraftGeomUtils.sortEdges(wire.Edges) points = [] for edge in edges: v1 = edge.Vertexes[0].Point if len(edge.Vertexes) < 2: points.append((v1.x,v1.y,v1.z,None,None,0.0)) elif (isinstance(edge.Curve,Part.Circle)): - mp = fcgeo.findMidpoint(edge) + mp = DraftGeomUtils.findMidpoint(edge) v2 = edge.Vertexes[-1].Point c = edge.Curve.Center - angle = abs(fcvec.angle(v1.sub(c),v2.sub(c))) - # if (fcvec.angle(v2.sub(c)) < fcvec.angle(v1.sub(c))): + angle = abs(DraftVecUtils.angle(v1.sub(c),v2.sub(c))) + # if (DraftVecUtils.angle(v2.sub(c)) < DraftVecUtils.angle(v1.sub(c))): # angle = -angle # polyline bulge -> negative makes the arc go clockwise bul = math.tan(angle/4) @@ -1259,9 +1259,9 @@ def getWire(wire,nospline=False): points.append((p.x,p.y,p.z,None,None,0.0)) else: points.append((v1.x,v1.y,v1.z,None,None,0.0)) - if not fcgeo.isReallyClosed(wire): + if not DraftGeomUtils.isReallyClosed(wire): v = edges[-1].Vertexes[-1].Point - points.append(fcvec.tup(v)) + points.append(DraftVecUtils.tup(v)) # print "wire verts: ",points return points @@ -1289,7 +1289,7 @@ def writeShape(ob,dxfobject,nospline=False): layer=getGroup(ob,exportList))) else: dxfobject.append(dxfLibrary.PolyLine(getWire(wire,nospline), [0.0,0.0,0.0], - int(fcgeo.isReallyClosed(wire)), color=getACI(ob), + int(DraftGeomUtils.isReallyClosed(wire)), color=getACI(ob), layer=getGroup(ob,exportList))) if len(processededges) < len(ob.Shape.Edges): # lone edges loneedges = [] @@ -1318,7 +1318,7 @@ def writeShape(ob,dxfobject,nospline=False): else: # anything else is treated as lines ve1=edge.Vertexes[0].Point ve2=edge.Vertexes[1].Point - dxfobject.append(dxfLibrary.Line([fcvec.tup(ve1), fcvec.tup(ve2)], + dxfobject.append(dxfLibrary.Line([DraftVecUtils.tup(ve1), DraftVecUtils.tup(ve2)], color=getACI(ob), layer=getGroup(ob,exportList))) @@ -1377,7 +1377,7 @@ def export(objectslist,filename,nospline=False): # temporary - as dxfLibrary doesn't support mtexts well, we use several single-line texts # well, anyway, at the moment, Draft only writes single-line texts, so... for text in ob.LabelText: - point = fcvec.tup(FreeCAD.Vector(ob.Position.x, + point = DraftVecUtils.tup(FreeCAD.Vector(ob.Position.x, ob.Position.y-ob.LabelText.index(text), ob.Position.z)) if gui: height = float(ob.ViewObject.FontSize) @@ -1388,14 +1388,14 @@ def export(objectslist,filename,nospline=False): layer=getGroup(ob,exportList))) elif 'Dimline' in ob.PropertiesList: - p1 = fcvec.tup(ob.Start) - p2 = fcvec.tup(ob.End) + p1 = DraftVecUtils.tup(ob.Start) + p2 = DraftVecUtils.tup(ob.End) base = Part.Line(ob.Start,ob.End).toShape() - proj = fcgeo.findDistance(ob.Dimline,base) + proj = DraftGeomUtils.findDistance(ob.Dimline,base) if not proj: - pbase = fcvec.tup(ob.End) + pbase = DraftVecUtils.tup(ob.End) else: - pbase = fcvec.tup(ob.End.add(fcvec.neg(proj))) + pbase = DraftVecUtils.tup(ob.End.add(DraftVecUtils.neg(proj))) dxf.append(dxfLibrary.Dimension(pbase,p1,p2,color=getACI(ob), layer=getGroup(ob,exportList))) diff --git a/src/Mod/Draft/importOCA.py b/src/Mod/Draft/importOCA.py index 58131d830..79e769aa2 100644 --- a/src/Mod/Draft/importOCA.py +++ b/src/Mod/Draft/importOCA.py @@ -29,8 +29,7 @@ __url__ = ["http://yorik.orgfree.com","http://free-cad.sourceforge.net"] This script imports OCA/gcad files into FreeCAD. ''' -import FreeCAD, os, Part, math -from draftlibs import fcvec, fcgeo +import FreeCAD, os, Part, math, DraftVecUtils, DraftGeomUtils from FreeCAD import Vector try: import FreeCADGui @@ -56,7 +55,7 @@ def getpoint(data): if (data[1][0] == "R"): return objects[data[0]].add(objects[data[1]]) elif (data[1][0] == "C"): - return fcgeo.findProjection(objects[data[0]],objects[data[1]]) + return DraftGeomUtils.findProjection(objects[data[0]],objects[data[1]]) elif (data[0][0] == "C"): if objects[data[0]]: p1 = objects[data[0]].Curve.Position @@ -65,7 +64,7 @@ def getpoint(data): else: if (data[1][0] == "L"): l = objects[data[1]] - return p1.add(fcgeo.vec(l)) + return p1.add(DraftGeomUtils.vec(l)) def getarea(data): "turns an OCA area definition into a FreeCAD Part Wire" @@ -111,7 +110,7 @@ def getarc(data): c = Part.Circle() c.Center = verts[0] if rad: c.Radius = rad - else: c.Radius = fcvec.new(verts[0],verts[1]).Length + else: c.Radius = DraftVecUtils.new(verts[0],verts[1]).Length elif (data[0][0] == "L"): # 2-lines circle lines = [] @@ -121,7 +120,7 @@ def getarc(data): rad = float(data[p+1]) elif (data[p][0] == "L"): lines.append(objects[data[p]]) - circles = fcgeo.circleFrom2LinesRadius(lines[0],lines[1],rad) + circles = DraftGeomUtils.circleFrom2LinesRadius(lines[0],lines[1],rad) if circles: c = circles[0] if c: return c.toShape() @@ -268,7 +267,7 @@ def export(exportList,filename): oca.write("C"+str(count)+"=ARC ") oca.write(writepoint(e.Vertexes[0].Point)) oca.write(" ") - oca.write(writepoint(fcgeo.findMidpoint(e))) + oca.write(writepoint(DraftGeomUtils.findMidpoint(e))) oca.write(" ") oca.write(writepoint(e.Vertexes[-1].Point)) else: diff --git a/src/Mod/Draft/importSVG.py b/src/Mod/Draft/importSVG.py index b49d4735c..099041d0a 100644 --- a/src/Mod/Draft/importSVG.py +++ b/src/Mod/Draft/importSVG.py @@ -38,9 +38,7 @@ currently unsupported: use, image # implement inherting fill style from group # handle relative units -import xml.sax, string, FreeCAD, os, math, re, Draft -from draftlibs import fcvec -from draftlibs import fcgeo +import xml.sax, string, FreeCAD, os, math, re, Draft, DraftVecUtils, DraftGeomUtils from FreeCAD import Vector try: import FreeCADGui @@ -271,7 +269,7 @@ def makewire(path,checkclosed=False,donttry=False): #ToDo Do not catch all exceptions if not donttry: try: - sh = Part.Wire(fcgeo.sortEdges(path)) + sh = Part.Wire(DraftGeomUtils.sortEdges(path)) #sh = Part.Wire(path) isok = (not checkclosed) or sh.isClosed() except:# BRep_API:command not done @@ -334,13 +332,13 @@ def arcend2center(lastvec,currentvec,rx,ry,xrotation=0.0,correction=False): m2=FreeCAD.Matrix() m2.rotateZ(xrotation) centeroff = currentvec.add(lastvec) - centeroff = fcvec.scale(centeroff,.5) + centeroff = DraftVecUtils.scale(centeroff,.5) vcenter = m2.multiply(vcx1).add(centeroff) # Step3 F.6.5.3 #angle1 = Vector(1,0,0).getAngle(Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0)) # F.6.5.5 #angledelta = Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0).getAngle(Vector((-v1.x-vcx1.x)/rx,(-v1.y-vcx1.y)/ry,0)) # F.6.5.6 #we need the right sign for the angle - angle1 = fcvec.angle(Vector(1,0,0),Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0)) # F.6.5.5 - angledelta = fcvec.angle(Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0),Vector((-v1.x-vcx1.x)/rx,(-v1.y-vcx1.y)/ry,0)) # F.6.5.6 + angle1 = DraftVecUtils.angle(Vector(1,0,0),Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0)) # F.6.5.5 + angledelta = DraftVecUtils.angle(Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0),Vector((-v1.x-vcx1.x)/rx,(-v1.y-vcx1.y)/ry,0)) # F.6.5.6 results.append((vcenter,angle1,angledelta)) return results,(rx,ry) @@ -558,7 +556,7 @@ class svgHandler(xml.sax.ContentHandler): currentvec = lastvec.add(Vector(x,-y,0)) else: currentvec = Vector(x,-y,0) - if not fcvec.equals(lastvec,currentvec): + if not DraftVecUtils.equals(lastvec,currentvec): seg = Part.Line(lastvec,currentvec).toShape() FreeCAD.Console.PrintMessage("line %s %s\n" %(lastvec,currentvec)) lastvec = currentvec @@ -599,15 +597,15 @@ class svgHandler(xml.sax.ContentHandler): # here is a better way to find the perpendicular if sweepflag == 1: # clockwise - perp = fcvec.rotate2D(chord,-math.pi/2) + perp = DraftVecUtils.rotate2D(chord,-math.pi/2) else: # anticlockwise - perp = fcvec.rotate2D(chord,math.pi/2) - chord = fcvec.scale(chord,.5) + perp = DraftVecUtils.rotate2D(chord,math.pi/2) + chord = DraftVecUtils.scale(chord,.5) if chord.Length > rx: a = 0 else: a = math.sqrt(rx**2-chord.Length**2) s = rx - a - perp = fcvec.scale(perp,s/perp.Length) + perp = DraftVecUtils.scale(perp,s/perp.Length) midpoint = lastvec.add(chord.add(perp)) seg = Part.Arc(lastvec,midpoint,currentvec).toShape() else:# big arc or elliptical arc @@ -676,7 +674,7 @@ class svgHandler(xml.sax.ContentHandler): currentvec = Vector(x,-y,0) pole2 = Vector(p2x,-p2y,0) - if not fcvec.equals(currentvec,lastvec): + if not DraftVecUtils.equals(currentvec,lastvec): mainv = currentvec.sub(lastvec) pole1v = lastvec.add(pole1) pole2v = currentvec.add(pole2) @@ -718,7 +716,7 @@ class svgHandler(xml.sax.ContentHandler): else: currentvec = Vector(x,-y,0) - if not fcvec.equals(currentvec,lastvec): + if not DraftVecUtils.equals(currentvec,lastvec): if True and \ pole.distanceToLine(lastvec,currentvec) < 20**(-1*(2+Draft.precision())): #print "straight segment" @@ -733,7 +731,7 @@ class svgHandler(xml.sax.ContentHandler): lastpole = ('quadratic',pole) path.append(seg) elif (d == "Z") or (d == "z"): - if not fcvec.equals(lastvec,firstvec): + if not DraftVecUtils.equals(lastvec,firstvec): seg = Part.Line(lastvec,firstvec).toShape() path.append(seg) if path: #the path should be closed by now @@ -821,7 +819,7 @@ class svgHandler(xml.sax.ContentHandler): esh.append(arc.toShape()) for esh1,esh2 in zip(esh[-1:]+esh[:-1],esh): p1,p2 = esh1.Vertexes[-1].Point,esh2.Vertexes[0].Point - if not fcvec.equals(p1,p2): + if not DraftVecUtils.equals(p1,p2): edges.append(Part.Line(esh1.Vertexes[-1].Point,esh2.Vertexes[0].Point).toShape()) #straight segments edges.append(esh2) # elliptical segments sh = Part.Wire(edges) @@ -859,7 +857,7 @@ class svgHandler(xml.sax.ContentHandler): points=points+points[:2] # emulate closepath for svgx,svgy in zip(points[2::2],points[3::2]): currentvec = Vector(svgx,-svgy,0) - if not fcvec.equals(lastvec,currentvec): + if not DraftVecUtils.equals(lastvec,currentvec): seg = Part.Line(lastvec,currentvec).toShape() #print "polyline seg ",lastvec,currentvec lastvec = currentvec diff --git a/src/WindowsInstaller/ModDraft.wxi b/src/WindowsInstaller/ModDraft.wxi index 13fcc92ff..720a39810 100644 --- a/src/WindowsInstaller/ModDraft.wxi +++ b/src/WindowsInstaller/ModDraft.wxi @@ -38,6 +38,8 @@ + + @@ -46,8 +48,6 @@ - - From b1de8d217e20ce36cca92b42e3c667db6fef7bfc Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Tue, 22 May 2012 12:00:03 -0300 Subject: [PATCH 28/42] Further Draft lib name fixes --- src/Mod/Arch/ArchSectionPlane.py | 3 +- src/Mod/Draft/DraftGeomUtils.py | 170 +++++++++++++++---------------- 2 files changed, 87 insertions(+), 86 deletions(-) diff --git a/src/Mod/Arch/ArchSectionPlane.py b/src/Mod/Arch/ArchSectionPlane.py index 59c802382..e1230e59f 100644 --- a/src/Mod/Arch/ArchSectionPlane.py +++ b/src/Mod/Arch/ArchSectionPlane.py @@ -21,7 +21,7 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,Drawing,math,Draft,ArchCommands, DraftVecUtils +import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,math,Draft,ArchCommands, DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore from pivy import coin @@ -197,6 +197,7 @@ class _ArchDrawingView: else: # render using the Drawing module + import Drawing shapes = [] for o in objs: if o.isDerivedFrom("Part::Feature"): diff --git a/src/Mod/Draft/DraftGeomUtils.py b/src/Mod/Draft/DraftGeomUtils.py index ccacbf62c..16468ad0c 100755 --- a/src/Mod/Draft/DraftGeomUtils.py +++ b/src/Mod/Draft/DraftGeomUtils.py @@ -27,7 +27,7 @@ __url__ = ["http://free-cad.sourceforge.net"] "this file contains generic geometry functions for manipulating Part shapes" -import FreeCAD, Part, fcvec, math, cmath +import FreeCAD, Part, DraftVecUtils, math, cmath from FreeCAD import Vector NORM = Vector(0,0,1) # provisory normal direction for all geometry ops. @@ -51,7 +51,7 @@ def vec(edge): def edg(p1,p2): "edg(Vector,Vector) -- returns an edge from 2 vectors" if isinstance(p1,FreeCAD.Vector) and isinstance(p2,FreeCAD.Vector): - if fcvec.equals(p1,p2): return None + if DraftVecUtils.equals(p1,p2): return None else: return Part.Line(p1,p2).toShape() def getVerts(shape): @@ -85,7 +85,7 @@ def isPtOnEdge(pt,edge) : '''isPtOnEdge(Vector,edge) -- Tests if a point is on an edge''' if isinstance(edge.Curve,Part.Line) : orig = edge.Vertexes[0].Point - if fcvec.isNull(pt.sub(orig).cross(vec(edge))) : + if DraftVecUtils.isNull(pt.sub(orig).cross(vec(edge))) : return pt.sub(orig).Length <= vec(edge).Length and pt.sub(orig).dot(vec(edge)) >= 0 else : return False @@ -101,16 +101,16 @@ def isPtOnEdge(pt,edge) : else : begin = edge.Vertexes[0].Point end = edge.Vertexes[-1].Point - if fcvec.isNull(pt.sub(begin)) or fcvec.isNull(pt.sub(end)) : + if DraftVecUtils.isNull(pt.sub(begin)) or DraftVecUtils.isNull(pt.sub(end)) : return True else : # newArc = Part.Arc(begin,pt,end) - # return fcvec.isNull(newArc.Center.sub(center)) \ - # and fcvec.isNull(newArc.Axis-axis) \ + # return DraftVecUtils.isNull(newArc.Center.sub(center)) \ + # and DraftVecUtils.isNull(newArc.Axis-axis) \ # and round(newArc.Radius-radius,precision) == 0 - angle1 = fcvec.angle(begin.sub(center)) - angle2 = fcvec.angle(end.sub(center)) - anglept = fcvec.angle(pt.sub(center)) + angle1 = DraftVecUtils.angle(begin.sub(center)) + angle2 = DraftVecUtils.angle(end.sub(center)) + anglept = DraftVecUtils.angle(pt.sub(center)) if (angle1 < anglept) and (anglept < angle2): return True return False @@ -165,8 +165,8 @@ def findEdge(anEdge,aList): '''findEdge(anEdge,aList): returns True if anEdge is found in aList of edges''' for e in range(len(aList)): if str(anEdge.Curve) == str(aList[e].Curve): - if fcvec.equals(anEdge.Vertexes[0].Point,aList[e].Vertexes[0].Point): - if fcvec.equals(anEdge.Vertexes[-1].Point,aList[e].Vertexes[-1].Point): + if DraftVecUtils.equals(anEdge.Vertexes[0].Point,aList[e].Vertexes[0].Point): + if DraftVecUtils.equals(anEdge.Vertexes[-1].Point,aList[e].Vertexes[-1].Point): return(e) return None @@ -202,13 +202,13 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F return [pt2] #we have 2 straight lines - if fcvec.isNull(pt2.sub(pt1).cross(pt3.sub(pt1)).cross(pt2.sub(pt4).cross(pt3.sub(pt4)))): + if DraftVecUtils.isNull(pt2.sub(pt1).cross(pt3.sub(pt1)).cross(pt2.sub(pt4).cross(pt3.sub(pt4)))): vec1 = pt2.sub(pt1) ; vec2 = pt4.sub(pt3) - if fcvec.isNull(vec1) or fcvec.isNull(vec2): + if DraftVecUtils.isNull(vec1) or DraftVecUtils.isNull(vec2): return [] vec1.normalize() ; vec2.normalize() cross = vec1.cross(vec2) - if not fcvec.isNull(cross) : + if not DraftVecUtils.isNull(cross) : k = ((pt3.z-pt1.z)*(vec2.x-vec2.y)+(pt3.y-pt1.y)*(vec2.z-vec2.x)+ \ (pt3.x-pt1.x)*(vec2.y-vec2.z))/(cross.x+cross.y+cross.z) vec1.scale(k,k,k) @@ -251,7 +251,7 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F elif (pt2 in [pt3,pt4]): return [pt2] - if fcvec.isNull(pt1.sub(center).cross(pt2.sub(center)).cross(arc.Curve.Axis)) : + if DraftVecUtils.isNull(pt1.sub(center).cross(pt2.sub(center)).cross(arc.Curve.Axis)) : # Line and Arc are on same plane dOnLine = center.sub(pt1).dot(dirVec) @@ -303,18 +303,18 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F axis1, axis2 = edge1.Curve.Axis , edge2.Curve.Axis c2c = cent2.sub(cent1) - if fcvec.isNull(axis1.cross(axis2)) : + if DraftVecUtils.isNull(axis1.cross(axis2)) : if round(c2c.dot(axis1),precision) == 0 : # circles are on same plane dc2c = c2c.Length ; - if not fcvec.isNull(c2c): c2c.normalize() + if not DraftVecUtils.isNull(c2c): c2c.normalize() if round(rad1+rad2-dc2c,precision) < 0 \ or round(rad1-dc2c-rad2,precision) > 0 or round(rad2-dc2c-rad1,precision) > 0 : return [] else : norm = c2c.cross(axis1) - if not fcvec.isNull(norm): norm.normalize() - if fcvec.isNull(norm): x = 0 + if not DraftVecUtils.isNull(norm): norm.normalize() + if DraftVecUtils.isNull(norm): x = 0 else: x = (dc2c**2 + rad1**2 - rad2**2)/(2*dc2c) y = abs(rad1**2 - x**2)**(0.5) c2c.scale(x,x,x) @@ -369,8 +369,8 @@ def geom(edge): v2 = edge.Vertexes[-1].Point c = edge.Curve.Center cu = Part.Circle(edge.Curve.Center,edge.Curve.Axis,edge.Curve.Radius) - a1 = -fcvec.angle(v1.sub(c),ref,edge.Curve.Axis) - a2 = -fcvec.angle(v2.sub(c),ref,edge.Curve.Axis) + a1 = -DraftVecUtils.angle(v1.sub(c),ref,edge.Curve.Axis) + a2 = -DraftVecUtils.angle(v2.sub(c),ref,edge.Curve.Axis) print "creating sketch arc from ",cu, ", p1=",v1, " (",math.degrees(a1), "d) p2=",v2," (", math.degrees(a2),"d)" p= Part.ArcOfCircle(cu,a1,a2) return p @@ -382,7 +382,7 @@ def mirror (point, edge): normPoint = point.add(findDistance(point, edge, False)) if normPoint: normPoint_point = Vector.sub(point, normPoint) - normPoint_refl = fcvec.neg(normPoint_point) + normPoint_refl = DraftVecUtils.neg(normPoint_point) refl = Vector.add(normPoint, normPoint_refl) return refl else: @@ -547,13 +547,13 @@ def findWires(edgeslist): return False if len(e2.Vertexes) < 2: return False - if fcvec.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point): + if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point): return True - if fcvec.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point): + if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point): return True - if fcvec.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point): + if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point): return True - if fcvec.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point): + if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point): return True return False @@ -656,7 +656,7 @@ def findMidpoint(edge): if len(edge.Vertexes) == 1: # Circle dv = first.sub(center) - dv = fcvec.neg(dv) + dv = DraftVecUtils.neg(dv) return center.add(dv) axis = edge.Curve.Axis chord = last.sub(first) @@ -665,12 +665,12 @@ def findMidpoint(edge): ray = first.sub(center) apothem = ray.dot(perp) sagitta = radius - apothem - startpoint = Vector.add(first, fcvec.scale(chord,0.5)) - endpoint = fcvec.scaleTo(perp,sagitta) + startpoint = Vector.add(first, DraftVecUtils.scale(chord,0.5)) + endpoint = DraftVecUtils.scaleTo(perp,sagitta) return Vector.add(startpoint,endpoint) elif isinstance(edge.Curve,Part.Line): - halfedge = fcvec.scale(last.sub(first),.5) + halfedge = DraftVecUtils.scale(last.sub(first),.5) return Vector.add(first,halfedge) else: @@ -759,7 +759,7 @@ def isReallyClosed(wire): if len(wire.Edges) == len(wire.Vertexes): return True v1 = wire.Vertexes[0].Point v2 = wire.Vertexes[-1].Point - if fcvec.equals(v1,v2): return True + if DraftVecUtils.equals(v1,v2): return True return False def getNormal(shape): @@ -784,7 +784,7 @@ def getNormal(shape): if FreeCAD.GuiUp: import Draft vdir = Draft.get3DView().getViewDirection() - if n.getAngle(vdir) < 0.78: n = fcvec.neg(n) + if n.getAngle(vdir) < 0.78: n = DraftVecUtils.neg(n) return n def offsetWire(wire,dvec,bind=False,occ=False): @@ -815,8 +815,8 @@ def offsetWire(wire,dvec,bind=False,occ=False): curredge = edges[i] delta = dvec if i != 0: - angle = fcvec.angle(vec(edges[0]),vec(curredge),norm) - delta = fcvec.rotate(delta,angle,norm) + angle = DraftVecUtils.angle(vec(edges[0]),vec(curredge),norm) + delta = DraftVecUtils.rotate(delta,angle,norm) nedge = offset(curredge,delta) nedges.append(nedge) nedges = connect(nedges,closed) @@ -890,7 +890,7 @@ def findDistance(point,edge,strict=False): chord = edge.Vertexes[0].Point.sub(point) norm = segment.cross(chord) perp = segment.cross(norm) - dist = fcvec.project(chord,perp) + dist = DraftVecUtils.project(chord,perp) if not dist: return None newpoint = point.add(dist) if (dist.Length == 0): @@ -912,14 +912,14 @@ def findDistance(point,edge,strict=False): center = edge.Curve.Center segment = center.sub(point) ratio = (segment.Length - edge.Curve.Radius) / segment.Length - dist = fcvec.scale(segment,ratio) + dist = DraftVecUtils.scale(segment,ratio) newpoint = Vector.add(point, dist) if (dist.Length == 0): return None if strict and ve2: - ang1 = fcvec.angle(ve1.sub(center)) - ang2 = fcvec.angle(ve2.sub(center)) - angpt = fcvec.angle(newpoint.sub(center)) + ang1 = DraftVecUtils.angle(ve1.sub(center)) + ang2 = DraftVecUtils.angle(ve2.sub(center)) + angpt = DraftVecUtils.angle(newpoint.sub(center)) if ((angpt <= ang2 and angpt >= ang1) or (angpt <= ang1 and angpt >= ang2)): return dist else: @@ -954,15 +954,15 @@ def angleBisection(edge1, edge2): int = findIntersection(edge1, edge2, True, True) if int: line1Dir = p2.sub(p1) - angleDiff = fcvec.angle(line1Dir, p4.sub(p3)) + angleDiff = DraftVecUtils.angle(line1Dir, p4.sub(p3)) ang = angleDiff * 0.5 origin = int[0] line1Dir.normalize() - dir = fcvec.rotate(line1Dir, ang) + dir = DraftVecUtils.rotate(line1Dir, ang) return Part.Line(origin,origin.add(dir)).toShape() else: diff = p3.sub(p1) - origin = p1.add(fcvec.scale(diff, 0.5)) + origin = p1.add(DraftVecUtils.scale(diff, 0.5)) dir = p2.sub(p1); dir.normalize() return Part.Line(origin,origin.add(dir)).toShape() else: @@ -998,8 +998,8 @@ def isPlanar(shape): n = bt.normalAt(0,0) for p in shape.Vertexes[3:]: pv = p.Point.sub(pts[0]) - rv = fcvec.project(pv,n) - if not fcvec.isNull(rv): + rv = DraftVecUtils.project(pv,n) + if not DraftVecUtils.isNull(rv): return False return True @@ -1216,9 +1216,9 @@ def getCubicDimensions(shape): vx = vec(base.Edges[0]) vy = vec(base.Edges[1]) # getting rotations - rotZ = fcvec.angle(vx) - rotY = fcvec.angle(vx,FreeCAD.Vector(vx.x,vx.y,0)) - rotX = fcvec.angle(vy,FreeCAD.Vector(vy.x,vy.y,0)) + rotZ = DraftVecUtils.angle(vx) + rotY = DraftVecUtils.angle(vx,FreeCAD.Vector(vx.x,vx.y,0)) + rotX = DraftVecUtils.angle(vy,FreeCAD.Vector(vy.x,vy.y,0)) # getting height vz = None rpi = round(math.pi/2,precision) @@ -1687,22 +1687,22 @@ def circlefrom1Line2Points(edge, p1, p2): v2 = p2.sub(s) projectedDist = math.sqrt(abs(v1.dot(v2))) edgeDir = vec(edge); edgeDir.normalize() - projectedCen1 = Vector.add(s, fcvec.scale(edgeDir, projectedDist)) - projectedCen2 = Vector.add(s, fcvec.scale(edgeDir, -projectedDist)) + projectedCen1 = Vector.add(s, DraftVecUtils.scale(edgeDir, projectedDist)) + projectedCen2 = Vector.add(s, DraftVecUtils.scale(edgeDir, -projectedDist)) perpEdgeDir = edgeDir.cross(Vector(0,0,1)) perpCen1 = Vector.add(projectedCen1, perpEdgeDir) perpCen2 = Vector.add(projectedCen2, perpEdgeDir) mid = findMidpoint(p1_p2) - x = fcvec.crossproduct(vec(p1_p2)); x.normalize() + x = DraftVecUtils.crossproduct(vec(p1_p2)); x.normalize() perp_mid = Vector.add(mid, x) cen1 = findIntersection(edg(projectedCen1, perpCen1), edg(mid, perp_mid), True, True) cen2 = findIntersection(edg(projectedCen2, perpCen2), edg(mid, perp_mid), True, True) circles = [] if cen1: - radius = fcvec.dist(projectedCen1, cen1[0]) + radius = DraftVecUtils.dist(projectedCen1, cen1[0]) circles.append(Part.Circle(cen1[0], NORM, radius)) if cen2: - radius = fcvec.dist(projectedCen2, cen2[0]) + radius = DraftVecUtils.dist(projectedCen2, cen2[0]) circles.append(Part.Circle(cen2[0], NORM, radius)) if circles: return circles @@ -1714,26 +1714,26 @@ def circleFrom2LinesRadius (edge1, edge2, radius): if not int: return None int = int[0] bis12 = angleBisection(edge1,edge2) - bis21 = Part.Line(bis12.Vertexes[0].Point,fcvec.rotate(vec(bis12), math.pi/2.0)) - ang12 = abs(fcvec.angle(vec(edge1),vec(edge2))) + bis21 = Part.Line(bis12.Vertexes[0].Point,DraftVecUtils.rotate(vec(bis12), math.pi/2.0)) + ang12 = abs(DraftVecUtils.angle(vec(edge1),vec(edge2))) ang21 = math.pi - ang12 dist12 = radius / math.sin(ang12 * 0.5) dist21 = radius / math.sin(ang21 * 0.5) circles = [] - cen = Vector.add(int, fcvec.scale(vec(bis12), dist12)) + cen = Vector.add(int, DraftVecUtils.scale(vec(bis12), dist12)) circles.append(Part.Circle(cen, NORM, radius)) - cen = Vector.add(int, fcvec.scale(vec(bis12), -dist12)) + cen = Vector.add(int, DraftVecUtils.scale(vec(bis12), -dist12)) circles.append(Part.Circle(cen, NORM, radius)) - cen = Vector.add(int, fcvec.scale(vec(bis21), dist21)) + cen = Vector.add(int, DraftVecUtils.scale(vec(bis21), dist21)) circles.append(Part.Circle(cen, NORM, radius)) - cen = Vector.add(int, fcvec.scale(vec(bis21), -dist21)) + cen = Vector.add(int, DraftVecUtils.scale(vec(bis21), -dist21)) circles.append(Part.Circle(cen, NORM, radius)) return circles def circleFrom3LineTangents (edge1, edge2, edge3): "circleFrom3LineTangents(edge,edge,edge)" def rot(ed): - return Part.Line(v1(ed),v1(ed).add(fcvec.rotate(vec(ed),math.pi/2))).toShape() + return Part.Line(v1(ed),v1(ed).add(DraftVecUtils.rotate(vec(ed),math.pi/2))).toShape() bis12 = angleBisection(edge1,edge2) bis23 = angleBisection(edge2,edge3) bis31 = angleBisection(edge3,edge1) @@ -1766,7 +1766,7 @@ def circleFrom3LineTangents (edge1, edge2, edge3): for int in intersections: exists = False for cir in circles: - if fcvec.equals(cir.Center, int.Center): + if DraftVecUtils.equals(cir.Center, int.Center): exists = True break if not exists: @@ -1783,16 +1783,16 @@ def circleFromPointLineRadius (point, edge, radius): center2 = None if dist.Length == 0: segment = vec(edge) - perpVec = fcvec.crossproduct(segment); perpVec.normalize() - normPoint_c1 = fcvec.scale(perpVec, radius) - normPoint_c2 = fcvec.scale(perpVec, -radius) + perpVec = DraftVecUtils.crossproduct(segment); perpVec.normalize() + normPoint_c1 = DraftVecUtils.scale(perpVec, radius) + normPoint_c2 = DraftVecUtils.scale(perpVec, -radius) center1 = point.add(normPoint_c1) center2 = point.add(normPoint_c2) elif dist.Length > 2 * radius: return None elif dist.Length == 2 * radius: normPoint = point.add(findDistance(point, edge, False)) - dummy = fcvec.scale(normPoint.sub(point), 0.5) + dummy = DraftVecUtils.scale(normPoint.sub(point), 0.5) cen = point.add(dummy) circ = Part.Circle(cen, NORM, radius) if circ: @@ -1801,12 +1801,12 @@ def circleFromPointLineRadius (point, edge, radius): return None else: normPoint = point.add(findDistance(point, edge, False)) - normDist = fcvec.dist(normPoint, point) + normDist = DraftVecUtils.dist(normPoint, point) dist = math.sqrt(radius**2 - (radius - normDist)**2) - centerNormVec = fcvec.scaleTo(point.sub(normPoint), radius) + centerNormVec = DraftVecUtils.scaleTo(point.sub(normPoint), radius) edgeDir = edge.Vertexes[0].Point.sub(normPoint); edgeDir.normalize() - center1 = centerNormVec.add(normPoint.add(fcvec.scale(edgeDir, dist))) - center2 = centerNormVec.add(normPoint.add(fcvec.scale(edgeDir, -dist))) + center1 = centerNormVec.add(normPoint.add(DraftVecUtils.scale(edgeDir, dist))) + center2 = centerNormVec.add(normPoint.add(DraftVecUtils.scale(edgeDir, -dist))) circles = [] if center1: circ = Part.Circle(center1, NORM, radius) @@ -1824,10 +1824,10 @@ def circleFromPointLineRadius (point, edge, radius): def circleFrom2PointsRadius(p1, p2, radius): "circleFrom2PointsRadiust(Vector, Vector, radius)" - if fcvec.equals(p1, p2): return None + if DraftVecUtils.equals(p1, p2): return None p1_p2 = Part.Line(p1, p2).toShape() - dist_p1p2 = fcvec.dist(p1, p1) + dist_p1p2 = DraftVecUtils.dist(p1, p1) mid = findMidpoint(p1_p2) if dist_p1p2 == 2*radius: circle = Part.Circle(mid, norm, radius) @@ -1836,8 +1836,8 @@ def circleFrom2PointsRadius(p1, p2, radius): dir = vec(p1_p2); dir.normalize() perpDir = dir.cross(Vector(0,0,1)); perpDir.normailze() dist = math.sqrt(radius**2 - (dist_p1p2 / 2.0)**2) - cen1 = Vector.add(mid, fcvec.scale(perpDir, dist)) - cen2 = Vector.add(mid, fcvec.scale(perpDir, -dist)) + cen1 = Vector.add(mid, DraftVecUtils.scale(perpDir, dist)) + cen2 = Vector.add(mid, DraftVecUtils.scale(perpDir, -dist)) circles = [] if cen1: circles.append(Part.Circle(cen1, norm, radius)) if cen2: circles.append(Part.Circle(cen2, norm, radius)) @@ -2069,7 +2069,7 @@ def findHomotheticCenterOfCircles(circle1, circle2): ''' if isinstance(circle1.Curve, Part.Circle) and isinstance(circle2.Curve, Part.Circle): - if fcvec.equals(circle1.Curve.Center, circle2.Curve.Center): + if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center): return None cen1_cen2 = Part.Line(circle1.Curve.Center, circle2.Curve.Center).toShape() @@ -2079,21 +2079,21 @@ def findHomotheticCenterOfCircles(circle1, circle2): perpCenDir = cenDir.cross(Vector(0,0,1)); perpCenDir.normalize() # Get point on first circle - p1 = Vector.add(circle1.Curve.Center, fcvec.scale(perpCenDir, circle1.Curve.Radius)) + p1 = Vector.add(circle1.Curve.Center, DraftVecUtils.scale(perpCenDir, circle1.Curve.Radius)) centers = [] # Calculate inner homothetic center # Get point on second circle - p2_inner = Vector.add(circle1.Curve.Center, fcvec.scale(perpCenDir, -circle1.Curve.Radius)) - hCenterInner = fcvec.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_inner, True, True) + p2_inner = Vector.add(circle1.Curve.Center, DraftVecUtils.scale(perpCenDir, -circle1.Curve.Radius)) + hCenterInner = DraftVecUtils.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_inner, True, True) if hCenterInner: centers.append(hCenterInner) # Calculate outer homothetic center (only exists of the circles have different radii) if circle1.Curve.Radius != circle2.Curve.Radius: # Get point on second circle - p2_outer = Vector.add(circle1.Curve.Center, fcvec.scale(perpCenDir, circle1.Curve.Radius)) - hCenterOuter = fcvec.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_outer, True, True) + p2_outer = Vector.add(circle1.Curve.Center, DraftVecUtils.scale(perpCenDir, circle1.Curve.Radius)) + hCenterOuter = DraftVecUtils.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_outer, True, True) if hCenterOuter: centers.append(hCenterOuter) @@ -2121,13 +2121,13 @@ def findRadicalAxis(circle1, circle2): ''' if isinstance(circle1.Curve, Part.Circle) and isinstance(circle2.Curve, Part.Circle): - if fcvec.equals(circle1.Curve.Center, circle2.Curve.Center): + if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center): return None r1 = circle1.Curve.Radius r2 = circle1.Curve.Radius cen1 = circle1.Curve.Center # dist .. the distance from cen1 to cen2. - dist = fcvec.dist(cen1, circle2.Curve.Center) + dist = DraftVecUtils.dist(cen1, circle2.Curve.Center) cenDir = cen1.sub(circle2.Curve.Center); cenDir.normalize() # Get the perpedicular vector. @@ -2142,7 +2142,7 @@ def findRadicalAxis(circle1, circle2): k1 = (dist + (r1^2 - r2^2) / dist) / 2.0 #k2 = dist - k1 - K = Vector.add(cen1, fcvec.scale(cenDir, k1)) + K = Vector.add(cen1, DraftVecUtils.scale(cenDir, k1)) # K_ .. A point somewhere between K and J (actually with a distance of 1 unit from K). K_ = Vector,add(K, perpCenDir) @@ -2208,13 +2208,13 @@ def pointInversion(circle, point): cen = circle.Curve.Center rad = circle.Curve.Radius - if fcvec.equals(cen, point): + if DraftVecUtils.equals(cen, point): return None # Inverse the distance of the point # dist(cen -> P) = r^2 / dist(cen -> invP) - dist = fcvec.dist(point, cen) + dist = DraftVecUtils.dist(point, cen) invDist = rad**2 / d invPoint = Vector(0, 0, point.z) @@ -2260,7 +2260,7 @@ def circleInversion(circle, circle2): cen1 = circle.Curve.Center rad1 = circle.Curve.Radius - if fcvec.equals(cen1, point): + if DraftVecUtils.equals(cen1, point): return None invCen2 = Inversion(circle, circle2.Curve.Center) @@ -2268,7 +2268,7 @@ def circleInversion(circle, circle2): pointOnCircle2 = Vector.add(circle2.Curve.Center, Vector(circle2.Curve.Radius, 0, 0)) invPointOnCircle2 = Inversion(circle, pointOnCircle2) - return Part.Circle(invCen2, norm, fcvec.dist(invCen2, invPointOnCircle2)) + return Part.Circle(invCen2, norm, DraftVecUtils.dist(invCen2, invPointOnCircle2)) else: print "debug: circleInversion bad parameters!\n" From 3b67a56b1ee3cff12b78040c03688d4cb862f22a Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Tue, 22 May 2012 17:09:06 -0300 Subject: [PATCH 29/42] Added 0000680 : DXF polylines with defined width --- src/Mod/Draft/Draft.py | 3 +- src/Mod/Draft/Draft_rc.py | 410 +++++++++--------- .../Draft/Resources/ui/userprefs-import.ui | 20 + src/Mod/Draft/importDXF.py | 17 +- 4 files changed, 246 insertions(+), 204 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 300bc8692..2e7cf692d 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -107,7 +107,8 @@ def getParamType(param): elif param in ["textheight","tolerance","gridSpacing"]: return "float" elif param in ["selectBaseObjects","alwaysSnap","grid","fillmode","saveonexit","maxSnap", - "SvgLinesBlack","dxfStdSize","showSnapBar","hideSnapBar","alwaysShowGrid"]: + "SvgLinesBlack","dxfStdSize","showSnapBar","hideSnapBar","alwaysShowGrid", + "renderPolylineWidth"]: return "bool" elif param in ["color","constructioncolor","snapcolor"]: return "unsigned" diff --git a/src/Mod/Draft/Draft_rc.py b/src/Mod/Draft/Draft_rc.py index 7ef42e43f..e1f587ddd 100644 --- a/src/Mod/Draft/Draft_rc.py +++ b/src/Mod/Draft/Draft_rc.py @@ -2,8 +2,8 @@ # Resource object code # -# Created: Fri May 4 19:15:01 2012 -# by: The Resource Compiler for PyQt (Qt v4.7.4) +# Created: Tue May 22 16:46:43 2012 +# by: The Resource Compiler for PyQt (Qt v4.8.1) # # WARNING! All changes made in this file will be lost! @@ -26543,153 +26543,159 @@ qt_resource_data = "\ \x93\x83\x1e\x48\xef\x57\xc6\xa2\x49\xdb\x13\x44\xd4\xba\x3f\x06\ \x46\x3f\xfe\x6c\x03\x93\xf1\x73\xb1\x4b\x54\x79\xc9\xd8\x04\x84\ \x23\xc5\xbe\x37\x98\x7a\x44\xf4\xff\x03\x15\x2c\x14\x99\ -\x00\x00\x09\x10\ +\x00\x00\x09\x69\ \x00\ -\x00\x45\x1d\x78\x9c\xed\x5c\x6d\x73\xdb\x36\x12\xfe\xee\x5f\x81\ -\xd1\x87\xbb\xb4\xe3\x5a\x96\x5f\x93\x9c\xac\x4e\x62\xd7\x49\x6e\ -\x92\x6b\x7a\x72\xd3\xfb\xe6\x81\x48\x48\x44\x4d\x12\x2a\x00\x5a\ -\x52\x7f\xfd\xed\x02\xa0\xf8\x22\xea\xdd\x92\x1c\x8f\x66\x3c\x23\ -\x11\x00\x77\x17\x8b\x67\x17\x8b\xc5\x5a\xcd\x9f\x87\x51\x48\x1e\ -\x99\x54\x5c\xc4\x57\xb5\xc6\xd1\x71\x8d\xb0\xd8\x13\x3e\x8f\x7b\ -\x57\xb5\xdf\xef\x6e\x7f\x7a\x5d\xfb\xb9\x75\xd0\x4c\x78\x36\xe8\ -\x0c\x06\xb5\x0e\x48\xd3\x0b\xa9\x52\xad\x0f\x09\x7f\xfb\xf6\x86\ -\xd3\x50\xf4\xe0\x33\xec\xb5\x99\xd6\xf0\xb2\xba\x91\xb4\xab\x9b\ -\x75\x3b\x08\x46\x0f\xb8\xdf\x63\x9a\x98\xe7\xab\xda\x6f\x7f\x98\ -\xc7\x1a\x89\x69\xc4\xae\x6a\x33\x89\x20\x33\xd2\xec\x4b\xd1\x67\ -\x52\x8f\xdc\x1b\x3d\x26\x22\xa6\xe5\xc8\x74\x92\xa6\x64\x9e\x36\ -\xdf\x48\x73\xd8\x3a\x6e\xd6\x87\xee\x61\x84\x0f\x23\xf7\x00\x22\ -\xe8\xa0\x75\x7e\x79\xde\xac\xdb\xaf\xb6\x39\x60\xbc\x17\xe8\xd6\ -\xc5\xc9\x9b\x66\xdd\x7d\x37\x34\xeb\x29\xd1\x66\x3d\x65\x5e\x25\ -\xc9\x80\xc7\xbe\x18\xdc\x71\x1d\x32\x27\x8c\xd2\x12\x84\x6f\x7d\ -\x8a\xfa\x42\xea\xfa\x2f\x43\xfc\x68\xd6\x5d\xeb\x24\xbd\x90\x8e\ -\x44\x92\x69\xe6\xdb\x7b\x31\xfc\x6c\x9a\x1c\xb9\x12\x3f\xd5\xa7\ -\x1e\x10\xaa\x39\xe9\xe3\x24\xea\x30\xd9\xba\x68\xd6\xdd\x37\x2b\ -\x7b\x9e\xc3\x04\x89\x88\xca\x1e\x8f\x4b\x14\xde\xcc\xa4\xc0\x35\ -\x8b\x32\x35\xe6\x57\xf2\x83\x14\x49\x1f\x64\x1e\xaf\xa5\x7b\x6e\ -\x9c\x38\x06\x13\xec\x75\xa6\xab\x9c\xba\x6e\xfe\x77\x4b\xba\x42\ -\x46\x54\x13\xd1\xd7\x80\x34\x95\xd7\xd9\xa4\x48\xf3\x35\x37\x57\ -\x79\x53\xf5\x57\xc5\x6d\xb6\x16\xa7\x2a\xb2\x9a\x54\xa6\xce\x8a\ -\x79\x7c\x9c\x9c\xc7\x02\x33\x99\x31\x97\x2a\x11\xe6\xcf\x27\x23\ -\x78\xbc\x20\xc1\xc2\xac\x26\x91\xf2\x99\x76\x58\x98\xc2\x44\xb3\ -\xa1\x36\x0d\x8d\xfb\xd3\x3c\xcf\x49\xb4\xc0\xc0\xc2\x80\x92\x81\ -\x11\xa5\x47\x21\x2b\x61\x65\xaa\x8c\xc4\xd8\x3e\x48\x95\x9f\x4a\ -\x51\xee\x39\xd3\x30\xbe\xea\xab\x64\xdd\x6b\x11\x75\x44\x0e\xf8\ -\x3d\xec\xe8\x43\x87\x87\x1d\x1d\xe8\x98\x39\x2d\x21\xc2\x3b\xde\ -\xaf\x9e\xd9\x5d\xc0\x15\x81\x3f\x1d\x30\x02\x6e\x2e\x10\x3e\xf1\ -\x02\x21\x14\xf3\xd1\x44\x08\x37\x13\x87\x81\x04\x1e\xb4\xa4\xb1\ -\x0a\xa9\x79\x44\x1b\x12\x9d\x3f\xc1\x6f\x11\x4f\x84\x38\x32\xd6\ -\x82\xdc\x4a\xc6\xae\xdf\xdd\x1c\x91\x83\x4f\x5d\xd7\x1e\xd1\x7e\ -\x1f\x5f\x00\x1e\x8e\xf0\x21\x01\xc0\x91\x28\x51\xda\xb5\x10\x5a\ -\x1a\xdb\xe5\x21\x83\xa6\x58\x53\x1e\xe3\x33\xcd\x58\x8b\x98\x68\ -\xda\x81\x6e\x1d\x80\xf9\x0e\x78\x18\xe2\x40\xd8\x31\x9c\x1c\xca\ -\x0a\x12\xf2\x98\x19\xcf\xab\x8e\x0e\x16\x5e\xb0\x09\xcd\x79\x89\ -\x94\x2c\xd6\x9f\x62\x9f\x0d\x4b\xea\x9b\x8e\xd7\x45\x89\xe3\xfa\ -\xfd\x12\xe3\xc6\x02\xb8\xf2\x15\xd3\x57\xb5\xe3\x12\x13\xcf\x09\ -\xee\x0f\xbb\x0e\x7a\xde\xaa\x53\x41\x6e\x5f\xa9\x0e\xe6\x33\xfb\ -\x22\xfc\x7a\xba\xa5\x2e\xcc\xad\x04\xe4\x45\x6c\x6b\x0c\xc1\xff\ -\x88\x98\x91\x57\x5d\xaa\x34\x53\xfa\x87\xaa\xd5\x9a\xc6\xb5\x5e\ -\x66\xbb\x96\x1c\xbf\x03\x12\x7d\xd6\xa5\x49\x98\x62\x9a\xc6\x7e\ -\x86\xa4\xdd\x09\xf6\xab\xe4\xe0\x2e\x69\xf8\xbc\xa4\xba\x1e\x9b\ -\x2c\xf8\x8a\xbc\xc9\xed\x50\x24\xc9\xa8\x66\xa4\x4f\x25\xc5\x90\ -\x8d\x7b\xce\x45\x95\xf7\xf7\xed\x8b\xd4\x7e\x60\xda\x0b\xd8\x5a\ -\x82\xcc\xdd\x4f\x9a\x75\xbb\xbd\x67\xd1\x40\xbe\x7b\xe1\x48\xc0\ -\x4d\x2a\x10\x92\xff\x8d\x3e\x38\x9c\x8c\x10\x96\xd9\x7e\x43\x7c\ -\xb8\xbf\x5c\x71\xe7\xfd\x42\x87\xa4\xdd\x47\x6c\x91\x36\xeb\x45\ -\xe0\x8d\x77\xb0\xff\xb6\x61\x57\xaa\xda\x7e\x15\xb4\xc3\xee\x7b\ -\x7f\x32\x73\x72\x11\x1d\xf2\x28\x89\xda\xfc\x6f\x56\x9e\x23\x34\ -\x95\x60\x63\x8f\x0b\x17\xc7\x85\x83\xc3\xb8\xd7\x1d\x1a\x1a\x17\ -\x97\x97\x97\x27\x8d\xf3\xc2\x29\x22\x9b\x64\x99\xec\x62\x3b\xc4\ -\xcc\x30\xe1\x8f\x80\xc5\x84\x0d\xd3\x60\x40\x99\x15\x51\x68\xf6\ -\x10\x08\x1c\x62\xf4\x30\x22\x54\x32\xbb\x4f\x63\x6c\x0d\x3e\x81\ -\xc7\xa4\x2f\xc2\x91\x19\x79\x44\x4c\xa0\xf1\x48\xc3\x84\x8d\xc3\ -\x0d\xab\x17\x12\xb2\xb8\xa7\x03\x22\xba\x84\x51\xcf\x7c\x62\x6f\ -\xfa\x2a\x51\x76\xd9\x81\x04\xc4\x14\xc7\x86\x57\x6c\x46\x0c\x02\ -\x01\x71\x80\x15\xc5\xd0\x34\xa6\xe6\x13\xaa\x20\x60\x00\xb9\x29\ -\xaa\x26\x7d\xfd\x68\xf5\x28\xc0\x08\x5d\xbd\xfd\x9f\x6f\x65\xfb\ -\x07\x45\x39\x85\xa7\x16\xf0\x3c\xc3\x80\x1d\x3b\xa8\x42\x74\xbf\ -\xbc\x8b\x5a\xd1\x41\x5d\x4f\x44\xae\x3b\x70\x50\xb7\xc0\xf6\xda\ -\xc4\xd2\x72\xc2\x49\xa1\x48\x9e\xeb\x9b\xe9\xa6\x20\xd6\x5e\xd2\ -\x4d\x9d\x1e\xcf\xf6\x53\xc7\xdb\x73\x50\x77\x01\xab\x3a\x44\x74\ -\x4b\xc7\x16\x88\xa4\xa7\x9c\x13\x56\xf7\x0f\xcb\x05\xf2\x4e\x3c\ -\x0b\x94\xbd\x1d\x57\xd9\xf1\xe5\xe2\x76\x9c\x1d\x91\x03\xe6\x3d\ -\x54\x1e\x91\xb1\x63\xfe\x26\x3d\x13\x5c\x1c\xb7\x24\x7b\x4e\x4e\ -\x62\x43\x10\x4f\xb1\xe8\x13\x54\x3d\x32\x1f\x64\x20\xe2\x7f\x6a\ -\xd2\x61\xee\xc4\xcc\xfc\xd5\xf1\x34\x37\x0d\x61\x39\xe2\x31\xc0\ -\xe7\xb0\x1f\xa8\x8a\x0c\xd6\x92\x50\x5a\x1c\xbe\xc8\x7b\x8f\xdb\ -\x6a\xdc\x9e\x6c\x04\xb7\x73\x72\x56\x0b\xe2\x76\x8c\xda\x3e\x85\ -\xd7\x09\xe6\xf4\x58\x7a\x3a\xb2\x69\x94\x1c\x76\x21\xae\x13\x1b\ -\xc4\xaf\xd5\xec\xd6\x20\x6b\xd9\xed\x41\x5b\x0d\xda\xb3\x8d\x80\ -\x76\xce\x71\x6f\x16\x68\x0d\x71\x87\xdb\xae\x49\x15\x0e\x68\xac\ -\x4d\xc4\x1f\x8b\xf8\x27\xa4\xe0\x93\x4e\x28\xbc\x07\x45\x5e\x75\ -\x58\x8f\xc7\x26\x47\x38\xe0\x70\x86\xa0\xe4\xc7\x1f\xf0\x50\xb2\ -\x3d\x2c\xff\x68\x25\xd9\x16\x96\x95\xa6\x32\xe5\xb8\xc7\x73\x15\ -\x9e\x5f\x6f\x04\xcf\xe7\x4f\xeb\x84\x53\xc7\xdb\x95\x22\x32\xc8\ -\x56\x40\x07\xfd\x22\x93\x99\x37\xfe\x53\x40\x70\xea\xdb\x38\xd5\ -\x2c\x02\x79\x6f\x56\x1e\x22\x8f\x44\x1a\xcc\xe3\x9b\x3e\x87\xb3\ -\x21\x1d\x11\x93\x3f\x95\x87\xa4\x03\xea\x8a\xe8\x83\xeb\xc6\xd3\ -\xb5\x52\x70\xb0\x56\x3c\x1c\x11\xe6\x73\x93\x3c\xdf\x84\x3d\x98\ -\xcb\xb8\x74\x0a\x46\xe6\x2d\x5a\x46\x0f\x99\x7f\x36\xbc\xf7\x76\ -\x51\x6d\x17\xe7\x1b\xb1\x8b\x37\xab\xdb\x05\xde\x10\xa5\xf6\xd0\ -\x95\x8c\x79\xd4\xb7\xd0\x87\x15\x47\x1f\x8e\xf0\xc7\x44\x3c\x8f\ -\x3d\xee\x33\xf8\x9a\x1a\x8d\x01\xd7\x80\x4b\xcc\x2a\xbd\x67\x03\ -\x2a\xd9\xa1\xb5\x30\x8f\xe2\xe5\xd0\x03\xde\x27\x0d\x02\x38\x5f\ -\x1d\x1d\xad\x91\xf5\x99\x8e\xf4\x7f\x83\x48\x24\xad\x0a\xd8\x0a\ -\xbc\x51\x15\x19\xc3\x3d\xbe\xab\xf0\x7d\xb1\x09\x7c\xaf\x85\xee\ -\x09\xaf\x4f\x01\xdc\x29\x88\x73\xb7\x9b\x5d\x08\xc5\x33\xaf\x6f\ -\x93\xac\x36\x8d\x79\xea\x9b\x34\xa8\x19\xb0\x09\x24\xdb\x82\x11\ -\x72\x7a\x33\x16\x0b\x98\xa6\x1c\x49\xc4\xd4\x94\x1b\x8b\x8d\xe4\ -\x45\x80\xdb\x1e\xdb\xd5\xd8\x6e\x34\x36\xe2\xbc\x5f\x3f\x2d\xbc\ -\xb3\x88\xdb\x66\x44\x10\xd0\x28\x98\x89\x6f\x34\x8d\x7d\x2a\x7d\ -\x17\xc8\xe0\x08\x82\x59\x40\x78\x2b\x86\xb8\x05\x5c\xbf\x4b\xfb\ -\x63\xa3\xbd\x4e\x08\xe8\x23\xc3\x3b\x04\x6c\xc5\x6a\x03\x5f\x78\ -\xc9\x52\xf7\x3f\x4b\x18\x02\x5e\xfd\x8e\x45\xec\x82\xea\xad\x1c\ -\x26\x7b\x88\x93\xd9\x96\x11\xb4\xb5\x8f\xf9\xd7\xbd\x1d\x4c\xb1\ -\x83\xcd\x64\x58\x1a\xc7\x4f\x6b\x08\x01\x35\x77\xbd\x63\x97\xee\ -\x0a\x54\xd2\x58\x5e\x81\xa1\x84\xcc\x46\x30\x1b\x3c\x99\x1a\x29\ -\x48\x47\x24\x88\x6a\xce\x8c\x6f\x5f\x93\xe7\x12\x60\xb6\xce\xe0\ -\x66\xd8\xfd\x48\xdd\xc5\xf7\x4b\x84\x74\xb1\xb3\x40\x2b\x37\x6e\ -\xa5\x92\xc6\xfb\x25\x8b\x1a\xdb\xdf\x3e\x3c\x5d\x51\xa3\xe3\x94\ -\xcb\x3d\x7e\xef\xe5\x8d\xe9\x8c\x0a\xe9\xae\x97\x5b\xe8\x38\x27\ -\x5f\xb1\xf3\x42\x47\x93\x7f\x96\x13\x7e\xbe\x6d\x9a\x0b\xb1\xfc\ -\xa4\xf4\x30\x1a\xc2\x00\x53\x0b\x58\x9a\x04\x03\x95\xb6\x7e\xd3\ -\x6f\xdf\x7e\x1c\x53\x6c\xd6\x4d\xe3\xd2\x4e\x07\xf7\xff\x8f\xe0\ -\xae\xa7\x3b\x9d\xa9\xb7\xa2\x67\xb3\x2f\x45\x4f\xd6\xba\x15\x85\ -\x61\x46\x47\x4b\xe8\x7a\xd5\xa2\xd2\x75\x6e\x1e\x16\x2e\x2b\x45\ -\xb7\x35\xbd\x8e\xf4\xfb\x2f\xdd\x54\x8f\xbd\x7d\xe9\xe6\xbe\x74\ -\xf3\xa9\xa5\xda\x75\x24\xfe\x66\xf1\x40\xbc\xaa\x1a\x70\xce\x5d\ -\xfc\xbc\x84\x45\xfb\x99\xd4\xe1\x83\x71\xdf\xdb\x7c\xcd\xbd\x31\ -\xf2\xfb\xf5\xeb\xf1\xcd\xd4\xf0\x30\x6c\xe2\x39\x2c\x61\xc1\x64\ -\xa7\x04\x01\xc9\xa0\x58\x83\x47\x5d\x51\xe9\xcb\x70\x92\x05\x3d\ -\xbe\x4c\x67\x79\xe7\xea\x90\x60\x0f\x7c\x85\x9b\x60\x5f\x62\x82\ -\xfb\x1f\x34\xea\xff\x2b\xbd\xc5\xd9\xa1\x0b\xfd\x2f\x1d\x58\xb1\ -\xae\xdf\x7d\x59\x4b\x8c\x5d\xbb\xa6\xc2\x69\xfe\xe9\x92\x04\xb3\ -\x63\xd2\x65\x8a\x67\xd1\xb2\x1f\x39\x1b\xa8\x43\xbc\xa8\x63\x26\ -\x2d\x3c\x08\xd0\xc2\xcd\xd6\x20\xe4\x03\xc1\xa2\x7a\x8a\xb1\x10\ -\xe9\x84\xd4\x7b\x38\x34\x41\x53\x87\x69\x0d\x31\xb3\x64\xd4\xa7\ -\x1d\x1e\x72\x60\x4e\x7b\x14\xf3\x67\xee\xf5\x0e\x0c\xc5\x9b\xb0\ -\xd8\xdf\x48\x5e\x61\x8c\xdf\x9c\xb4\x6e\x5f\x33\xb7\x7d\xc0\x7d\ -\x0d\x57\x64\x93\x27\x25\xce\x1d\x50\x6b\x4b\xcb\x04\x3c\x82\xf9\ -\xba\x49\x27\xd4\x7e\xec\x7d\xc6\x1a\xdb\xf7\x76\x22\xcf\xd3\x03\ -\x3d\xdf\x74\xc5\xf8\xb0\xb0\x58\xba\xe2\xd7\xeb\x77\x4f\x9f\xae\ -\xc8\x6c\xf4\xa5\xa4\x2b\x0a\xa5\x90\xdf\x7d\xba\x62\x09\x77\x7b\ -\xb6\xba\xbb\x9d\x51\x40\x44\xc1\x79\x2a\xf2\xea\xf4\xc6\x5e\xba\ -\x55\xd5\x0a\x6d\xe4\xca\xd8\xa5\x55\x10\xf4\x46\x84\xad\xa4\x60\ -\x85\x47\x1d\xb3\xbd\x2f\x33\x6b\x91\xcf\x39\x61\x42\x9e\x7b\x69\ -\xc6\x69\x9a\xef\xaa\x4a\x35\x65\x59\xa6\x6f\x8e\x46\x21\xc7\x34\ -\xe9\xb7\x96\xc8\x2c\x15\x93\x4a\x2e\x9f\x74\x32\x91\x4f\x4a\x53\ -\x49\x67\x13\xa9\xa4\x42\x16\xa9\x2c\x4a\x21\x77\x94\x29\x29\xa7\ -\xc9\x9c\x1a\x9d\x73\x4a\x4f\xd5\xce\xd9\x5c\xd5\x2e\x6a\xc4\xba\ -\x89\xab\x5a\xa3\x51\xab\xe3\xc8\x3e\x1f\x46\xb4\xdf\x4d\x62\x0f\ -\x15\xd5\xfa\xeb\xab\x79\xbe\x95\x22\xfa\xc2\x23\xd6\x16\x89\xf4\ -\x60\x03\x2f\x8d\xc2\x9f\x75\x48\x94\x16\x91\xe5\xa8\x8c\x24\xf9\ -\x16\x2b\x65\xee\xa7\x1f\x72\xff\xe4\x90\xfd\xda\x03\xae\xc7\x50\ -\x33\x08\x79\x5a\xee\x97\x1e\x60\x35\x5c\xc3\x81\x55\x15\xf5\x61\ -\xca\x40\xa1\x8e\x04\xec\x4f\x3f\x1c\x05\xa8\x38\xd3\x61\x14\x50\ -\xe6\x3b\x5b\x90\xd2\x7f\x5c\x54\x0a\x33\x29\xf1\x34\xa9\x90\x9a\ -\x95\x5c\xad\x2f\x96\xfb\x4f\xb5\x6a\xfd\x8c\x3b\xb7\x22\x4a\xea\ -\xe3\xab\x65\xc9\x7a\xb7\x23\x8c\x3b\xb9\x4f\x11\x66\xdc\xbb\xbe\ -\x30\xc5\x06\xf3\x83\x24\x92\x29\x63\x03\xca\x58\x8b\x27\xe2\x98\ -\x19\x1b\xc0\xe7\x66\x3d\xe1\xad\x83\xff\x03\xad\x19\x30\x45\ +\x00\x48\x24\x78\x9c\xed\x5c\x5b\x73\xdb\xb6\x12\x7e\xf7\xaf\xc0\ +\xe8\xe1\x9c\xb4\xe3\x5a\x92\xaf\x49\x8e\xac\x4e\x62\xd7\x49\x3a\ +\xc9\x69\x5a\xb9\x49\xdf\x3c\x10\x09\x89\xa8\x49\x42\x05\x40\x4b\ +\xea\xaf\xef\x2e\x00\x8a\x14\x45\xdd\x2d\xc9\x71\x35\xe3\x19\x8b\ +\x00\x88\x5d\x2c\xbe\x5d\xec\x2e\x56\x6a\xfc\x38\x88\x42\xf2\xc0\ +\xa4\xe2\x22\xbe\xac\xd4\x8f\x6a\x15\xc2\x62\x4f\xf8\x3c\xee\x5e\ +\x56\x7e\xbf\xbd\xf9\xe1\x65\xe5\xc7\xe6\x41\x23\xe1\xd9\xa0\x53\ +\x18\xd4\x3c\x20\x0d\x2f\xa4\x4a\x35\xdf\x25\xfc\xf5\xeb\x6b\x4e\ +\x43\xd1\x85\xff\x61\xb7\xc5\xb4\x86\x97\xd5\xb5\xa4\x1d\xdd\xa8\ +\xda\x41\x30\xba\xcf\xfd\x2e\xd3\xc4\x3c\x5f\x56\x7e\xfd\x6a\x1e\ +\x2b\x24\xa6\x11\xbb\xac\xcc\x9c\x04\x89\x91\x46\x4f\x8a\x1e\x93\ +\x7a\xe8\xde\xe8\x32\x11\x31\x2d\x87\xa6\x93\x34\x24\xf3\xb4\xf9\ +\x44\x1a\x83\x66\xad\x51\x1d\xb8\x87\x21\x3e\x0c\xdd\x03\xb0\xa0\ +\x83\xe6\xd9\xc5\x59\xa3\x6a\x3f\xda\xe6\x80\xf1\x6e\xa0\x9b\xe7\ +\xc7\xaf\x1a\x55\xf7\xd9\xcc\x59\x4d\x27\x6d\x54\x53\xe2\x65\x9c\ +\xf4\x79\xec\x8b\xfe\x2d\xd7\x21\x73\xcc\x28\x2d\x81\xf9\xe6\x87\ +\xa8\x27\xa4\xae\xfe\x34\xc0\x7f\x8d\xaa\x6b\x9d\x9c\x2f\xa4\x43\ +\x91\x64\x92\xf9\xf2\x56\x0c\x3e\x9a\x26\x37\x5d\x81\x9e\xea\x51\ +\x0f\x26\xaa\x38\xee\xe3\x24\x6a\x33\xd9\x3c\x6f\x54\xdd\x27\xcb\ +\x7b\x9e\xc2\xc4\x14\x11\x95\x5d\x1e\x17\x66\x78\x35\x73\x06\xae\ +\x59\x94\x89\x31\xbf\x93\xef\xa4\x48\x7a\xc0\xf3\x68\x2f\xdd\x73\ +\xfd\xd8\x11\x98\x20\xaf\x33\x59\xe5\xc4\x75\xfd\xc7\x0d\xe9\x08\ +\x19\x51\x4d\x44\x4f\x03\xd2\x54\x5e\x66\x93\x2c\xcd\x97\xdc\x5c\ +\xe1\x4d\x95\x5f\x19\xb5\xd9\x52\x9c\x2a\xc8\xf2\xa9\x32\x71\x96\ +\xac\xe3\xfd\xe4\x3a\x16\x58\xc9\x8c\xb5\x94\xb1\x30\x7f\x3d\xd9\ +\x84\xb5\x05\x27\x1c\x5b\xd5\x24\x52\x3e\xd2\x36\x0b\x53\x98\x68\ +\x36\xd0\xa6\xa1\x7e\x77\x92\xa7\x39\x89\x16\x18\x38\x36\xa0\xa0\ +\x60\x44\xe9\x61\xc8\x0a\x58\x99\xca\x23\x31\xba\x0f\x5c\xe5\x97\ +\x32\xce\xf7\x9c\x65\x18\x5b\xf5\x59\xb2\xce\x95\x88\xda\x22\x07\ +\xfc\x2e\x76\xf4\xa0\xc3\xc3\x8e\x36\x74\xcc\x5c\x96\x10\xe1\x2d\ +\xef\x95\xaf\xec\x36\xe0\x8a\xc0\x9f\x0e\x18\x01\x33\x17\x08\x9f\ +\x78\x81\x10\x8a\xf9\xa8\x22\x84\x9b\x85\xc3\x40\x02\x0f\x5a\xd2\ +\x58\x85\xd4\x3c\xa2\x0e\x89\xf6\x9f\x60\xb7\x88\x27\x42\x1c\x19\ +\x6b\x41\x6e\x24\x63\x57\x6f\xae\x8f\xc8\xc1\x87\x8e\x6b\x8f\x68\ +\xaf\x87\x2f\x00\x0d\x37\xf1\x21\x01\xc0\x91\x28\x51\xda\xb5\x10\ +\x5a\x18\xdb\xe1\x21\x83\xa6\x58\x53\x1e\xe3\x33\xcd\x48\x8b\x98\ +\x68\xda\x86\x6e\x1d\x80\xfa\xf6\x79\x18\xe2\x40\x38\x31\x1c\x1f\ +\xca\x32\x12\xf2\x98\x19\xcb\xab\x8e\x0e\x16\xde\xb0\x09\xc9\x79\ +\x89\x94\x2c\xd6\x1f\x62\x9f\x0d\x0a\xe2\x9b\x8e\xd7\x45\x27\xc7\ +\xfd\xfb\x29\xc6\x83\x05\x70\xe5\x2b\xa6\x2f\x2b\xb5\x02\x11\xcf\ +\x31\xee\x0f\x3a\x0e\x7a\xde\xaa\x4b\x41\x6a\x9f\xa9\x0e\xe6\x13\ +\xfb\x24\xfc\x6a\x7a\xa4\x2e\x4c\xad\x00\xe4\x45\x74\x6b\x04\xc1\ +\xff\x8b\x98\x91\x17\x1d\xaa\x34\x53\xfa\xbb\xb2\xdd\x9a\x46\xb5\ +\x5a\x24\xbb\x16\x1f\xbf\x03\x12\x7d\xd6\xa1\x49\x98\x62\x9a\xc6\ +\x7e\x86\xa4\xdd\x31\xf6\x8b\xe4\x60\x2e\x69\xf8\xb4\xb8\xba\x1a\ +\xa9\x2c\xd8\x8a\xbc\xca\xed\x90\x25\xc9\xa8\x66\xa4\x47\x25\x45\ +\x97\x8d\x7b\xce\x44\x15\xcf\xf7\xed\xb3\xd4\xba\x67\xda\x0b\xd8\ +\x5a\x8c\xcc\x3d\x4f\x1a\x55\x7b\xbc\x67\xde\x40\xbe\x7b\x61\x4f\ +\xc0\x2d\x2a\x10\x92\xff\x8d\x36\x38\x9c\xf4\x10\x96\x39\x7e\x43\ +\x7c\xb8\xbb\x58\xf1\xe4\xfd\x44\x07\xa4\xd5\x43\x6c\x91\x16\xeb\ +\x46\x60\x8d\x77\x70\xfe\xb6\xe0\x54\x2a\x3b\x7e\x15\xb4\xc3\xe9\ +\x7b\x77\x3c\x73\x71\x11\x1d\xf0\x28\x89\x5a\xfc\x6f\x56\x5c\x23\ +\x34\x15\x60\x63\xc3\x85\xf3\xda\x58\xe0\x30\xea\x75\x41\x43\xfd\ +\xfc\xe2\xe2\xe2\xb8\x7e\x36\x16\x45\x64\x8b\x2c\x4e\xbb\xd8\x09\ +\x31\xd3\x4d\xf8\x1a\xb0\x98\xb0\x41\xea\x0c\x28\xb3\x23\x0a\xd5\ +\x1e\x1c\x81\x43\xf4\x1e\x86\x84\x4a\x66\xcf\x69\xf4\xad\xc1\x26\ +\xf0\x98\xf4\x44\x38\x34\x23\x8f\x88\x71\x34\x1e\x68\x98\xb0\x91\ +\xbb\x61\xe5\x42\x42\x16\x77\x75\x40\x44\x87\x30\xea\x99\xff\xd8\ +\x9b\xbe\x4a\x94\xdd\x76\x98\x02\x7c\x8a\x9a\xa1\x15\x9b\x11\xfd\ +\x40\x80\x1f\x60\x59\x31\x73\x1a\x55\xf3\x09\x55\xe0\x30\x00\xdf\ +\x14\x45\x93\xbe\x7e\xb4\xba\x17\x60\x98\x2e\x3f\xfe\xcf\xb6\x72\ +\xfc\x83\xa0\x9c\xc0\x53\x0d\x78\x9a\x6e\xc0\x8e\x0d\xd4\x98\x77\ +\xbf\xbc\x89\x5a\xd1\x40\x5d\x4d\x78\xae\x3b\x30\x50\x37\x40\xf6\ +\xca\xf8\xd2\x72\xc2\x48\x21\x4b\x9e\xeb\x9b\x69\xa6\xc0\xd7\x5e\ +\xd2\x4c\x9d\xd4\x66\xdb\xa9\xda\xf6\x0c\xd4\x6d\xc0\xca\x82\x88\ +\x4e\x21\x6c\x01\x4f\x7a\x4a\x9c\xb0\xba\x7d\x58\xce\x91\x77\xec\ +\x59\xa0\xec\xf5\xb8\x4c\x8f\x2f\x16\xd7\xe3\x2c\x44\x0e\x98\x77\ +\x5f\x1a\x22\x63\xc7\xfc\x43\x7a\x26\xb8\x38\x1e\x49\x36\x4e\x4e\ +\x62\x33\x21\x46\xb1\x68\x13\x54\x35\x32\xff\x48\x5f\xc4\xff\xd5\ +\xa4\xcd\x5c\xc4\xcc\xfc\xd5\xf1\x34\x37\x0d\x61\x29\x62\x18\xe0\ +\x73\x38\x0f\x54\x49\x06\x6b\x49\x28\x2d\x0e\x5f\xa4\xbd\xc7\x6d\ +\x39\x6e\x8f\x37\x82\xdb\x39\x39\xab\x05\x71\x3b\x42\x6d\x8f\xc2\ +\xeb\x04\x73\x7a\x2c\x8d\x8e\x6c\x1a\x25\x87\x5d\xf0\xeb\xc4\x06\ +\xf1\x6b\x25\xbb\x35\xc8\x5a\x72\x7b\xd0\x96\x83\xf6\x74\x23\xa0\ +\x9d\x13\xee\xcd\x02\xad\x99\xdc\xe1\xb6\x63\x52\x85\x7d\x1a\x6b\ +\xe3\xf1\xc7\x22\xfe\x01\x67\xf0\x49\x3b\x14\xde\xbd\x22\x2f\xda\ +\xac\xcb\x63\x93\x23\xec\x73\x88\x21\x28\xf9\xfe\x3b\x0c\x4a\xb6\ +\x87\xe5\xef\x2d\x27\xdb\xc2\xb2\xd2\x54\xa6\x14\xf7\x78\x2e\xc3\ +\xf3\xcb\x8d\xe0\xf9\xec\x71\x8d\x70\x6a\x78\x3b\x52\x44\x06\xd9\ +\x0a\xe6\x41\xbb\xc8\x64\x66\x8d\xff\x14\xe0\x9c\xfa\xd6\x4f\x35\ +\x9b\x40\xde\x9a\x9d\x07\xcf\x23\x91\x06\xf3\xf8\xa6\xcf\x21\x36\ +\xa4\x43\x62\xf2\xa7\xf2\x90\xb4\x41\x5c\x11\xbd\x77\xdd\x18\x5d\ +\x2b\x05\x81\xb5\xe2\xe1\x90\x30\x9f\x9b\xe4\xf9\x26\xf4\xc1\x5c\ +\xc6\xa5\x4b\x30\x3c\x6f\x51\x33\xba\x48\xfc\xa3\xa1\xbd\xd7\x8b\ +\x72\xbd\x38\xdb\x88\x5e\xbc\x5a\x5d\x2f\xf0\x86\x28\xd5\x87\x8e\ +\x64\xcc\xa3\xbe\x85\x3e\xec\x38\xda\x70\x84\x3f\x26\xe2\x79\xec\ +\x71\x9f\xc1\xc7\x54\x69\x0c\xb8\xfa\x5c\x62\x56\xe9\x2d\xeb\x53\ +\xc9\x0e\xad\x86\x79\x14\x2f\x87\xee\xf1\x3e\xa9\x1f\x40\x7c\x75\ +\x74\xb4\x46\xd6\x67\x3a\xd2\x7f\x06\x96\x48\x5a\x15\xb0\x15\x78\ +\xa3\x28\x32\x82\x7b\x7c\x97\xe1\xfb\x7c\x13\xf8\x5e\x0b\xdd\x13\ +\x56\x9f\x02\xb8\x53\x10\xe7\x6e\x37\x3b\xe0\x8a\x67\x56\xdf\x26\ +\x59\x6d\x1a\xf3\xc4\x37\x69\x50\x33\x60\x13\x48\xb6\x05\x23\xe4\ +\xe4\x7a\xc4\x16\x10\x4d\x29\x92\x88\xa9\x29\x37\x16\x1b\xc9\x8b\ +\x00\xb5\x3d\xb6\xcb\xb1\x5d\xaf\x6f\xc4\x78\xbf\x7c\x5c\x78\x67\ +\x1e\xb7\xcd\x88\x20\xa0\x91\x31\xe3\xdf\x68\x1a\xfb\x54\xfa\xce\ +\x91\xc1\x11\x04\xb3\x80\xf0\x56\x0c\x7e\x0b\x98\x7e\x97\xf6\xc7\ +\x46\x7b\x9d\x10\xd0\x07\x86\x77\x08\xd8\x8a\xd5\x06\xbe\xf0\x92\ +\xa5\xee\x7f\x96\x50\x04\xbc\xfa\x1d\xb1\xd8\x01\xd1\x5b\x3e\x4c\ +\xf6\x10\x17\xb3\x2d\x25\x68\x69\x1f\xf3\xaf\x7b\x3d\x98\xa2\x07\ +\x9b\xc9\xb0\xd4\x6b\x8f\xab\x08\x01\x35\x77\xbd\x23\x93\xee\x0a\ +\x54\x52\x5f\x5e\x81\xa2\x84\xcc\x7a\x30\x1b\x8c\x4c\x0d\x17\xa4\ +\x2d\x12\x44\x35\x67\xc6\xb6\xaf\x49\x73\x09\x30\x5b\x63\x70\x3d\ +\xe8\xbc\xa7\xee\xe2\x7b\x0f\xe9\x52\x48\x2f\x71\x69\xb5\x0c\xa4\ +\xeb\x8f\x0b\xe9\x3e\x5e\xba\x8e\x6e\x73\xad\x6d\x06\x2f\x1b\x6f\ +\x4e\xb0\x66\x06\x03\x55\x77\x0b\x9c\x82\x5e\xb2\xd8\x67\xd2\xfa\ +\x31\x5e\x68\x0a\xca\x0c\xfa\x6c\xa2\x46\x9b\xeb\x1a\x89\x75\xaf\ +\x64\x6a\xd1\xc8\xba\x8a\xf0\x9b\x61\x21\xc7\xb6\x21\xbd\x26\xb9\ +\x25\x74\xc0\x8a\xe0\xb3\x23\xff\xd5\xd2\x7d\x8e\x6a\x30\xde\x39\ +\x36\x57\x6e\xdc\x4a\x95\xbd\x77\x4b\xd6\xf6\xb6\xbe\xbc\x7b\xbc\ +\xda\x5e\x47\x29\x97\x82\xff\xd6\xab\x7c\xd3\x15\x8d\x65\x7d\x9f\ +\x6f\xbd\xef\x9c\xb4\xdd\xce\xeb\x7d\xcd\x35\x8c\x9c\x38\x1b\x5a\ +\xa6\x79\x2c\xa4\x9d\xe4\x1e\x46\x83\x37\x6c\x4a\x62\x0b\x8b\x60\ +\x20\xd2\xe6\xaf\xfa\xf5\xeb\xf7\xa3\x19\x1b\x55\xd3\xb8\xb4\xd1\ +\x41\x37\xf8\x3d\x78\x2d\xd3\x8d\xce\xd4\xe2\x80\xd3\xd9\xb5\x01\ +\xc7\x6b\x15\x07\xc0\x30\x23\xa3\x25\x64\xbd\x6a\x6d\xf5\x3a\x17\ +\x70\x0b\x57\x57\xa3\xd9\x9a\x5e\x4e\xfd\xed\x57\x30\xab\x87\xee\ +\xbe\x82\x79\xe3\xc5\xa6\xff\xba\x0a\xe6\x5d\x7b\xef\xaf\x16\x77\ +\xde\xcb\x8a\x62\xe7\x94\xa4\xcc\xcb\xdb\xb5\x9e\xc8\xd7\x51\x40\ +\xb9\xef\x6c\xda\xf2\xce\x28\xf9\xdd\xfa\x5f\x4b\x31\x4b\xc3\x9c\ +\x90\xf1\xe7\xb0\x92\x0b\x73\xfe\x12\x18\xb4\xa1\x48\x56\x8a\x4a\ +\x5d\x6d\xf5\xf3\x30\x92\x63\x72\x7c\x9e\xc6\xf2\xd6\x95\xe3\xc1\ +\x19\xf8\x02\x0f\xc1\x9e\xc4\x7b\x9e\xff\xd0\xa8\xf7\xbf\xf4\x32\ +\x73\x87\x26\xf4\x37\xda\xb7\x6c\x5d\xbd\xf9\xb4\x16\x1b\xbb\x36\ +\x4d\x63\x49\xad\xc7\x4b\x2c\xcc\xf6\x49\x97\xa9\x21\x47\xcd\x7e\ +\xe0\xac\xaf\x0e\xf1\xbe\x9a\x99\xdb\x91\x7e\x80\x1a\x6e\x8e\x06\ +\x21\xef\x09\x7e\xb7\x84\xa2\x2f\x44\xda\x21\xf5\xee\x0f\x8d\xd3\ +\xd4\x66\x5a\x83\xcf\x2c\x19\xf5\x69\x9b\x87\x1c\x88\xd3\x2e\xc5\ +\x34\xb2\x7b\xbd\x0d\x43\xf1\x42\x38\xf6\x37\x92\x5e\x1b\xe1\x37\ +\xc7\xad\x3b\xd7\xcc\xa5\x37\x50\x5f\xc3\x14\xd9\x84\x4b\x81\x72\ +\x1b\xc4\xda\xd4\x32\x01\x8b\x60\x3e\x6e\xd2\x08\xb5\x1e\xba\x1f\ +\x31\x59\xf2\xd6\x2e\xe4\x69\x5a\xa0\xa7\x9b\xae\x18\x05\x0b\x8b\ +\xa5\x2b\x7e\xb9\x7a\xf3\xf8\xe9\x8a\x4c\x47\x9f\x4b\xba\x62\xac\ +\x22\xf8\x9b\x4f\x57\x2c\x61\x6e\x4f\x57\x37\xb7\x33\xea\xe8\x28\ +\x18\x4f\x45\x5e\x9c\x5c\xdb\xbb\xe7\xb2\x92\xb9\x8d\x54\x4e\xb8\ +\xb4\x0a\x82\xde\xb0\xb0\x95\x2c\xac\xf0\xa8\x23\xb6\xb7\x65\x66\ +\x2f\xf2\x39\x27\xbc\x97\xe2\x5e\x9a\x71\x9a\x66\xbb\xca\x52\x4d\ +\x59\x96\xe9\x8b\x9b\x63\x2c\xc7\x34\x69\xb7\x96\xc8\x2c\x8d\x27\ +\x95\x5c\x3e\xe9\x78\x22\x9f\x94\xa6\x92\x4e\x27\x52\x49\x63\x59\ +\xa4\x22\x2b\x63\xb9\xa3\x4c\x48\x39\x49\xe6\xc4\xe8\x8c\x53\x1a\ +\x55\x3b\x63\x73\x59\x39\xaf\x10\x6b\x26\x2e\x2b\xf5\x7a\xa5\x8a\ +\x23\x7b\x7c\x10\xd1\x5e\x27\x89\x3d\x14\x54\xf3\xaf\xcf\xe6\xf9\ +\x46\x8a\xe8\x13\x8f\x58\x4b\x24\xd2\x83\x03\xbc\x30\x0a\x7f\xdd\ +\x24\x51\x5a\x44\x96\xa2\x32\x9c\xe4\x5b\x2c\x97\xb9\x5f\x40\xc9\ +\x7d\xd7\x27\xfb\xd1\x13\xdc\x8f\x81\x66\xe0\xf2\x34\xdd\x0f\x9e\ +\xc0\x6e\xb8\x86\x03\x2b\x2a\xea\xc3\x92\x61\x86\x2a\x4e\x60\x7f\ +\x01\xe5\x28\x40\xc1\x99\x0e\x23\x80\x22\xdd\xd9\x8c\x14\xbe\x78\ +\x54\xca\xcc\x24\xc7\xd3\xb8\xc2\xd9\x2c\xe7\x6a\x7d\xb6\xdc\x17\ +\x36\xcb\xe5\x33\xea\xdc\x0a\x2b\xa9\x8d\x2f\xe7\x25\xeb\xdd\x0e\ +\x33\x2e\x72\x9f\xc2\xcc\xa8\x77\x7d\x66\xc6\x1b\xcc\xef\xf2\x48\ +\xa6\x8c\x0e\x28\xa3\x2d\x9e\x88\x63\x66\x74\x00\x9f\x1b\xd5\x84\ +\x37\x0f\xfe\x01\xbd\x89\x17\xfc\ \x00\x00\x0f\x9f\ \x00\ \x00\xa2\x2c\x78\x9c\xed\x1d\x6b\x6f\xdb\x38\xf2\x7b\x7e\x05\x91\ @@ -37791,61 +37797,61 @@ qt_resource_struct = "\ \x00\x00\x00\x64\x00\x00\x00\x00\x00\x01\x00\x00\x01\x64\ \x00\x00\x00\x96\x00\x00\x00\x00\x00\x01\x00\x00\x04\xc4\ \x00\x00\x00\x7c\x00\x00\x00\x00\x00\x01\x00\x00\x03\x12\ -\x00\x00\x06\x02\x00\x01\x00\x00\x00\x01\x00\x07\x6b\xbd\ -\x00\x00\x03\xb0\x00\x00\x00\x00\x00\x01\x00\x06\xbd\x6a\ -\x00\x00\x08\x38\x00\x01\x00\x00\x00\x01\x00\x08\x1f\x87\ -\x00\x00\x0a\x7e\x00\x01\x00\x00\x00\x01\x00\x08\xde\x6f\ -\x00\x00\x04\xba\x00\x01\x00\x00\x00\x01\x00\x07\x08\x51\ -\x00\x00\x06\x4a\x00\x00\x00\x00\x00\x01\x00\x07\x89\x07\ -\x00\x00\x07\x5e\x00\x01\x00\x00\x00\x01\x00\x07\xe1\xa5\ -\x00\x00\x06\xbe\x00\x00\x00\x00\x00\x01\x00\x07\xb2\xd6\ -\x00\x00\x08\xd2\x00\x01\x00\x00\x00\x01\x00\x08\x59\x16\ -\x00\x00\x0a\xce\x00\x01\x00\x00\x00\x01\x00\x08\xfa\x7f\ -\x00\x00\x03\xf6\x00\x01\x00\x00\x00\x01\x00\x06\xd6\x8c\ -\x00\x00\x07\x84\x00\x01\x00\x00\x00\x01\x00\x07\xe7\x69\ -\x00\x00\x06\x24\x00\x00\x00\x00\x00\x01\x00\x07\x76\x71\ -\x00\x00\x04\x1a\x00\x00\x00\x00\x00\x01\x00\x06\xdc\x0b\ -\x00\x00\x06\x92\x00\x01\x00\x00\x00\x01\x00\x07\xa1\xcc\ -\x00\x00\x03\xd2\x00\x01\x00\x00\x00\x01\x00\x06\xcc\x20\ -\x00\x00\x0a\x08\x00\x00\x00\x00\x00\x01\x00\x08\xc0\xb5\ -\x00\x00\x03\x30\x00\x01\x00\x00\x00\x01\x00\x06\x97\xb4\ -\x00\x00\x05\x0a\x00\x01\x00\x00\x00\x01\x00\x07\x23\x70\ -\x00\x00\x09\xc0\x00\x01\x00\x00\x00\x01\x00\x08\xac\xbf\ -\x00\x00\x09\xe2\x00\x01\x00\x00\x00\x01\x00\x08\xb7\x21\ -\x00\x00\x04\xe8\x00\x00\x00\x00\x00\x01\x00\x07\x11\x57\ -\x00\x00\x02\xfe\x00\x01\x00\x00\x00\x01\x00\x06\x8f\xfb\ -\x00\x00\x07\xee\x00\x01\x00\x00\x00\x01\x00\x08\x08\x5d\ -\x00\x00\x09\x2c\x00\x00\x00\x00\x00\x01\x00\x08\x69\x5e\ -\x00\x00\x05\x5e\x00\x01\x00\x00\x00\x01\x00\x07\x34\xe0\ -\x00\x00\x09\x50\x00\x00\x00\x00\x00\x01\x00\x08\x80\x11\ -\x00\x00\x07\x18\x00\x00\x00\x00\x00\x01\x00\x07\xc9\x78\ -\x00\x00\x04\x6c\x00\x01\x00\x00\x00\x01\x00\x06\xf7\x73\ -\x00\x00\x0a\x9e\x00\x00\x00\x00\x00\x01\x00\x08\xe9\x09\ -\x00\x00\x05\xb8\x00\x00\x00\x00\x00\x01\x00\x07\x4c\x1f\ -\x00\x00\x03\x5c\x00\x00\x00\x00\x00\x01\x00\x06\x9f\xbb\ -\x00\x00\x0a\xfe\x00\x00\x00\x00\x00\x01\x00\x09\x06\x58\ -\x00\x00\x09\x98\x00\x00\x00\x00\x00\x01\x00\x08\x9d\x98\ -\x00\x00\x03\x80\x00\x01\x00\x00\x00\x01\x00\x06\xb4\xdb\ -\x00\x00\x08\x5a\x00\x01\x00\x00\x00\x01\x00\x08\x28\x30\ -\x00\x00\x0a\x2e\x00\x00\x00\x00\x00\x01\x00\x08\xc9\x42\ -\x00\x00\x05\xe0\x00\x01\x00\x00\x00\x01\x00\x07\x5e\x5e\ -\x00\x00\x06\xf0\x00\x01\x00\x00\x00\x01\x00\x07\xbf\xc7\ -\x00\x00\x08\xb0\x00\x00\x00\x00\x00\x01\x00\x08\x44\x85\ -\x00\x00\x04\x90\x00\x01\x00\x00\x00\x01\x00\x06\xfe\x10\ -\x00\x00\x07\x3e\x00\x01\x00\x00\x00\x01\x00\x07\xdb\x30\ -\x00\x00\x05\x3e\x00\x01\x00\x00\x00\x01\x00\x07\x2f\x61\ -\x00\x00\x08\xfc\x00\x01\x00\x00\x00\x01\x00\x08\x5f\x8b\ -\x00\x00\x07\xc6\x00\x01\x00\x00\x00\x01\x00\x07\xfc\xeb\ -\x00\x00\x08\x10\x00\x01\x00\x00\x00\x01\x00\x08\x0f\xb1\ -\x00\x00\x0a\x54\x00\x01\x00\x00\x00\x01\x00\x08\xd3\xed\ -\x00\x00\x09\x74\x00\x01\x00\x00\x00\x01\x00\x08\x92\xe8\ -\x00\x00\x04\x3c\x00\x01\x00\x00\x00\x01\x00\x06\xef\x2a\ -\x00\x00\x07\xa6\x00\x00\x00\x00\x00\x01\x00\x07\xed\x19\ -\x00\x00\x05\x8c\x00\x00\x00\x00\x00\x01\x00\x07\x3c\xc5\ -\x00\x00\x06\x72\x00\x01\x00\x00\x00\x01\x00\x07\x98\x58\ -\x00\x00\x08\x7e\x00\x00\x00\x00\x00\x01\x00\x08\x2f\x81\ +\x00\x00\x06\x02\x00\x01\x00\x00\x00\x01\x00\x07\x6c\x16\ +\x00\x00\x03\xb0\x00\x00\x00\x00\x00\x01\x00\x06\xbd\xc3\ +\x00\x00\x08\x38\x00\x01\x00\x00\x00\x01\x00\x08\x1f\xe0\ +\x00\x00\x0a\x7e\x00\x01\x00\x00\x00\x01\x00\x08\xde\xc8\ +\x00\x00\x04\xba\x00\x01\x00\x00\x00\x01\x00\x07\x08\xaa\ +\x00\x00\x06\x4a\x00\x00\x00\x00\x00\x01\x00\x07\x89\x60\ +\x00\x00\x07\x5e\x00\x01\x00\x00\x00\x01\x00\x07\xe1\xfe\ +\x00\x00\x06\xbe\x00\x00\x00\x00\x00\x01\x00\x07\xb3\x2f\ +\x00\x00\x08\xd2\x00\x01\x00\x00\x00\x01\x00\x08\x59\x6f\ +\x00\x00\x0a\xce\x00\x01\x00\x00\x00\x01\x00\x08\xfa\xd8\ +\x00\x00\x03\xf6\x00\x01\x00\x00\x00\x01\x00\x06\xd6\xe5\ +\x00\x00\x07\x84\x00\x01\x00\x00\x00\x01\x00\x07\xe7\xc2\ +\x00\x00\x06\x24\x00\x00\x00\x00\x00\x01\x00\x07\x76\xca\ +\x00\x00\x04\x1a\x00\x00\x00\x00\x00\x01\x00\x06\xdc\x64\ +\x00\x00\x06\x92\x00\x01\x00\x00\x00\x01\x00\x07\xa2\x25\ +\x00\x00\x03\xd2\x00\x01\x00\x00\x00\x01\x00\x06\xcc\x79\ +\x00\x00\x0a\x08\x00\x00\x00\x00\x00\x01\x00\x08\xc1\x0e\ +\x00\x00\x03\x30\x00\x01\x00\x00\x00\x01\x00\x06\x98\x0d\ +\x00\x00\x05\x0a\x00\x01\x00\x00\x00\x01\x00\x07\x23\xc9\ +\x00\x00\x09\xc0\x00\x01\x00\x00\x00\x01\x00\x08\xad\x18\ +\x00\x00\x09\xe2\x00\x01\x00\x00\x00\x01\x00\x08\xb7\x7a\ +\x00\x00\x04\xe8\x00\x00\x00\x00\x00\x01\x00\x07\x11\xb0\ +\x00\x00\x02\xfe\x00\x01\x00\x00\x00\x01\x00\x06\x90\x54\ +\x00\x00\x07\xee\x00\x01\x00\x00\x00\x01\x00\x08\x08\xb6\ +\x00\x00\x09\x2c\x00\x00\x00\x00\x00\x01\x00\x08\x69\xb7\ +\x00\x00\x05\x5e\x00\x01\x00\x00\x00\x01\x00\x07\x35\x39\ +\x00\x00\x09\x50\x00\x00\x00\x00\x00\x01\x00\x08\x80\x6a\ +\x00\x00\x07\x18\x00\x00\x00\x00\x00\x01\x00\x07\xc9\xd1\ +\x00\x00\x04\x6c\x00\x01\x00\x00\x00\x01\x00\x06\xf7\xcc\ +\x00\x00\x0a\x9e\x00\x00\x00\x00\x00\x01\x00\x08\xe9\x62\ +\x00\x00\x05\xb8\x00\x00\x00\x00\x00\x01\x00\x07\x4c\x78\ +\x00\x00\x03\x5c\x00\x00\x00\x00\x00\x01\x00\x06\xa0\x14\ +\x00\x00\x0a\xfe\x00\x00\x00\x00\x00\x01\x00\x09\x06\xb1\ +\x00\x00\x09\x98\x00\x00\x00\x00\x00\x01\x00\x08\x9d\xf1\ +\x00\x00\x03\x80\x00\x01\x00\x00\x00\x01\x00\x06\xb5\x34\ +\x00\x00\x08\x5a\x00\x01\x00\x00\x00\x01\x00\x08\x28\x89\ +\x00\x00\x0a\x2e\x00\x00\x00\x00\x00\x01\x00\x08\xc9\x9b\ +\x00\x00\x05\xe0\x00\x01\x00\x00\x00\x01\x00\x07\x5e\xb7\ +\x00\x00\x06\xf0\x00\x01\x00\x00\x00\x01\x00\x07\xc0\x20\ +\x00\x00\x08\xb0\x00\x00\x00\x00\x00\x01\x00\x08\x44\xde\ +\x00\x00\x04\x90\x00\x01\x00\x00\x00\x01\x00\x06\xfe\x69\ +\x00\x00\x07\x3e\x00\x01\x00\x00\x00\x01\x00\x07\xdb\x89\ +\x00\x00\x05\x3e\x00\x01\x00\x00\x00\x01\x00\x07\x2f\xba\ +\x00\x00\x08\xfc\x00\x01\x00\x00\x00\x01\x00\x08\x5f\xe4\ +\x00\x00\x07\xc6\x00\x01\x00\x00\x00\x01\x00\x07\xfd\x44\ +\x00\x00\x08\x10\x00\x01\x00\x00\x00\x01\x00\x08\x10\x0a\ +\x00\x00\x0a\x54\x00\x01\x00\x00\x00\x01\x00\x08\xd4\x46\ +\x00\x00\x09\x74\x00\x01\x00\x00\x00\x01\x00\x08\x93\x41\ +\x00\x00\x04\x3c\x00\x01\x00\x00\x00\x01\x00\x06\xef\x83\ +\x00\x00\x07\xa6\x00\x00\x00\x00\x00\x01\x00\x07\xed\x72\ +\x00\x00\x05\x8c\x00\x00\x00\x00\x00\x01\x00\x07\x3d\x1e\ +\x00\x00\x06\x72\x00\x01\x00\x00\x00\x01\x00\x07\x98\xb1\ +\x00\x00\x08\x7e\x00\x00\x00\x00\x00\x01\x00\x08\x2f\xda\ \x00\x00\x02\xaa\x00\x01\x00\x00\x00\x01\x00\x06\x77\x44\ -\x00\x00\x02\xd6\x00\x01\x00\x00\x00\x01\x00\x06\x80\x58\ +\x00\x00\x02\xd6\x00\x01\x00\x00\x00\x01\x00\x06\x80\xb1\ " def qInitResources(): diff --git a/src/Mod/Draft/Resources/ui/userprefs-import.ui b/src/Mod/Draft/Resources/ui/userprefs-import.ui index 09d5ee1c2..a14084d3b 100755 --- a/src/Mod/Draft/Resources/ui/userprefs-import.ui +++ b/src/Mod/Draft/Resources/ui/userprefs-import.ui @@ -320,6 +320,26 @@ If color mapping is choosed, you must choose a color mapping file containing a t + + + + + + If this is checked, when polylines have a width defined, they will be rendered as closed wires with the correct width + + + Render polylines with width + + + renderPolylineWidth + + + Mod/Draft + + + + + diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index f71e10166..ba8fa2909 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -202,6 +202,7 @@ class fcformat: self.makeBlocks = params.GetBool("groupLayers") self.stdSize = params.GetBool("dxfStdSize") self.importDxfHatches = params.GetBool("importDxfHatches") + self.renderPolylineWidth = params.GetBool("renderPolylineWidth") bparams = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View") if self.paramstyle > 1: @@ -403,7 +404,21 @@ def drawPolyline(polyline,shapemode=False,num=None): warn(polyline,num) if edges: try: - if (fmt.paramstyle >= 4) and (not curves) and (not shapemode): + width = rawValue(polyline,43) + if width and fmt.renderPolylineWidth: + w = Part.Wire(edges) + w1 = w.makeOffset(width/2) + if polyline.closed: + w2 = w.makeOffset(-width/2) + w1 = Part.Face(w1) + w2 = Part.Face(w2) + if w1.BoundBox.DiagonalLength > w2.BoundBox.DiagonalLength: + return w1.cut(w2) + else: + return w2.cut(w1) + else: + return Part.Face(w1) + elif (fmt.paramstyle >= 4) and (not curves) and (not shapemode): ob = Draft.makeWire(verts) ob.Closed = polyline.closed return ob From 7e028e94704da6a216f8e328a1b432430e46ec84 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Tue, 22 May 2012 17:29:50 -0300 Subject: [PATCH 30/42] Fixed 0000701 : Draft Wire naming --- src/Mod/Draft/Draft.py | 2 +- src/Mod/Draft/DraftTools.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 2e7cf692d..7b1c5dc8f 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -528,7 +528,7 @@ def makeWire(pointslist,closed=False,placement=None,face=True,support=None): print closed if placement: typecheck([(placement,FreeCAD.Placement)], "makeWire") if len(pointslist) == 2: fname = "Line" - else: fname = "Wire" + else: fname = "DWire" obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",fname) _Wire(obj) obj.Points = pointslist diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index bde2ad4a7..d137c5228 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -416,7 +416,7 @@ class Line(Creator): todo.delay(self.doc.removeObject,old) self.obj = None if (len(self.node) > 1): - self.commit(translate("draft","Create Wire"), + self.commit(translate("draft","Create DWire"), partial(Draft.makeWire,self.node,closed, face=self.ui.fillmode,support=self.support)) if self.ui: @@ -456,7 +456,7 @@ class Line(Creator): if ((point-self.node[0]).Length < Draft.tolerance()): self.undolast() self.finish(True,cont=True) - msg(translate("draft", "Wire has been closed\n")) + msg(translate("draft", "DWire has been closed\n")) def undolast(self): "undoes last line segment" @@ -523,10 +523,10 @@ class Wire(Line): def GetResources(self): return {'Pixmap' : 'Draft_Wire', 'Accel' : "W, I", - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Wire", "Wire"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Wire", "Creates a multiple-point wire. CTRL to snap, SHIFT to constrain")} + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Wire", "DWire"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Wire", "Creates a multiple-point DraftWire (DWire). CTRL to snap, SHIFT to constrain")} def Activated(self): - Line.Activated(self,name=str(translate("draft","Wire"))) + Line.Activated(self,name=str(translate("draft","DWire"))) class BSpline(Line): From 260d12bc9f47b047f71ddf7c03ce2cd22bd1d1d9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 23 May 2012 11:48:43 +0200 Subject: [PATCH 31/42] 0000710: merge project annoyance --- src/Gui/CommandDoc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index 02e043490..46c5f5681 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -281,7 +281,7 @@ void StdCmdMergeProjects::activated(int iMsg) { QString exe = QString::fromUtf8(App::GetApplication().getExecutableName()); QString project = QFileDialog::getOpenFileName(Gui::getMainWindow(), - QString::fromUtf8(QT_TR_NOOP("Merge project")), QString(), + QString::fromUtf8(QT_TR_NOOP("Merge project")), QDir::homePath(), QString::fromUtf8(QT_TR_NOOP("%1 document (*.fcstd)")).arg(exe)); if (!project.isEmpty()) { App::Document* doc = App::GetApplication().getActiveDocument(); From c156fc6e9c6c9b2b682393b7cd7212164720b61f Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 23 May 2012 12:07:04 +0200 Subject: [PATCH 32/42] 0000717: Version info causes crash --- src/App/ApplicationPy.cpp | 41 ++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/App/ApplicationPy.cpp b/src/App/ApplicationPy.cpp index d74b1b4a7..15781cc3d 100644 --- a/src/App/ApplicationPy.cpp +++ b/src/App/ApplicationPy.cpp @@ -383,23 +383,36 @@ PyObject* Application::sGetVersion(PyObject * /*self*/, PyObject *args,PyObject if (!PyArg_ParseTuple(args, "")) // convert args: Python->C return NULL; // NULL triggers exception - PyObject* pList = PyList_New(5); - PyObject *pItem; - pItem = PyString_FromString(Application::Config()["BuildVersionMajor"].c_str()); - PyList_SetItem(pList, 0, pItem); - pItem = PyString_FromString(Application::Config()["BuildVersionMinor"].c_str()); - PyList_SetItem(pList, 1, pItem); - pItem = PyString_FromString(Application::Config()["BuildRevision"].c_str()); - PyList_SetItem(pList, 2, pItem); - pItem = PyString_FromString(Application::Config()["BuildRepositoryURL"].c_str()); - PyList_SetItem(pList, 4, pItem); - pItem = PyString_FromString(Application::Config()["BuildCurrentDate"].c_str()); - PyList_SetItem(pList, 6, pItem); + Py::List list; + const std::map& cfg = Application::Config(); + std::map::const_iterator it; - return pList; + it = cfg.find("BuildVersionMajor"); + list.append(Py::String(it != cfg.end() ? it->second : "")); + + it = cfg.find("BuildVersionMinor"); + list.append(Py::String(it != cfg.end() ? it->second : "")); + + it = cfg.find("BuildRevision"); + list.append(Py::String(it != cfg.end() ? it->second : "")); + + it = cfg.find("BuildRepositoryURL"); + list.append(Py::String(it != cfg.end() ? it->second : "")); + + it = cfg.find("BuildRevisionDate"); + list.append(Py::String(it != cfg.end() ? it->second : "")); + + it = cfg.find("BuildRevisionBranch"); + if (it != cfg.end()) + list.append(Py::String(it->second)); + + it = cfg.find("BuildRevisionHash"); + if (it != cfg.end()) + list.append(Py::String(it->second)); + + return Py::new_reference_to(list); } - PyObject* Application::sAddImportType(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/) { char *psKey,*psMod; From 6774f160beb26022f7940b2e585bddfe4bb7dacb Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 23 May 2012 15:03:19 +0200 Subject: [PATCH 33/42] 0000716: src/Tools/PyTools.c: strange assignment and a memory leak --- src/Base/PyTools.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Base/PyTools.c b/src/Base/PyTools.c index 2346f80cc..d204ae72d 100644 --- a/src/Base/PyTools.c +++ b/src/Base/PyTools.c @@ -377,8 +377,10 @@ const char *PP_Init(const char *modname) { //#ifdef FC_OS_LINUX /* cannot convert `const char *' to `char *' in assignment */ if (modname!=NULL) return modname; { /* we assume here that the caller frees allocated memory */ - char* __main__=(char *)malloc(sizeof("__main__")); - return __main__="__main__"; + // #0000716: strange assignment and a memory leak + return "__main__"; + //char* __main__=(char *)malloc(sizeof("__main__")); + //return __main__="__main__"; } //#else // return modname == NULL ? "__main__" : modname; /* default to '__main__' */ From 432a460fda32347b3884135f9ba5904e44e375d9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 23 May 2012 15:03:48 +0200 Subject: [PATCH 34/42] Expose merge project function to python --- src/Gui/CommandDoc.cpp | 3 --- src/Gui/DocumentPy.xml | 5 +++++ src/Gui/DocumentPyImp.cpp | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index 46c5f5681..b9d0ea68b 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -294,9 +294,6 @@ void StdCmdMergeProjects::activated(int iMsg) return; } - QString dir1 = proj.absoluteDir().filePath(proj.baseName()); - QString dir2 = info.absoluteDir().filePath(info.baseName()); - Base::FileInfo fi((const char*)project.toUtf8()); Base::ifstream str(fi, std::ios::in | std::ios::binary); MergeDocuments md(doc); diff --git a/src/Gui/DocumentPy.xml b/src/Gui/DocumentPy.xml index 75ac71a54..c76e101cf 100644 --- a/src/Gui/DocumentPy.xml +++ b/src/Gui/DocumentPy.xml @@ -77,6 +77,11 @@ Send a message to all views of the document + + + + Merges this document with another project file + diff --git a/src/Gui/DocumentPyImp.cpp b/src/Gui/DocumentPyImp.cpp index 4d30e7cc5..67b66f36a 100644 --- a/src/Gui/DocumentPyImp.cpp +++ b/src/Gui/DocumentPyImp.cpp @@ -32,6 +32,7 @@ #include #include "Document.h" +#include "MergeDocuments.h" #include "ViewProviderExtern.h" // inclusion of the generated files (generated out of DocumentPy.xml) @@ -234,6 +235,22 @@ PyObject* DocumentPy::sendMsgToViews(PyObject *args) } PY_CATCH; } +PyObject* DocumentPy::mergeProject(PyObject *args) +{ + char* filename; + if (!PyArg_ParseTuple(args, "s", &filename)) // convert args: Python->C + return NULL; // NULL triggers exception + + PY_TRY { + Base::FileInfo fi(filename); + Base::ifstream str(fi, std::ios::in | std::ios::binary); + App::Document* doc = getDocumentPtr()->getDocument(); + MergeDocuments md(doc); + md.importObjects(str); + Py_Return; + } PY_CATCH; +} + Py::Object DocumentPy::getActiveObject(void) const { App::DocumentObject *object = getDocumentPtr()->getDocument()->getActiveObject(); From 6a264ac2a5b6bed5269477c8de3769bdc0893358 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 23 May 2012 16:57:36 +0200 Subject: [PATCH 35/42] Add method Document::findObject() --- src/App/Document.cpp | 15 +++++++++ src/App/Document.h | 1 + src/App/DocumentPyImp.cpp | 66 ++++++++++++++++++--------------------- 3 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 519f5d7e4..f130bb35a 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -63,6 +63,7 @@ recompute path. Also enables more complicated dependencies beyond trees. #include #include #include +#include #include "Document.h" @@ -1689,6 +1690,20 @@ std::vector Document::getObjectsOfType(const Base::Type& typeId return Objects; } +std::vector Document::findObjects(const Base::Type& typeId, const char* objname) const +{ + boost::regex rx(objname); + boost::cmatch what; + std::vector Objects; + for (std::vector::const_iterator it = d->objectArray.begin(); it != d->objectArray.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(typeId)) { + if (boost::regex_match((*it)->getNameInDocument(), what, rx)) + Objects.push_back(*it); + } + } + return Objects; +} + int Document::countObjectsOfType(const Base::Type& typeId) const { int ct=0; diff --git a/src/App/Document.h b/src/App/Document.h index dcf56d670..d1675001e 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -161,6 +161,7 @@ public: /// Returns a list of all Objects std::vector getObjects() const; std::vector getObjectsOfType(const Base::Type& typeId) const; + std::vector findObjects(const Base::Type& typeId, const char* objname) const; /// Returns an array with the correct types already. template inline std::vector getObjectsOfType() const; int countObjectsOfType(const Base::Type& typeId) const; diff --git a/src/App/DocumentPyImp.cpp b/src/App/DocumentPyImp.cpp index 3b7fdd289..6bd02f51c 100644 --- a/src/App/DocumentPyImp.cpp +++ b/src/App/DocumentPyImp.cpp @@ -290,42 +290,36 @@ PyObject* DocumentPy::findObjects(PyObject *args) char *sType="App::DocumentObject", *sName=0; if (!PyArg_ParseTuple(args, "|ss",&sType, &sName)) // convert args: Python->C return NULL; // NULL triggers exception - - Base::Type type = Base::Type::fromName(sType); - if (type == Base::Type::badType()) { - PyErr_Format(PyExc_Exception, "'%s' is not a valid type", sType); - return NULL; - } - - if (!type.isDerivedFrom(App::DocumentObject::getClassTypeId())) { - PyErr_Format(PyExc_Exception, "Type '%s' does not inherit from 'App::DocumentObject'", sType); - return NULL; - } - - std::vector res; - std::vector objs = getDocumentPtr()->getObjectsOfType(type); - - if (sName) { - try { - boost::regex rx(sName); - boost::cmatch what; - for (std::vector::const_iterator It = objs.begin();It != objs.end();++It) { - if (boost::regex_match((*It)->getNameInDocument(), what, rx)) - res.push_back(*It); - } - } - catch (const boost::regex_error& e) { - PyErr_SetString(PyExc_RuntimeError, e.what()); - return 0; - } - } - else { - res = objs; - } - - Py_ssize_t index=0; - PyObject* list = PyList_New((Py_ssize_t)res.size()); - for (std::vector::const_iterator It = res.begin();It != res.end();++It, index++) + + Base::Type type = Base::Type::fromName(sType); + if (type == Base::Type::badType()) { + PyErr_Format(PyExc_Exception, "'%s' is not a valid type", sType); + return NULL; + } + + if (!type.isDerivedFrom(App::DocumentObject::getClassTypeId())) { + PyErr_Format(PyExc_Exception, "Type '%s' does not inherit from 'App::DocumentObject'", sType); + return NULL; + } + + std::vector res; + + if (sName) { + try { + res = getDocumentPtr()->findObjects(type, sName); + } + catch (const boost::regex_error& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return 0; + } + } + else { + res = getDocumentPtr()->getObjectsOfType(type); + } + + Py_ssize_t index=0; + PyObject* list = PyList_New((Py_ssize_t)res.size()); + for (std::vector::const_iterator It = res.begin();It != res.end();++It, index++) PyList_SetItem(list, index, (*It)->getPyObject()); return list; } From c7c874a705e4b69b045befeb1c222aeb32368280 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 23 May 2012 18:03:25 -0300 Subject: [PATCH 36/42] Small GUI adjustments in Draft --- src/Mod/Draft/DraftGui.py | 15 ++++++++++++++- src/Mod/Draft/DraftTools.py | 5 ++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 752abb76b..13517f478 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -523,13 +523,24 @@ class DraftToolBar: self.xValue.setEnabled(True) self.yValue.setEnabled(True) self.isRelative.show() + self.undoButton.show() + self.continueCmd.show() + + def wireUi(self,title=None): + if title: + self.pointUi(title) + else: + self.pointUi(translate("draft", "DWire")) + self.xValue.setEnabled(True) + self.yValue.setEnabled(True) + self.isRelative.show() self.hasFill.show() self.finishButton.show() self.closeButton.show() self.wipeButton.show() self.undoButton.show() self.continueCmd.show() - + def circleUi(self): self.pointUi(translate("draft", "Circle")) self.continueCmd.show() @@ -935,6 +946,8 @@ class DraftToolBar: if self.finishButton.isVisible(): self.finish() spec = True + elif txt.endsWith("t"): + self.continueCmd.setChecked(not self.continueCmd.isChecked()) elif txt.endsWith("w"): self.wipeLine() elif txt.endsWith("s"): diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index d137c5228..885e781c6 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -400,7 +400,10 @@ class Line(Creator): Creator.Activated(self,name) if self.doc: self.obj = None - self.ui.lineUi(name) + if self.isWire: + self.ui.wireUi(name) + else: + self.ui.lineUi(name) self.linetrack = lineTracker() self.constraintrack = lineTracker(dotted=True) self.obj=self.doc.addObject("Part::Feature",self.featureName) From 50bbf527dd79d15d8b1596ab1678bfe40eb1aece Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 25 May 2012 12:12:30 +0200 Subject: [PATCH 37/42] Add parameter to keep trailing digits in object name of copy, other little fix --- src/App/Document.cpp | 13 ++++++++----- src/App/Document.h | 4 ++-- src/App/DocumentPyImp.cpp | 6 +++--- src/Mod/Part/Gui/Command.cpp | 2 -- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index f130bb35a..61d1b7921 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -1484,15 +1484,18 @@ void Document::breakDependency(DocumentObject* pcObject, bool clear) } DocumentObject* Document::_copyObject(DocumentObject* obj, std::map& copy_map, bool recursive) + DocumentObject*>& copy_map, bool recursive, + bool keepdigitsatend) { if (!obj) return 0; // remove number from end to avoid lengthy names std::string objname = obj->getNameInDocument(); + if (!keepdigitsatend) { size_t lastpos = objname.length()-1; while (objname[lastpos] >= 48 && objname[lastpos] <= 57) lastpos--; objname = objname.substr(0, lastpos+1); + } DocumentObject* copy = addObject(obj->getTypeId().getName(),objname.c_str()); if (!copy) return 0; copy->addDynamicProperties(obj); @@ -1512,7 +1515,7 @@ DocumentObject* Document::_copyObject(DocumentObject* obj, std::map(it->second)->setValue(pt->second); } else if (recursive) { - DocumentObject* link_copy = _copyObject(link, copy_map, recursive); + DocumentObject* link_copy = _copyObject(link, copy_map, recursive, keepdigitsatend); copy_map[link] = link_copy; static_cast(it->second)->setValue(link_copy); } @@ -1531,7 +1534,7 @@ DocumentObject* Document::_copyObject(DocumentObject* obj, std::mapsecond); } else { - links_copy.push_back(_copyObject(*jt, copy_map, recursive)); + links_copy.push_back(_copyObject(*jt, copy_map, recursive, keepdigitsatend)); copy_map[*jt] = links_copy.back(); } } @@ -1561,10 +1564,10 @@ DocumentObject* Document::_copyObject(DocumentObject* obj, std::map copy_map; - DocumentObject* copy = _copyObject(obj, copy_map, recursive); + DocumentObject* copy = _copyObject(obj, copy_map, recursive, keepdigitsatend); return copy; } diff --git a/src/App/Document.h b/src/App/Document.h index d1675001e..38b247a20 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -140,7 +140,7 @@ public: * are copied as well. By default \a recursive is false. * Returns the copy of the object or 0 if the creation failed. */ - DocumentObject* copyObject(DocumentObject* obj, bool recursive=false); + DocumentObject* copyObject(DocumentObject* obj, bool recursive=false, bool keepdigitsatend=false); /** Move an object from another document to this document * If \a recursive is true then all objects this object depends on * are moved as well. By default \a recursive is false. @@ -261,7 +261,7 @@ protected: void _remObject(DocumentObject* pcObject); void _addObject(DocumentObject* pcObject, const char* pObjectName); DocumentObject* _copyObject(DocumentObject* obj, std::map&, bool recursive=false); + DocumentObject*>&, bool recursive=false, bool keepdigitsatend=false); /// checks if a valid transaction is open void _checkTransaction(void); void breakDependency(DocumentObject* pcObject, bool clear); diff --git a/src/App/DocumentPyImp.cpp b/src/App/DocumentPyImp.cpp index 6bd02f51c..64b04d8b9 100644 --- a/src/App/DocumentPyImp.cpp +++ b/src/App/DocumentPyImp.cpp @@ -163,12 +163,12 @@ PyObject* DocumentPy::removeObject(PyObject *args) PyObject* DocumentPy::copyObject(PyObject *args) { - PyObject *obj, *rec=0; - if (!PyArg_ParseTuple(args, "O!|O!",&(DocumentObjectPy::Type),&obj,&PyBool_Type,&rec)) + PyObject *obj, *rec=0, *keep=0; + if (!PyArg_ParseTuple(args, "O!|O!O!",&(DocumentObjectPy::Type),&obj,&PyBool_Type,&rec,&PyBool_Type,&keep)) return NULL; // NULL triggers exception DocumentObjectPy* docObj = static_cast(obj); - DocumentObject* copy = getDocumentPtr()->copyObject(docObj->getDocumentObjectPtr(), rec==Py_True); + DocumentObject* copy = getDocumentPtr()->copyObject(docObj->getDocumentObjectPtr(), rec==Py_True, keep==Py_True); if (copy) { return copy->getPyObject(); } diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index 1b616525a..33cd008ee 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -511,7 +511,6 @@ void CmdPartExport::activated(int iMsg) if (!fn.isEmpty()) { App::Document* pDoc = getDocument(); if (!pDoc) return; // no document - openCommand("Import Part"); QString ext = QFileInfo(fn).suffix().toLower(); if (ext == QLatin1String("step") || ext == QLatin1String("stp") || @@ -522,7 +521,6 @@ void CmdPartExport::activated(int iMsg) else { Gui::Application::Instance->exportTo((const char*)fn.toUtf8(),pDoc->getName(),"Part"); } - commitCommand(); } } From b7965052a3535ecc25c70c84c805f8754675f258 Mon Sep 17 00:00:00 2001 From: logari81 Date: Fri, 25 May 2012 18:04:29 +0200 Subject: [PATCH 38/42] Sketcher: skip the latest added one of the detected redundant constraints --- src/Mod/Sketcher/App/freegcs/GCS.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/App/freegcs/GCS.cpp b/src/Mod/Sketcher/App/freegcs/GCS.cpp index aa850c9a2..7b9455ddc 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/freegcs/GCS.cpp @@ -1397,7 +1397,9 @@ int System::diagnose() Constraint *mostPopular = NULL; for (std::map< Constraint *, SET_I >::const_iterator it=conflictingMap.begin(); it != conflictingMap.end(); it++) { - if (it->second.size() >= maxPopularity) { + if (it->second.size() > maxPopularity || + (it->second.size() == maxPopularity && mostPopular && + it->first->getTag() > mostPopular->getTag())) { mostPopular = it->first; maxPopularity = it->second.size(); } From 7cbb16f2e840eac3e65a696d3a2a6e121c07df9e Mon Sep 17 00:00:00 2001 From: logari81 Date: Fri, 25 May 2012 18:18:51 +0200 Subject: [PATCH 39/42] Sketcher: include coincident constraints in the sketch diagnosis --- src/Mod/Sketcher/App/Sketch.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 59b6410a7..1898955f3 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -743,10 +743,7 @@ int Sketch::addPointCoincidentConstraint(int geoId1, PointPos pos1, int geoId2, GCS::Point &p1 = Points[pointId1]; GCS::Point &p2 = Points[pointId2]; int tag = ++ConstraintsCounter; - // trick: we do not tag coincidence constraints in order to exclude - // them from the diagnosing of conflicts - //GCSsys.addConstraintP2PCoincident(p1, p2, tag); - GCSsys.addConstraintP2PCoincident(p1, p2); + GCSsys.addConstraintP2PCoincident(p1, p2, tag); return ConstraintsCounter; } return -1; From 1e60d45dd4740707ca2d3ed60d5e51fd7d161faf Mon Sep 17 00:00:00 2001 From: logari81 Date: Sat, 26 May 2012 19:23:38 +0200 Subject: [PATCH 40/42] Sketcher: fix minor issue in sketch diagnostics --- src/Mod/Sketcher/App/freegcs/GCS.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/App/freegcs/GCS.cpp b/src/Mod/Sketcher/App/freegcs/GCS.cpp index 7b9455ddc..ffab4c579 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/freegcs/GCS.cpp @@ -1425,7 +1425,8 @@ int System::diagnose() subSysTmp->applySolution(); for (std::set::const_iterator constr=skipped.begin(); constr != skipped.end(); constr++) { - if ((*constr)->error() < XconvergenceFine) + double err = (*constr)->error(); + if (err * err < XconvergenceFine) redundant.insert(*constr); } resetToReference(); From d92f627a8d206fbf76aaf948e97293346333b012 Mon Sep 17 00:00:00 2001 From: logari81 Date: Sat, 26 May 2012 20:02:57 +0200 Subject: [PATCH 41/42] Sketcher: simplify sketch solver messages --- src/Mod/Sketcher/App/SketchObject.cpp | 14 ++++-- src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp | 44 +++-------------- src/Mod/Sketcher/Gui/TaskSketcherMessages.h | 4 +- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 48 ++++++++++--------- src/Mod/Sketcher/Gui/ViewProviderSketch.h | 4 +- 5 files changed, 46 insertions(+), 68 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 8d75c5f24..c09cd6963 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -1393,10 +1393,14 @@ void SketchObject::appendConflictMsg(const std::vector &conflicting, std::s if (msg.length() > 0) ss << msg; if (conflicting.size() > 0) { - ss << "Please remove at least one of the constraints (" << conflicting[0]; + if (conflicting.size() == 1) + ss << "Please remove the following constraint:\n"; + else + ss << "Please remove at least one of the following constraints:\n"; + ss << conflicting[0]; for (unsigned int i=1; i < conflicting.size(); i++) ss << ", " << conflicting[i]; - ss << ")\n"; + ss << "\n"; } msg = ss.str(); } @@ -1407,7 +1411,11 @@ void SketchObject::appendRedundantMsg(const std::vector &redundant, std::st if (msg.length() > 0) ss << msg; if (redundant.size() > 0) { - ss << "The following constraints were identified as redundant and should be removed:\n" << redundant[0]; + if (redundant.size() == 1) + ss << "Please remove the following redundant constraint:\n"; + else + ss << "Please remove the following redundant constraints:\n"; + ss << redundant[0]; for (unsigned int i=1; i < redundant.size(); i++) ss << ", " << redundant[i]; ss << "\n"; diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp index 5ef6c65fb..dc006117a 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp @@ -54,8 +54,8 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView) this->groupLayout()->addWidget(proxy); - connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this,_1,_2,_3)); - connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this,_1,_2)); + connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this,_1)); + connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this,_1)); } TaskSketcherMessages::~TaskSketcherMessages() @@ -65,46 +65,14 @@ TaskSketcherMessages::~TaskSketcherMessages() delete ui; } -void TaskSketcherMessages::slotSetUp(int type, int dofs, const std::string &msg) +void TaskSketcherMessages::slotSetUp(QString msg) { - switch(type){ - case -1: - ui->labelConstrainStatus->setText(QString::fromLatin1("Empty sketch")); - break; - case 0: - ui->labelConstrainStatus->setText(QString::fromLatin1("Fully constrained sketch ")); - break; - case 1: - if (dofs==1) - ui->labelConstrainStatus->setText(QString::fromLatin1("Under-constrained sketch with 1 degree of freedom")); - else - ui->labelConstrainStatus->setText(QString::fromLatin1("Under-constrained sketch with %1 degrees of freedom").arg(dofs)); - break; - case 2: - ui->labelConstrainStatus->setText(QString::fromLatin1("Sketch contains conflicting constraints
%1
").arg(QString::fromStdString(msg))); - break; - case 3: - ui->labelConstrainStatus->setText(QString::fromLatin1("Over-constrained sketch
%1
").arg(QString::fromStdString(msg))); - break; - case 4: - ui->labelConstrainStatus->setText(QString::fromLatin1("Sketch contains redundant constraints
%1").arg(QString::fromStdString(msg))); - break; - } + ui->labelConstrainStatus->setText(msg); } -void TaskSketcherMessages::slotSolved(int type, float time) +void TaskSketcherMessages::slotSolved(QString msg) { - switch(type){ - case -1: - ui->labelSolverStatus->setText(QString()); - break; - case 0: - ui->labelSolverStatus->setText(QString::fromLatin1("Solved in %1 sec").arg(time)); - break; - case 1: - ui->labelSolverStatus->setText(QString::fromLatin1("Unsolved (%1)").arg(time)); - break; - } + ui->labelSolverStatus->setText(msg); } #include "moc_TaskSketcherMessages.cpp" diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.h b/src/Mod/Sketcher/Gui/TaskSketcherMessages.h index 7cdc104a7..cdf5f907b 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.h +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.h @@ -47,8 +47,8 @@ public: TaskSketcherMessages(ViewProviderSketch *sketchView); ~TaskSketcherMessages(); - void slotSetUp(int type, int dofs, const std::string &msg); - void slotSolved(int type, float time); + void slotSetUp(QString msg); + void slotSolved(QString msg); private Q_SLOTS: diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 2239f7445..4b6cc1988 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -822,9 +822,9 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal, if (edit->ActSketch.movePoint(GeoId, PosId, vec, relative) == 0) { setPositionText(Base::Vector2D(x,y)); draw(true); - signalSolved(0, edit->ActSketch.SolveTime); + signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime)); } else { - signalSolved(1, edit->ActSketch.SolveTime); + signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime)); //Base::Console().Log("Error solving:%d\n",ret); } } @@ -835,9 +835,9 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal, if (edit->ActSketch.movePoint(edit->DragCurve, Sketcher::none, vec, relative) == 0) { setPositionText(Base::Vector2D(x,y)); draw(true); - signalSolved(0, edit->ActSketch.SolveTime); + signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime)); } else { - signalSolved(1, edit->ActSketch.SolveTime); + signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime)); } } return true; @@ -2808,46 +2808,48 @@ void ViewProviderSketch::solveSketch(void) int dofs = edit->ActSketch.setUpSketch(getSketchObject()->getCompleteGeometry(), getSketchObject()->Constraints.getValues(), getSketchObject()->getExternalGeometryCount()); - std::string msg; if (getSketchObject()->Geometry.getSize() == 0) { - signalSetUp(-1, 0, msg); - signalSolved(-1, 0); + signalSetUp(QString::fromLatin1("Empty sketch")); + signalSolved(QString()); } else if (dofs < 0) { // over-constrained sketch + std::string msg; SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); - //Base::Console().Warning("Over-constrained sketch\n%s",msg.c_str()); - signalSetUp(3, 0, msg); - signalSolved(-1, 0); + signalSetUp(QString::fromLatin1("Over-constrained sketch
%1
") + .arg(QString::fromStdString(msg))); + signalSolved(QString()); } else if (edit->ActSketch.hasConflicts()) { // conflicting constraints + std::string msg; SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); - //Base::Console().Warning("Sketch with conflicting constraints\n%s",msg.c_str()); - signalSetUp(2, dofs, msg); - signalSolved(-1, 0); + signalSetUp(QString::fromLatin1("Sketch contains conflicting constraints
%1
") + .arg(QString::fromStdString(msg))); + signalSolved(QString()); } else { if (edit->ActSketch.hasRedundancies()) { // redundant constraints + std::string msg; SketchObject::appendRedundantMsg(edit->ActSketch.getRedundant(), msg); - //Base::Console().Warning("Sketch with redundant constraints\n%s",msg.c_str()); - signalSetUp(4, dofs, msg); + signalSetUp(QString::fromLatin1("Sketch contains redundant constraints
%1
") + .arg(QString::fromStdString(msg))); } if (edit->ActSketch.solve() == 0) { // solving the sketch if (dofs == 0) { // color the sketch as fully constrained edit->FullyConstrained = true; - if (!edit->ActSketch.hasRedundancies()) { - //Base::Console().Message("Fully constrained sketch\n"); - signalSetUp(0, 0, msg); - } + if (!edit->ActSketch.hasRedundancies()) + signalSetUp(QString::fromLatin1("Fully constrained sketch ")); } else if (!edit->ActSketch.hasRedundancies()) { - //Base::Console().Message("Under-constrained sketch with %d degrees of freedom\n", dofs); - signalSetUp(1, dofs, msg); + if (dofs == 1) + signalSetUp(QString::fromLatin1("Under-constrained sketch with 1 degree of freedom")); + else + signalSetUp(QString::fromLatin1("Under-constrained sketch with %1 degrees of freedom").arg(dofs)); } - signalSolved(0, edit->ActSketch.SolveTime); + signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime)); } else { - signalSolved(1, edit->ActSketch.SolveTime); + signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime)); } } } diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index 234ede976..2c98d71eb 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -174,9 +174,9 @@ public: /// signals if the constraints list has changed boost::signal signalConstraintsChanged; /// signals if the sketch has been set up - boost::signal signalSetUp; + boost::signal signalSetUp; /// signals if the sketch has been solved - boost::signal signalSolved; + boost::signal signalSolved; protected: virtual bool setEdit(int ModNum); From 455f5a67c30d5381dc6446c86e78d42d3c827f5e Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 26 May 2012 00:29:29 +0200 Subject: [PATCH 42/42] Handle OCC exception in exportStl --- src/Mod/Part/App/TopoShapePyImp.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Mod/Part/App/TopoShapePyImp.cpp b/src/Mod/Part/App/TopoShapePyImp.cpp index 3aef9eab9..8f641a2f7 100644 --- a/src/Mod/Part/App/TopoShapePyImp.cpp +++ b/src/Mod/Part/App/TopoShapePyImp.cpp @@ -347,7 +347,12 @@ PyObject* TopoShapePy::exportStl(PyObject *args) } catch (const Base::Exception& e) { PyErr_SetString(PyExc_Exception,e.what()); - return NULL; + return 0; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; } Py_Return;