From 30a93b648bba43733cc102346371de86ff503ae3 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Fri, 12 Feb 2021 07:25:20 +0100 Subject: [PATCH 1/3] Sketcher: Coverity fix in Sketch::analyseBlockedGeometry ======================================================== Users chennes and hyarion made me aware of this covereity issue: Fixes Coverity: geoit can be end() when dereferenced https://github.com/FreeCAD/FreeCAD/pull/4429/files# When analysing the block where the dereferrencing appears, it appears that it is a left-over that no longer makes sense: - The algorithm classifies block constraints into those that are not affected by any other driving constraint and those that are affected by other driving constraints. - The offending block deals with internal aligned geometry, thus per definition has a driving internal alignment constraint, for which the previous block already set the need of post-analysis. - No matter what, the geometries, the complex one and the internal one will have at least the driving internal alignment constraint, so they cannot become "not affected by any other driving constraint". - If the geometry had a block constraint on it, it was already added for post-analysis in the previous block. If it did not have one block constraint, the fact that it is internal aligned geometry is an irrelevant consideration. Probably there was a point during development when this made sense, but with the current post-analysis, it does not appear to make sense anymore. So the block was removed. This commit adds a unit test for blocked geometry (new block constraint). --- src/Mod/Sketcher/App/Sketch.cpp | 51 +-- .../SketcherTests/TestSketcherSolver.py | 341 ++++++++++-------- 2 files changed, 199 insertions(+), 193 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 86a21cb61c..f783918c27 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -138,7 +138,9 @@ bool Sketch::analyseBlockedGeometry( const std::vector &intern std::vector &onlyblockedGeometry, std::vector &blockedGeoIds) const { - bool isSomethingBlocked = false; + // To understand this function read the documentation in Sketch.h + // It is important that "onlyblockedGeometry" ONLY identifies blocked geometry + // that is not affected by any other driving constraint bool doesBlockAffectOtherConstraints = false; int geoindex = 0; @@ -152,7 +154,7 @@ bool Sketch::analyseBlockedGeometry( const std::vector &intern // is block driving if( c->Type == Sketcher::Block && c->isDriving && c->First == geoindex) blockisDriving = true; - + // We have another driving constraint (which may be InternalAlignment) if( c->Type != Sketcher::Block && c->isDriving && (c->First == geoindex || c->Second == geoindex || c->Third == geoindex) ) blockOnly = false; @@ -161,12 +163,10 @@ bool Sketch::analyseBlockedGeometry( const std::vector &intern if(blockisDriving) { if(blockOnly) { onlyblockedGeometry[geoindex] = true; // we pre-fix this geometry - isSomethingBlocked = true; } else { // we will have to pos-analyse the first diagnose result for these geometries // in order to avoid redundant constraints - isSomethingBlocked = true; doesBlockAffectOtherConstraints = true; blockedGeoIds.push_back(geoindex); } @@ -176,39 +176,6 @@ bool Sketch::analyseBlockedGeometry( const std::vector &intern geoindex++; } - if(isSomethingBlocked) { - - // look for internal geometry linked IAs - for(auto c : constraintList) { - if(c->Type == InternalAlignment) { - - auto geoit = std::find(blockedGeoIds.begin(),blockedGeoIds.end(),c->Second); - - if(geoit != blockedGeoIds.end() || onlyblockedGeometry[c->Second]) { // internal alignment geometry found, add to list - // check if pre-fix or post-analyses - bool blockAffectedOnly = true; - - for(auto ic : constraintList) { - // there is another driving constraint - if( ic->Type != Sketcher::Block && ic->isDriving && - (ic->First == c->First || ic->Second == c->First || ic->Third == c->First)) - blockAffectedOnly = false; - } - - if(blockAffectedOnly) { - onlyblockedGeometry[c->Second] = true; // we pre-fix this geometry - } - else { - // we will have to post-analyse the first diagnose result for these geometries - // in order to avoid redundant constraints - doesBlockAffectOtherConstraints = true; - blockedGeoIds.push_back(*geoit); - } - } - } - } - } - return doesBlockAffectOtherConstraints; } @@ -247,19 +214,23 @@ int Sketch::setUpSketch(const std::vector &GeoList, Base::Console().Log("\nOnlyBlocked GeoIds:"); size_t i = 0; + bool found = false; for(; i < onlyBlockedGeometry.size(); i++) { - if(onlyBlockedGeometry[i]) + if(onlyBlockedGeometry[i]) { Base::Console().Log("\n GeoId=%d", i); + found = true; + } } - if( i == 0) + if(found) Base::Console().Log("\n None"); Base::Console().Log("\nNotOnlyBlocked GeoIds:"); i = 0; for(; i < blockedGeoIds.size(); i++) Base::Console().Log("\n GeoId=%d", blockedGeoIds[i]); - if( i == 0) + if(i == 0) Base::Console().Log("\n None"); + Base::Console().Log("\n"); #endif //DEBUG_BLOCK_CONSTRAINT addGeometry(intGeoList,onlyBlockedGeometry); diff --git a/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py b/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py index 90a0e42cf0..9b99266dbb 100644 --- a/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py +++ b/src/Mod/Sketcher/SketcherTests/TestSketcherSolver.py @@ -35,92 +35,90 @@ def CreateRectangleSketch(SketchFeature, corner, lengths): SketchFeature.addGeometry(Part.LineSegment(FreeCAD.Vector(hmin,vmin,0),FreeCAD.Vector(hmin,vmax,0))) # add the rectangular constraints - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',i+0,2,i+1,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',i+1,2,i+2,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',i+2,2,i+3,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',i+3,2,i+0,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',i+0)) - SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',i+2)) - SketchFeature.addConstraint(Sketcher.Constraint('Vertical',i+1)) - SketchFeature.addConstraint(Sketcher.Constraint('Vertical',i+3)) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',i+0,2,i+1,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',i+1,2,i+2,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',i+2,2,i+3,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',i+3,2,i+0,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',i+0)) + SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',i+2)) + SketchFeature.addConstraint(Sketcher.Constraint('Vertical',i+1)) + SketchFeature.addConstraint(Sketcher.Constraint('Vertical',i+3)) # Fix the bottom left corner of the rectangle - SketchFeature.addConstraint(Sketcher.Constraint('DistanceX',i+2,2,corner[0])) - SketchFeature.addConstraint(Sketcher.Constraint('DistanceY',i+2,2,corner[1])) + SketchFeature.addConstraint(Sketcher.Constraint('DistanceX',i+2,2,corner[0])) + SketchFeature.addConstraint(Sketcher.Constraint('DistanceY',i+2,2,corner[1])) # add dimensions if lengths[0] == lengths[1]: - SketchFeature.addConstraint(Sketcher.Constraint('Equal',i+2,i+3)) - SketchFeature.addConstraint(Sketcher.Constraint('Distance',i+0,hmax-hmin)) + SketchFeature.addConstraint(Sketcher.Constraint('Equal',i+2,i+3)) + SketchFeature.addConstraint(Sketcher.Constraint('Distance',i+0,hmax-hmin)) else: - SketchFeature.addConstraint(Sketcher.Constraint('Distance',i+1,vmax-vmin)) - SketchFeature.addConstraint(Sketcher.Constraint('Distance',i+0,hmax-hmin)) + SketchFeature.addConstraint(Sketcher.Constraint('Distance',i+1,vmax-vmin)) + SketchFeature.addConstraint(Sketcher.Constraint('Distance',i+0,hmax-hmin)) def CreateCircleSketch(SketchFeature, center, radius): i = int(SketchFeature.GeometryCount) SketchFeature.addGeometry(Part.Circle(App.Vector(*center), App.Vector(0,0,1), radius),False) - SketchFeature.addConstraint(Sketcher.Constraint('Radius',i,radius)) - SketchFeature.addConstraint(Sketcher.Constraint('DistanceX',i,3,center[0])) - SketchFeature.addConstraint(Sketcher.Constraint('DistanceY',i,3,center[1])) + SketchFeature.addConstraint(Sketcher.Constraint('Radius',i,radius)) + SketchFeature.addConstraint(Sketcher.Constraint('DistanceX',i,3,center[0])) + SketchFeature.addConstraint(Sketcher.Constraint('DistanceY',i,3,center[1])) def CreateBoxSketchSet(SketchFeature): - SketchFeature.addGeometry(Part.LineSegment(FreeCAD.Vector(-99.230339,36.960674,0),FreeCAD.Vector(69.432587,36.960674,0))) - SketchFeature.addGeometry(Part.LineSegment(FreeCAD.Vector(69.432587,36.960674,0),FreeCAD.Vector(69.432587,-53.196629,0))) - SketchFeature.addGeometry(Part.LineSegment(FreeCAD.Vector(69.432587,-53.196629,0),FreeCAD.Vector(-99.230339,-53.196629,0))) - SketchFeature.addGeometry(Part.LineSegment(FreeCAD.Vector(-99.230339,-53.196629,0),FreeCAD.Vector(-99.230339,36.960674,0))) - # add the constraints - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',0,2,1,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',1,2,2,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',3,2,0,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',0)) - SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',2)) - SketchFeature.addConstraint(Sketcher.Constraint('Vertical',1)) - SketchFeature.addConstraint(Sketcher.Constraint('Vertical',3)) - # add dimensions - SketchFeature.addConstraint(Sketcher.Constraint('Distance',1,81.370787)) - SketchFeature.addConstraint(Sketcher.Constraint('Distance',0,187.573036)) + SketchFeature.addGeometry(Part.LineSegment(FreeCAD.Vector(-99.230339,36.960674,0),FreeCAD.Vector(69.432587,36.960674,0))) + SketchFeature.addGeometry(Part.LineSegment(FreeCAD.Vector(69.432587,36.960674,0),FreeCAD.Vector(69.432587,-53.196629,0))) + SketchFeature.addGeometry(Part.LineSegment(FreeCAD.Vector(69.432587,-53.196629,0),FreeCAD.Vector(-99.230339,-53.196629,0))) + SketchFeature.addGeometry(Part.LineSegment(FreeCAD.Vector(-99.230339,-53.196629,0),FreeCAD.Vector(-99.230339,36.960674,0))) + # add the constraints + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',0,2,1,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',1,2,2,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',3,2,0,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',0)) + SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',2)) + SketchFeature.addConstraint(Sketcher.Constraint('Vertical',1)) + SketchFeature.addConstraint(Sketcher.Constraint('Vertical',3)) + # add dimensions + SketchFeature.addConstraint(Sketcher.Constraint('Distance',1,81.370787)) + SketchFeature.addConstraint(Sketcher.Constraint('Distance',0,187.573036)) def CreateSlotPlateSet(SketchFeature): - SketchFeature.addGeometry(Part.LineSegment(App.Vector(60.029362,-30.279360,0),App.Vector(-120.376335,-30.279360,0))) - SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',0)) - SketchFeature.addGeometry(Part.LineSegment(App.Vector(-120.376335,-30.279360,0),App.Vector(-70.193062,38.113884,0))) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',0,2,1,1)) - SketchFeature.addGeometry(Part.LineSegment(App.Vector(-70.193062,38.113884,0),App.Vector(60.241116,37.478645,0))) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',1,2,2,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',2)) - SketchFeature.addGeometry(Part.ArcOfCircle(Part.Circle(App.Vector(60.039921,3.811391,0),App.Vector(0,0,1),35.127132),-1.403763,1.419522)) - SketchFeature.addConstraint(Sketcher.Constraint('Tangent',2,2,3,2)) - SketchFeature.addConstraint(Sketcher.Constraint('Tangent',0,1,3,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Angle',0,2,1,1,0.947837)) - SketchFeature.addConstraint(Sketcher.Constraint('Distance',0,184.127425)) - SketchFeature.setDatum(7,200.000000) - SketchFeature.addConstraint(Sketcher.Constraint('Radius',3,38.424808)) - SketchFeature.setDatum(8,40.000000) - SketchFeature.setDatum(6,0.872665) - SketchFeature.addConstraint(Sketcher.Constraint('DistanceX',0,2,0.0)) - SketchFeature.setDatum(9,0.000000) - SketchFeature.movePoint(0,2,App.Vector(-0.007829,-33.376450,0)) - SketchFeature.movePoint(0,2,App.Vector(-0.738149,-10.493386,0)) - SketchFeature.movePoint(0,2,App.Vector(-0.007829,2.165328,0)) - SketchFeature.addConstraint(Sketcher.Constraint('DistanceY',0,2,2.165328)) - SketchFeature.setDatum(10,0.000000) + SketchFeature.addGeometry(Part.LineSegment(App.Vector(60.029362,-30.279360,0),App.Vector(-120.376335,-30.279360,0))) + SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',0)) + SketchFeature.addGeometry(Part.LineSegment(App.Vector(-120.376335,-30.279360,0),App.Vector(-70.193062,38.113884,0))) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',0,2,1,1)) + SketchFeature.addGeometry(Part.LineSegment(App.Vector(-70.193062,38.113884,0),App.Vector(60.241116,37.478645,0))) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',1,2,2,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',2)) + SketchFeature.addGeometry(Part.ArcOfCircle(Part.Circle(App.Vector(60.039921,3.811391,0),App.Vector(0,0,1),35.127132),-1.403763,1.419522)) + SketchFeature.addConstraint(Sketcher.Constraint('Tangent',2,2,3,2)) + SketchFeature.addConstraint(Sketcher.Constraint('Tangent',0,1,3,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Angle',0,2,1,1,0.947837)) + SketchFeature.addConstraint(Sketcher.Constraint('Distance',0,184.127425)) + SketchFeature.setDatum(7,200.000000) + SketchFeature.addConstraint(Sketcher.Constraint('Radius',3,38.424808)) + SketchFeature.setDatum(8,40.000000) + SketchFeature.setDatum(6,0.872665) + SketchFeature.addConstraint(Sketcher.Constraint('DistanceX',0,2,0.0)) + SketchFeature.setDatum(9,0.000000) + SketchFeature.movePoint(0,2,App.Vector(-0.007829,-33.376450,0)) + SketchFeature.movePoint(0,2,App.Vector(-0.738149,-10.493386,0)) + SketchFeature.movePoint(0,2,App.Vector(-0.007829,2.165328,0)) + SketchFeature.addConstraint(Sketcher.Constraint('DistanceY',0,2,2.165328)) + SketchFeature.setDatum(10,0.000000) def CreateSlotPlateInnerSet(SketchFeature): - SketchFeature.addGeometry(Part.Circle(App.Vector(195.055893,39.562252,0),App.Vector(0,0,1),29.846098)) - SketchFeature.addGeometry(Part.LineSegment(App.Vector(150.319031,13.449363,0),App.Vector(36.700474,13.139774,0))) - SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',5)) - SketchFeature.addGeometry(Part.LineSegment(App.Vector(36.700474,13.139774,0),App.Vector(77.566010,63.292927,0))) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',5,2,6,1)) - SketchFeature.addGeometry(Part.LineSegment(App.Vector(77.566010,63.292927,0),App.Vector(148.151917,63.602505,0))) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',6,2,7,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',7)) - SketchFeature.addConstraint(Sketcher.Constraint('Parallel',1,6)) - SketchFeature.addGeometry(Part.ArcOfCircle(Part.Circle(App.Vector(192.422913,38.216347,0),App.Vector(0,0,1),45.315174),2.635158,3.602228)) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',7,2,8,1)) - SketchFeature.addConstraint(Sketcher.Constraint('Coincident',8,2,5,1)) - - + SketchFeature.addGeometry(Part.Circle(App.Vector(195.055893,39.562252,0),App.Vector(0,0,1),29.846098)) + SketchFeature.addGeometry(Part.LineSegment(App.Vector(150.319031,13.449363,0),App.Vector(36.700474,13.139774,0))) + SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',5)) + SketchFeature.addGeometry(Part.LineSegment(App.Vector(36.700474,13.139774,0),App.Vector(77.566010,63.292927,0))) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',5,2,6,1)) + SketchFeature.addGeometry(Part.LineSegment(App.Vector(77.566010,63.292927,0),App.Vector(148.151917,63.602505,0))) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',6,2,7,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Horizontal',7)) + SketchFeature.addConstraint(Sketcher.Constraint('Parallel',1,6)) + SketchFeature.addGeometry(Part.ArcOfCircle(Part.Circle(App.Vector(192.422913,38.216347,0),App.Vector(0,0,1),45.315174),2.635158,3.602228)) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',7,2,8,1)) + SketchFeature.addConstraint(Sketcher.Constraint('Coincident',8,2,5,1)) #--------------------------------------------------------------------------- # define the test cases to test the FreeCAD Sketcher module @@ -128,89 +126,126 @@ def CreateSlotPlateInnerSet(SketchFeature): class TestSketcherSolver(unittest.TestCase): - def setUp(self): - self.Doc = FreeCAD.newDocument("SketchSolverTest") + def setUp(self): + self.Doc = FreeCAD.newDocument("SketchSolverTest") - def testBoxCase(self): - self.Box = self.Doc.addObject('Sketcher::SketchObject','SketchBox') - CreateBoxSketchSet(self.Box) - self.Doc.recompute() - # moving a point of the sketch - self.Box.movePoint(0,2,App.Vector(88.342697,28.174158,0)) - # fully constrain - self.Box.addConstraint(Sketcher.Constraint('DistanceX',1,2,90.0)) - self.Box.addConstraint(Sketcher.Constraint('DistanceY',1,2,-50.0)) - self.Doc.recompute() - - def testSlotCase(self): - self.Slot = self.Doc.addObject('Sketcher::SketchObject','SketchSlot') - CreateSlotPlateSet(self.Slot) - self.Doc.recompute() - # test if all edges created - self.failUnless(len(self.Slot.Shape.Edges) == 4) - CreateSlotPlateInnerSet(self.Slot) - self.Doc.recompute() - self.failUnless(len(self.Slot.Shape.Edges) == 9) + def testBoxCase(self): + self.Box = self.Doc.addObject('Sketcher::SketchObject','SketchBox') + CreateBoxSketchSet(self.Box) + self.Doc.recompute() + # moving a point of the sketch + self.Box.movePoint(0,2,App.Vector(88.342697,28.174158,0)) + # fully constrain + self.Box.addConstraint(Sketcher.Constraint('DistanceX',1,2,90.0)) + self.Box.addConstraint(Sketcher.Constraint('DistanceY',1,2,-50.0)) + self.Doc.recompute() - def testIssue3245(self): - self.Doc2 = FreeCAD.newDocument("Issue3245") - self.Doc2.addObject('Sketcher::SketchObject','Sketch') - self.Doc2.Sketch.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(0.000000,0.000000,0.000000,1.000000)) - self.Doc2.Sketch.MapMode = "Deactivated" - self.Doc2.Sketch.addGeometry(Part.LineSegment(App.Vector(-1.195999,56.041161,0),App.Vector(60.654316,56.382877,0)),False) - self.Doc2.Sketch.addConstraint(Sketcher.Constraint('PointOnObject',0,1,-2)) - self.Doc2.Sketch.addConstraint(Sketcher.Constraint('Horizontal',0)) - self.Doc2.Sketch.addGeometry(Part.LineSegment(App.Vector(0.512583,32.121155,0),App.Vector(60.654316,31.779440,0)),False) - self.Doc2.Sketch.addConstraint(Sketcher.Constraint('Horizontal',1)) - self.Doc2.Sketch.addGeometry(Part.LineSegment(App.Vector(0.170867,13.326859,0),App.Vector(61.679455,13.326859,0)),False) - self.Doc2.Sketch.addConstraint(Sketcher.Constraint('PointOnObject',2,1,-2)) - self.Doc2.Sketch.addConstraint(Sketcher.Constraint('Horizontal',2)) - self.Doc2.Sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-2)) - self.Doc2.Sketch.addConstraint(Sketcher.Constraint('DistanceX',0,1,0,2,60.654316)) - self.Doc2.Sketch.setExpression('Constraints[6]', u'60') - self.Doc2.Sketch.addConstraint(Sketcher.Constraint('DistanceX',1,1,1,2,60.654316)) - self.Doc2.Sketch.setExpression('Constraints[7]', u'65') - self.Doc2.Sketch.addConstraint(Sketcher.Constraint('DistanceX',2,1,2,2,61.679455)) - self.Doc2.Sketch.setExpression('Constraints[8]', u'70') - self.Doc2.recompute() - self.Doc2.Sketch.delGeometry(2) - values = d = {key: value for (key, value) in self.Doc2.Sketch.ExpressionEngine} - self.failUnless(values['Constraints[4]'] == u'60') - self.failUnless(values['Constraints[5]'] == u'65') - FreeCAD.closeDocument("Issue3245") + def testSlotCase(self): + self.Slot = self.Doc.addObject('Sketcher::SketchObject','SketchSlot') + CreateSlotPlateSet(self.Slot) + self.Doc.recompute() + # test if all edges created + self.failUnless(len(self.Slot.Shape.Edges) == 4) + CreateSlotPlateInnerSet(self.Slot) + self.Doc.recompute() + self.failUnless(len(self.Slot.Shape.Edges) == 9) - def testIssue3245_2(self): - self.Doc2 = FreeCAD.newDocument("Issue3245") - ActiveSketch = self.Doc2.addObject('Sketcher::SketchObject','Sketch') - ActiveSketch.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(0.000000,0.000000,0.000000,1.000000)) - ActiveSketch.MapMode = "Deactivated" - geoList = [] - geoList.append(Part.LineSegment(App.Vector(-23.574591,42.399727,0),App.Vector(81.949776,42.399727,0))) - geoList.append(Part.LineSegment(App.Vector(81.949776,42.399727,0),App.Vector(81.949776,-19.256901,0))) - geoList.append(Part.LineSegment(App.Vector(81.949776,-19.256901,0),App.Vector(-23.574591,-19.256901,0))) - geoList.append(Part.LineSegment(App.Vector(-23.574591,-19.256901,0),App.Vector(-23.574591,42.399727,0))) - ActiveSketch.addGeometry(geoList,False) - conList = [] - conList.append(Sketcher.Constraint('Coincident',0,2,1,1)) - conList.append(Sketcher.Constraint('Coincident',1,2,2,1)) - conList.append(Sketcher.Constraint('Coincident',2,2,3,1)) - conList.append(Sketcher.Constraint('Coincident',3,2,0,1)) - conList.append(Sketcher.Constraint('Horizontal',0)) - conList.append(Sketcher.Constraint('Horizontal',2)) - conList.append(Sketcher.Constraint('Vertical',1)) - conList.append(Sketcher.Constraint('Vertical',3)) - ActiveSketch.addConstraint(conList) - ActiveSketch.addConstraint(Sketcher.Constraint('DistanceX',0,1,0,2,105.524367)) - ActiveSketch.setExpression('Constraints[8]', u'10 + 10') - ActiveSketch.addConstraint(Sketcher.Constraint('DistanceY',3,1,3,2,61.656628)) - ActiveSketch.setDatum(9,App.Units.Quantity('5.000000 mm')) - ActiveSketch.delConstraint(8) - values = d = {key: value for (key, value) in self.Doc2.Sketch.ExpressionEngine} - self.Doc2.recompute() - self.failUnless(len(values) == 0) - FreeCAD.closeDocument("Issue3245") - - def tearDown(self): - #closing doc - FreeCAD.closeDocument("SketchSolverTest") - #print ("omit closing document for debugging") + def testIssue3245(self): + self.Doc2 = FreeCAD.newDocument("Issue3245") + self.Doc2.addObject('Sketcher::SketchObject','Sketch') + self.Doc2.Sketch.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(0.000000,0.000000,0.000000,1.000000)) + self.Doc2.Sketch.MapMode = "Deactivated" + self.Doc2.Sketch.addGeometry(Part.LineSegment(App.Vector(-1.195999,56.041161,0),App.Vector(60.654316,56.382877,0)),False) + self.Doc2.Sketch.addConstraint(Sketcher.Constraint('PointOnObject',0,1,-2)) + self.Doc2.Sketch.addConstraint(Sketcher.Constraint('Horizontal',0)) + self.Doc2.Sketch.addGeometry(Part.LineSegment(App.Vector(0.512583,32.121155,0),App.Vector(60.654316,31.779440,0)),False) + self.Doc2.Sketch.addConstraint(Sketcher.Constraint('Horizontal',1)) + self.Doc2.Sketch.addGeometry(Part.LineSegment(App.Vector(0.170867,13.326859,0),App.Vector(61.679455,13.326859,0)),False) + self.Doc2.Sketch.addConstraint(Sketcher.Constraint('PointOnObject',2,1,-2)) + self.Doc2.Sketch.addConstraint(Sketcher.Constraint('Horizontal',2)) + self.Doc2.Sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-2)) + self.Doc2.Sketch.addConstraint(Sketcher.Constraint('DistanceX',0,1,0,2,60.654316)) + self.Doc2.Sketch.setExpression('Constraints[6]', u'60') + self.Doc2.Sketch.addConstraint(Sketcher.Constraint('DistanceX',1,1,1,2,60.654316)) + self.Doc2.Sketch.setExpression('Constraints[7]', u'65') + self.Doc2.Sketch.addConstraint(Sketcher.Constraint('DistanceX',2,1,2,2,61.679455)) + self.Doc2.Sketch.setExpression('Constraints[8]', u'70') + self.Doc2.recompute() + self.Doc2.Sketch.delGeometry(2) + values = d = {key: value for (key, value) in self.Doc2.Sketch.ExpressionEngine} + self.failUnless(values['Constraints[4]'] == u'60') + self.failUnless(values['Constraints[5]'] == u'65') + FreeCAD.closeDocument("Issue3245") + + def testIssue3245_2(self): + self.Doc2 = FreeCAD.newDocument("Issue3245") + ActiveSketch = self.Doc2.addObject('Sketcher::SketchObject','Sketch') + ActiveSketch.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(0.000000,0.000000,0.000000,1.000000)) + ActiveSketch.MapMode = "Deactivated" + geoList = [] + geoList.append(Part.LineSegment(App.Vector(-23.574591,42.399727,0),App.Vector(81.949776,42.399727,0))) + geoList.append(Part.LineSegment(App.Vector(81.949776,42.399727,0),App.Vector(81.949776,-19.256901,0))) + geoList.append(Part.LineSegment(App.Vector(81.949776,-19.256901,0),App.Vector(-23.574591,-19.256901,0))) + geoList.append(Part.LineSegment(App.Vector(-23.574591,-19.256901,0),App.Vector(-23.574591,42.399727,0))) + ActiveSketch.addGeometry(geoList,False) + conList = [] + conList.append(Sketcher.Constraint('Coincident',0,2,1,1)) + conList.append(Sketcher.Constraint('Coincident',1,2,2,1)) + conList.append(Sketcher.Constraint('Coincident',2,2,3,1)) + conList.append(Sketcher.Constraint('Coincident',3,2,0,1)) + conList.append(Sketcher.Constraint('Horizontal',0)) + conList.append(Sketcher.Constraint('Horizontal',2)) + conList.append(Sketcher.Constraint('Vertical',1)) + conList.append(Sketcher.Constraint('Vertical',3)) + ActiveSketch.addConstraint(conList) + ActiveSketch.addConstraint(Sketcher.Constraint('DistanceX',0,1,0,2,105.524367)) + ActiveSketch.setExpression('Constraints[8]', u'10 + 10') + ActiveSketch.addConstraint(Sketcher.Constraint('DistanceY',3,1,3,2,61.656628)) + ActiveSketch.setDatum(9,App.Units.Quantity('5.000000 mm')) + ActiveSketch.delConstraint(8) + values = d = {key: value for (key, value) in self.Doc2.Sketch.ExpressionEngine} + self.Doc2.recompute() + self.failUnless(len(values) == 0) + FreeCAD.closeDocument("Issue3245") + + def testBlockConstraintEllipse(self): + self.Doc3 = FreeCAD.newDocument("BlockConstraintTests") + ActiveSketch = self.Doc3.addObject('Sketcher::SketchObject','Sketch') + ActiveSketch.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(0.000000,0.000000,0.000000,1.000000)) + ActiveSketch.MapMode = "Deactivated" + ActiveSketch.addGeometry(Part.Ellipse(App.Vector(-19.129438,14.345055,0),App.Vector(-33.806261,12.085921,0),App.Vector(-30.689360,7.107538,0)),False) + ActiveSketch.solve() + ActiveSketch.exposeInternalGeometry(0) + ActiveSketch.solve() + ActiveSketch.movePoint(0,0,App.Vector(-26.266434,14.345055,0),0) + ActiveSketch.solve() + ActiveSketch.addConstraint(Sketcher.Constraint('Block',0)) # Block the Ellipse in place + ActiveSketch.addConstraint(Sketcher.Constraint('Block',1)) # Block the major axis in place (on purpose) + status = ActiveSketch.solve() + self.failUnless(status == 0) # no redundants/conflicts/convergence issues + ActiveSketch.addConstraint(Sketcher.Constraint('Distance',1,27.277350)) # Length of major axis + ActiveSketch.setDriving(6,True) # ensure length is driving (because pre-existing block constraint on major axis) + ActiveSketch.setDatum(6,App.Units.Quantity('28.000000 mm')) + status = ActiveSketch.solve() + self.failUnless(status == 0) # no redundants/conflicts/convergence issues + ActiveSketch.addConstraint(Sketcher.Constraint('Distance',2,11.747233)) # Length of minor axis + ActiveSketch.setDatum(7,App.Units.Quantity('15.000000 mm')) + ActiveSketch.solve() + self.failUnless(status == 0) # no redundants/conflicts/convergence issues + ActiveSketch.addConstraint(Sketcher.Constraint('Block',2)) + ActiveSketch.solve() + self.failUnless(status == 0) # no redundants/conflicts/convergence issues + ActiveSketch.addConstraint(Sketcher.Constraint('Horizontal',1)) # Make major axis horizontal (together with horizontal and length driving constraints) + ActiveSketch.solve() + self.failUnless(status == 0) # no redundants/conflicts/convergence issues + ActiveSketch.addConstraint(Sketcher.Constraint('DistanceX',0,3,-1,1,27.655024)) # Locate Ellipse center + ActiveSketch.addConstraint(Sketcher.Constraint('DistanceY',0,3,-1,1,-20.877021)) + ActiveSketch.setDatum(10,App.Units.Quantity('25.000000 mm')) + ActiveSketch.setDatum(11,App.Units.Quantity('-20.000000 mm')) + ActiveSketch.solve() + self.failUnless(status == 0) # no redundants/conflicts/convergence issues + + def tearDown(self): + #closing doc + FreeCAD.closeDocument("SketchSolverTest") + #print ("omit closing document for debugging") From ac6d06dd8431d5aca157c918667c3804135b217c Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 13 Feb 2021 12:14:12 +0100 Subject: [PATCH 2/3] Draft: fix syntax errors --- src/Mod/Draft/draftguitools/gui_arcs.py | 2 +- src/Mod/Draft/draftguitools/gui_beziers.py | 2 +- src/Mod/Draft/draftguitools/gui_groups.py | 5 ++++- src/Mod/Draft/draftguitools/gui_shape2dview.py | 2 +- src/Mod/Draft/draftguitools/gui_shapestrings.py | 2 +- src/Mod/Draft/draftguitools/gui_snaps.py | 2 +- src/Mod/Draft/draftguitools/gui_subelements.py | 2 +- src/Mod/Draft/drafttaskpanels/task_circulararray.py | 2 +- src/Mod/Draft/drafttaskpanels/task_polararray.py | 2 +- 9 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Mod/Draft/draftguitools/gui_arcs.py b/src/Mod/Draft/draftguitools/gui_arcs.py index bb202aa1ea..4a46256fb3 100644 --- a/src/Mod/Draft/draftguitools/gui_arcs.py +++ b/src/Mod/Draft/draftguitools/gui_arcs.py @@ -68,7 +68,7 @@ class Arc(gui_base_original.Creator): def Activated(self): """Execute when the command is called.""" - super(Arc, self).Activated(name=translate("draft","Arc") + super(Arc, self).Activated(name=translate("draft","Arc")) if self.ui: self.step = 0 self.center = None diff --git a/src/Mod/Draft/draftguitools/gui_beziers.py b/src/Mod/Draft/draftguitools/gui_beziers.py index 044bb03615..6dd84d1ec2 100644 --- a/src/Mod/Draft/draftguitools/gui_beziers.py +++ b/src/Mod/Draft/draftguitools/gui_beziers.py @@ -235,7 +235,7 @@ class CubicBezCurve(gui_lines.Line): def GetResources(self): """Set icon, menu and tooltip.""" - _menu = + _menu = "" _tip = () return {'Pixmap': 'Draft_CubicBezCurve', diff --git a/src/Mod/Draft/draftguitools/gui_groups.py b/src/Mod/Draft/draftguitools/gui_groups.py index 7e1039e450..e8e95ab582 100644 --- a/src/Mod/Draft/draftguitools/gui_groups.py +++ b/src/Mod/Draft/draftguitools/gui_groups.py @@ -163,7 +163,10 @@ class SelectGroup(gui_base.GuiCommandNeedsSelection): d = {'Pixmap': 'Draft_SelectGroup', 'MenuText': QT_TRANSLATE_NOOP("Draft_SelectGroup","Select group"), - 'ToolTip': QT_TRANSLATE_NOOP("Draft_SelectGroup","If the selection is a group, it selects all objects that are inside this group, including those in nested sub-groups.\n\nIf the selection is a simple object inside a group, it will select the "brother" objects, that is,\nthose that are at the same level as this object, including the upper group that contains them all.")} + 'ToolTip': QT_TRANSLATE_NOOP("Draft_SelectGroup","If the selection is a group, it selects all objects that are inside this group, " + "including those in nested sub-groups.\n\nIf the selection is a simple object " + "inside a group, it will select the \"brother\" objects, that is,\nthose that are " + "at the same level as this object, including the upper group that contains them all.")} return d def Activated(self): diff --git a/src/Mod/Draft/draftguitools/gui_shape2dview.py b/src/Mod/Draft/draftguitools/gui_shape2dview.py index 80cacece0a..292e0d9614 100644 --- a/src/Mod/Draft/draftguitools/gui_shape2dview.py +++ b/src/Mod/Draft/draftguitools/gui_shape2dview.py @@ -54,7 +54,7 @@ class Shape2DView(gui_base_original.Modifier): def GetResources(self): """Set icon, menu and tooltip.""" - _menu = + _menu = "" _tip = () return {'Pixmap': 'Draft_2DShapeView', diff --git a/src/Mod/Draft/draftguitools/gui_shapestrings.py b/src/Mod/Draft/draftguitools/gui_shapestrings.py index e1bf33abed..813bc85920 100644 --- a/src/Mod/Draft/draftguitools/gui_shapestrings.py +++ b/src/Mod/Draft/draftguitools/gui_shapestrings.py @@ -62,7 +62,7 @@ class ShapeString(gui_base_original.Creator): def GetResources(self): """Set icon, menu and tooltip.""" - _menu = + _menu = "" _tip = () d = {'Pixmap': 'Draft_ShapeString', diff --git a/src/Mod/Draft/draftguitools/gui_snaps.py b/src/Mod/Draft/draftguitools/gui_snaps.py index 362a2a1e9c..ccffaef8a6 100644 --- a/src/Mod/Draft/draftguitools/gui_snaps.py +++ b/src/Mod/Draft/draftguitools/gui_snaps.py @@ -567,7 +567,7 @@ class ShowSnapBar(gui_base.GuiCommandSimplest): def GetResources(self): """Set icon, menu and tooltip.""" - _tip = + _tip = "" return {'Pixmap': 'Draft_Snap', 'MenuText': QT_TRANSLATE_NOOP("Draft_ShowSnapBar","Show snap toolbar"), diff --git a/src/Mod/Draft/draftguitools/gui_subelements.py b/src/Mod/Draft/draftguitools/gui_subelements.py index 4abcc9770d..711de64753 100644 --- a/src/Mod/Draft/draftguitools/gui_subelements.py +++ b/src/Mod/Draft/draftguitools/gui_subelements.py @@ -54,7 +54,7 @@ class SubelementHighlight(gui_base_original.Modifier): def GetResources(self): """Set icon, menu and tooltip.""" - _menu = + _menu = "" _tip = () return {'Pixmap': 'Draft_SubelementHighlight', diff --git a/src/Mod/Draft/drafttaskpanels/task_circulararray.py b/src/Mod/Draft/drafttaskpanels/task_circulararray.py index a815c4e56c..6b0d86abf9 100644 --- a/src/Mod/Draft/drafttaskpanels/task_circulararray.py +++ b/src/Mod/Draft/drafttaskpanels/task_circulararray.py @@ -297,7 +297,7 @@ class TaskPanelCircularArray: "App.ActiveDocument.recompute()"] # We commit the command list through the parent command - self.source_command.commit(translate("draft","Circular array", _cmd_list) + self.source_command.commit(translate("draft","Circular array", _cmd_list)) def get_distances(self): """Get the distance parameters from the widgets.""" diff --git a/src/Mod/Draft/drafttaskpanels/task_polararray.py b/src/Mod/Draft/drafttaskpanels/task_polararray.py index 0258a9dbf9..66ad102f9e 100644 --- a/src/Mod/Draft/drafttaskpanels/task_polararray.py +++ b/src/Mod/Draft/drafttaskpanels/task_polararray.py @@ -92,7 +92,7 @@ class TaskPanelPolarArray: pix = QtGui.QPixmap(svg) icon = QtGui.QIcon.fromTheme(icon_name, QtGui.QIcon(svg)) self.form.setWindowIcon(icon) - self.form.setWindowTitle(translate("draft","Polar array") + self.form.setWindowTitle(translate("draft","Polar array")) self.form.label_icon.setPixmap(pix.scaled(32, 32)) From c8f9197bf06173ced23c873f6b8901c79f9f6348 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sat, 13 Feb 2021 15:12:28 +0100 Subject: [PATCH 3/3] Sketcher: Fix external geometry ellipse projection in parallel plane ==================================================================== When the ellipse to be projected and the sketch plane are parallel, the original code by shermelin provided for a translation of the original ellipse, which would be the best solution if it weren't because the Sketcher, internally, works under the assumption of a normal vector to the sketcher plane being (0,0,1). If the original ellipse is parallel to the sketch plane, but the sketch plane is not the XY plane, the copy and translation would result in a ellipse not in the XY plane of the Sketcher. Then the sketcher internals will not properly consider its dimensions. The solution applied here is to default to the general method for non-parallel planes. It solves: https://forum.freecadweb.org/viewtopic.php?f=3&t=55284#p477522 --- src/Mod/Sketcher/App/SketchObject.cpp | 140 +++++++++++++------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 81ff77e0c5..ed8e0afda8 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -6591,86 +6591,86 @@ void SketchObject::rebuildExternalGeometry(void) gp_Dir origAxisMinorDir = elipsOrig.YAxis().Direction(); gp_Vec origAxisMinor = elipsOrig.MinorRadius() * gp_Vec(origAxisMinorDir); - if (sketchPlane.Position().Direction().IsParallel(elipsOrig.Position().Direction(), Precision::Angular())) { - elipsDest = elipsOrig.Translated(origCenter, destCenter); - Handle(Geom_Ellipse) curve = new Geom_Ellipse(elipsDest); - Part::GeomEllipse* ellipse = new Part::GeomEllipse(); - ellipse->setHandle(curve); - GeometryFacade::setConstruction(ellipse, true); + // Here, it used to be a test for parallel direction between the sketchplane and the elipsOrig, in which + // the original ellipse would be copied and translated to the new position. + // The problem with that approach is that for the sketcher the normal vector is always (0,0,1). If the original + // ellipse was not on the XY plane, the copy will not be either. Then, the dimensions would be wrong because of the + // different major axis direction (which is not projected on the XY plane). So here, we default to the more general + // ellipse construction algorithm. + // + // Doing that solves: + // https://forum.freecadweb.org/viewtopic.php?f=3&t=55284#p477522 - ExternalGeo.push_back(ellipse); + // GENERAL ELLIPSE CONSTRUCTION ALGORITHM + // + // look for major axis of projected ellipse + // + // t is the parameter along the origin ellipse + // OM(t) = origCenter + // + majorRadius * cos(t) * origAxisMajorDir + // + minorRadius * sin(t) * origAxisMinorDir + gp_Vec2d PA = ProjVecOnPlane_UV(origAxisMajor, sketchPlane); + gp_Vec2d PB = ProjVecOnPlane_UV(origAxisMinor, sketchPlane); + double t_max = 2.0 * PA.Dot(PB) / (PA.SquareMagnitude() - PB.SquareMagnitude()); + t_max = 0.5 * atan(t_max); // gives new major axis is most cases, but not all + double t_min = t_max + 0.5 * M_PI; + + // ON_max = OM(t_max) gives the point, which projected on the sketch plane, + // becomes the apoapse of the pojected ellipse. + gp_Vec ON_max = origAxisMajor * cos(t_max) + origAxisMinor * sin(t_max); + gp_Vec ON_min = origAxisMajor * cos(t_min) + origAxisMinor * sin(t_min); + gp_Vec destAxisMajor = ProjVecOnPlane_UVN(ON_max, sketchPlane); + gp_Vec destAxisMinor = ProjVecOnPlane_UVN(ON_min, sketchPlane); + + double RDest = destAxisMajor.Magnitude(); + double rDest = destAxisMinor.Magnitude(); + + if (RDest < rDest) { + double rTmp = rDest; + rDest = RDest; + RDest = rTmp; + gp_Vec axisTmp = destAxisMajor; + destAxisMajor = destAxisMinor; + destAxisMinor = axisTmp; + } + + double sens = sketchAx3.Direction().Dot(elipsOrig.Position().Direction()); + gp_Ax2 destCurveAx2(destCenter, + gp_Dir(0, 0, sens > 0.0 ? 1.0 : -1.0), + gp_Dir(destAxisMajor)); + + if ((RDest - rDest) < (double) Precision::Confusion()) { // projection is a circle + Handle(Geom_Circle) curve = new Geom_Circle(destCurveAx2, 0.5 * (rDest + RDest)); + Part::GeomCircle* circle = new Part::GeomCircle(); + circle->setHandle(curve); + GeometryFacade::setConstruction(circle, true); + + ExternalGeo.push_back(circle); } else { + if (sketchPlane.Position().Direction().IsNormal(elipsOrig.Position().Direction(), Precision::Angular())) { + gp_Vec start = gp_Vec(destCenter.XYZ()) + destAxisMajor; + gp_Vec end = gp_Vec(destCenter.XYZ()) - destAxisMajor; - // look for major axis of projected ellipse - // - // t is the parameter along the origin ellipse - // OM(t) = origCenter - // + majorRadius * cos(t) * origAxisMajorDir - // + minorRadius * sin(t) * origAxisMinorDir - gp_Vec2d PA = ProjVecOnPlane_UV(origAxisMajor, sketchPlane); - gp_Vec2d PB = ProjVecOnPlane_UV(origAxisMinor, sketchPlane); - double t_max = 2.0 * PA.Dot(PB) / (PA.SquareMagnitude() - PB.SquareMagnitude()); - t_max = 0.5 * atan(t_max); // gives new major axis is most cases, but not all - double t_min = t_max + 0.5 * M_PI; - - // ON_max = OM(t_max) gives the point, which projected on the sketch plane, - // becomes the apoapse of the pojected ellipse. - gp_Vec ON_max = origAxisMajor * cos(t_max) + origAxisMinor * sin(t_max); - gp_Vec ON_min = origAxisMajor * cos(t_min) + origAxisMinor * sin(t_min); - gp_Vec destAxisMajor = ProjVecOnPlane_UVN(ON_max, sketchPlane); - gp_Vec destAxisMinor = ProjVecOnPlane_UVN(ON_min, sketchPlane); - - double RDest = destAxisMajor.Magnitude(); - double rDest = destAxisMinor.Magnitude(); - - if (RDest < rDest) { - double rTmp = rDest; - rDest = RDest; - RDest = rTmp; - gp_Vec axisTmp = destAxisMajor; - destAxisMajor = destAxisMinor; - destAxisMinor = axisTmp; - } - - double sens = sketchAx3.Direction().Dot(elipsOrig.Position().Direction()); - gp_Ax2 destCurveAx2(destCenter, - gp_Dir(0, 0, sens > 0.0 ? 1.0 : -1.0), - gp_Dir(destAxisMajor)); - - if ((RDest - rDest) < (double) Precision::Confusion()) { // projection is a circle - Handle(Geom_Circle) curve = new Geom_Circle(destCurveAx2, 0.5 * (rDest + RDest)); - Part::GeomCircle* circle = new Part::GeomCircle(); - circle->setHandle(curve); - GeometryFacade::setConstruction(circle, true); - - ExternalGeo.push_back(circle); + Part::GeomLineSegment * projectedSegment = new Part::GeomLineSegment(); + projectedSegment->setPoints(Base::Vector3d(start.X(), start.Y(), start.Z()), + Base::Vector3d(end.X(), end.Y(), end.Z())); + GeometryFacade::setConstruction(projectedSegment, true); + ExternalGeo.push_back(projectedSegment); } else { - if (sketchPlane.Position().Direction().IsNormal(elipsOrig.Position().Direction(), Precision::Angular())) { - gp_Vec start = gp_Vec(destCenter.XYZ()) + destAxisMajor; - gp_Vec end = gp_Vec(destCenter.XYZ()) - destAxisMajor; - Part::GeomLineSegment * projectedSegment = new Part::GeomLineSegment(); - projectedSegment->setPoints(Base::Vector3d(start.X(), start.Y(), start.Z()), - Base::Vector3d(end.X(), end.Y(), end.Z())); - GeometryFacade::setConstruction(projectedSegment, true); - ExternalGeo.push_back(projectedSegment); - } - else { - - elipsDest.SetPosition(destCurveAx2); - elipsDest.SetMajorRadius(destAxisMajor.Magnitude()); - elipsDest.SetMinorRadius(destAxisMinor.Magnitude()); + elipsDest.SetPosition(destCurveAx2); + elipsDest.SetMajorRadius(destAxisMajor.Magnitude()); + elipsDest.SetMinorRadius(destAxisMinor.Magnitude()); - Handle(Geom_Ellipse) curve = new Geom_Ellipse(elipsDest); - Part::GeomEllipse* ellipse = new Part::GeomEllipse(); - ellipse->setHandle(curve); - GeometryFacade::setConstruction(ellipse, true); + Handle(Geom_Ellipse) curve = new Geom_Ellipse(elipsDest); + Part::GeomEllipse* ellipse = new Part::GeomEllipse(); + ellipse->setHandle(curve); + GeometryFacade::setConstruction(ellipse, true); - ExternalGeo.push_back(ellipse); - } + ExternalGeo.push_back(ellipse); } } }