diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index 3404239f0d..3eaa17934d 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -1241,14 +1241,14 @@ class _Wall(ArchComponent.Component): # in some corner case != getSortedClusters() elif obj.Base.isDerivedFrom("Sketcher::SketchObject"): self.basewires = [] - skGeom = obj.Base.Geometry + skGeom = obj.Base.GeometryFacadeList skGeomEdges = [] skPlacement = obj.Base.Placement # Get Sketch's placement to restore later for i in skGeom: if not i.Construction: # support Line, Arc, Circle for Sketch as Base at the moment - if isinstance(i, (Part.LineSegment, Part.Circle, Part.ArcOfCircle)): - skGeomEdgesI = i.toShape() + if isinstance(i.Geometry, (Part.LineSegment, Part.Circle, Part.ArcOfCircle)): + skGeomEdgesI = i.Geometry.toShape() skGeomEdges.append(skGeomEdgesI) for cluster in Part.getSortedClusters(skGeomEdges): clusterTransformed = [] diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 74a944f8c6..0b34c1ad1e 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -1107,6 +1107,7 @@ class DraftToolBar: self.continueCmd.show() def modUi(self): + self.undoButton.hide() self.isCopy.show() self.isSubelementMode.show() p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") diff --git a/src/Mod/Draft/draftfunctions/upgrade.py b/src/Mod/Draft/draftfunctions/upgrade.py index 8768d0d916..c449015bde 100644 --- a/src/Mod/Draft/draftfunctions/upgrade.py +++ b/src/Mod/Draft/draftfunctions/upgrade.py @@ -42,6 +42,7 @@ import draftmake.make_block as make_block from draftutils.messages import _msg, _err from draftutils.translate import _tr +from draftgeoutils.geometry import is_straight_line # Delay import of module until first use because it is heavy Part = lz.LazyLoader("Part", globals(), "Part") @@ -160,6 +161,8 @@ def upgrade(objects, delete=False, force=None): return None if len(obj.Shape.Edges) == 1: return None + if is_straight_line(obj.Shape) == True: + return None if utils.get_type(obj) == "Wire": obj.Closed = True return True @@ -333,26 +336,35 @@ def upgrade(objects, delete=False, force=None): def makeWires(objectslist): """Join edges in the given objects list into wires.""" edges = [] - for o in objectslist: - for e in o.Shape.Edges: - edges.append(e) + for object in objectslist: + for edge in object.Shape.Edges: + edges.append(edge) + try: - nedges = Part.__sortEdges__(edges[:]) + sorted_edges = Part.sortEdges(edges) if _DEBUG: - for e in nedges: - print("Curve: {}".format(e.Curve)) - print("first: {}, last: {}".format(e.Vertexes[0].Point, + for item_sorted_edges in sorted_edges: + for e in item_sorted_edges: + print("Curve: {}".format(e.Curve)) + print("first: {}, last: {}".format(e.Vertexes[0].Point, e.Vertexes[-1].Point)) - w = Part.Wire(nedges) + wires = [Part.Wire(e) for e in sorted_edges] except Part.OCCError: return None else: - if len(w.Edges) == len(edges): + for wire in wires: newobj = doc.addObject("Part::Feature", "Wire") - newobj.Shape = w + newobj.Shape = wire add_list.append(newobj) - delete_list.extend(objectslist) - return True + # delete object only if there are no links to it + # TODO: A more refined criteria to delete object + for object in objectslist: + if object.InList: + if App.GuiUp: + object.ViewObject.Visibility = False + else: + delete_list.append(object) + return True return None # analyzing what we have in our selection @@ -475,54 +487,56 @@ def upgrade(objects, delete=False, force=None): _msg(_tr("Found 1 non-parametric objects: " "draftifying it")) - # we have only one object that contains one edge - elif not faces and len(objects) == 1 and len(edges) == 1: - # we have a closed sketch: extract a face - if (objects[0].isDerivedFrom("Sketcher::SketchObject") - and len(edges[0].Vertexes) == 1): - result = makeSketchFace(objects[0]) + # in the following cases there are no faces + elif not faces: + # we have only closed wires + if wires and not openwires and not loneedges: + # we have a sketch: extract a face + if (len(objects) == 1 + and objects[0].isDerivedFrom("Sketcher::SketchObject")): + result = makeSketchFace(objects[0]) + if result: + _msg(_tr("Found 1 closed sketch object: " + "creating a face from it")) + # only closed wires + else: + result = makeFaces(objects) + if result: + _msg(_tr("Found closed wires: creating faces")) + # wires or edges: we try to join them + elif len(wires) > 1 or len(loneedges) > 1: + result = makeWires(objects) if result: - _msg(_tr("Found 1 closed sketch object: " - "creating a face from it")) - else: + _msg(_tr("Found several wires or edges: wiring them")) + # TODO: improve draftify function + # only one object: if not parametric, we "draftify" it + # elif (len(objects) == 1 + # and not objects[0].isDerivedFrom("Part::Part2DObjectPython")): + # result = ext_draftify.draftify(objects[0]) + # if result: + # _msg(_tr("Found 1 non-parametric objects: " + # "draftifying it")) + # special case, we have only one open wire. We close it, + # unless it has only 1 edge! + elif len(objects) == 1 and len(openwires) == 1: + result = closeWire(objects[0]) + _msg(_tr("trying: closing it")) + if result: + _msg(_tr("Found 1 open wire: closing it")) + # we have only one object that contains one edge + # TODO: this case should be considered in draftify + elif len(objects) == 1 and len(edges) == 1: # turn to Draft Line e = objects[0].Shape.Edges[0] if isinstance(e.Curve, (Part.LineSegment, Part.Line)): result = turnToLine(objects[0]) if result: _msg(_tr("Found 1 linear object: converting to line")) - - # we have only closed wires, no faces - elif wires and not faces and not openwires: - # we have a sketch: extract a face - if (len(objects) == 1 - and objects[0].isDerivedFrom("Sketcher::SketchObject")): - result = makeSketchFace(objects[0]) + # only points, no edges + elif not edges and len(objects) > 1: + result = makeCompound(objects) if result: - _msg(_tr("Found 1 closed sketch object: " - "creating a face from it")) - # only closed wires - else: - result = makeFaces(objects) - if result: - _msg(_tr("Found closed wires: creating faces")) - - # special case, we have only one open wire. We close it, - # unless it has only 1 edge! - elif len(openwires) == 1 and not faces and not loneedges: - result = closeWire(objects[0]) - if result: - _msg(_tr("Found 1 open wire: closing it")) - # only open wires and edges: we try to join their edges - elif openwires and not wires and not faces: - result = makeWires(objects) - if result: - _msg(_tr("Found several open wires: joining them")) - # only loneedges: we try to join them - elif loneedges and not facewires: - result = makeWires(objects) - if result: - _msg(_tr("Found several edges: wiring them")) + _msg(_tr("Found points: creating compound")) # all other cases, if more than 1 object, make a compound elif len(objects) > 1: result = makeCompound(objects) diff --git a/src/Mod/Draft/drafttaskpanels/task_scale.py b/src/Mod/Draft/drafttaskpanels/task_scale.py index 7d6e93b289..a19c75fc7e 100644 --- a/src/Mod/Draft/drafttaskpanels/task_scale.py +++ b/src/Mod/Draft/drafttaskpanels/task_scale.py @@ -53,21 +53,21 @@ class ScaleTaskPanel: layout.addWidget(self.xLabel, 0, 0, 1, 1) self.xValue = QtGui.QDoubleSpinBox() self.xValue.setRange(0.0000001, 1000000.0) - self.xValue.setDecimals(Draft.getParam("precision")) + self.xValue.setDecimals(Draft.precision()) self.xValue.setValue(1) layout.addWidget(self.xValue,0,1,1,1) self.yLabel = QtGui.QLabel() layout.addWidget(self.yLabel,1,0,1,1) self.yValue = QtGui.QDoubleSpinBox() self.yValue.setRange(.0000001,1000000.0) - self.yValue.setDecimals(Draft.getParam("precision")) + self.yValue.setDecimals(Draft.precision()) self.yValue.setValue(1) layout.addWidget(self.yValue,1,1,1,1) self.zLabel = QtGui.QLabel() layout.addWidget(self.zLabel,2,0,1,1) self.zValue = QtGui.QDoubleSpinBox() self.zValue.setRange(.0000001,1000000.0) - self.zValue.setDecimals(Draft.getParam("precision")) + self.zValue.setDecimals(Draft.precision()) self.zValue.setValue(1) layout.addWidget(self.zValue,2,1,1,1) self.lock = QtGui.QCheckBox() diff --git a/src/Mod/Draft/drafttests/test_modification.py b/src/Mod/Draft/drafttests/test_modification.py index 97fcee07f7..4d5d621fcc 100644 --- a/src/Mod/Draft/drafttests/test_modification.py +++ b/src/Mod/Draft/drafttests/test_modification.py @@ -232,7 +232,7 @@ class DraftModification(unittest.TestCase): self.assertTrue(obj, "'{}' failed".format(operation)) def test_upgrade(self): - """Upgrade two Draft Lines into a closed Draft Wire.""" + """Upgrade two Lines into a closed Wire, then draftify it.""" operation = "Draft Upgrade" _msg(" Test '{}'".format(operation)) a = Vector(0, 0, 0) @@ -242,8 +242,12 @@ class DraftModification(unittest.TestCase): _msg(" a={0}, b={1}".format(a, b)) _msg(" Line 2") _msg(" b={0}, c={1}".format(b, c)) - line_1 = Draft.make_line(a, b) - line_2 = Draft.make_line(b, c) + shape_line_1 = Part.makeLine(a, b) + shape_line_2 = Part.makeLine(b, c) + line_1 = App.ActiveDocument.addObject("Part::Feature") + line_2 = App.ActiveDocument.addObject("Part::Feature") + line_1.Shape = shape_line_1 + line_2.Shape = shape_line_2 App.ActiveDocument.recompute() obj = Draft.upgrade([line_1, line_2], delete=True) @@ -255,8 +259,7 @@ class DraftModification(unittest.TestCase): obj2 = Draft.upgrade(obj[0], delete=True) App.ActiveDocument.recompute() s2 = obj2[0][0] - _msg(" 2: Result '{0}' ({1})".format(s2.Shape.ShapeType, - s2.TypeId)) + _msg(" 2: Result '{0}' ({1})".format(s2.Shape.ShapeType, s2.TypeId)) self.assertTrue(bool(obj2[0]), "'{}' failed".format(operation)) obj3 = Draft.upgrade(obj2[0], delete=True) @@ -265,10 +268,15 @@ class DraftModification(unittest.TestCase): _msg(" 3: Result '{0}' ({1})".format(s3.Shape.ShapeType, s3.TypeId)) self.assertTrue(bool(obj3[0]), "'{}' failed".format(operation)) - obj4 = Draft.upgrade(obj3[0], delete=True) + # when draftify, upgrade dont return a new object + Draft.upgrade(obj3[0], delete=True) App.ActiveDocument.recompute() wire = App.ActiveDocument.Wire _msg(" 4: Result '{0}' ({1})".format(wire.Proxy.Type, wire.TypeId)) + self.assertTrue(bool(wire), "'{}' failed".format(operation)) + + obj4 = Draft.upgrade(wire, delete=True) + App.ActiveDocument.recompute() _msg(" The last object cannot be upgraded further") self.assertFalse(bool(obj4[0]), "'{}' failed".format(operation)) diff --git a/src/Mod/Draft/importAirfoilDAT.py b/src/Mod/Draft/importAirfoilDAT.py index 4b19e34ab7..e496667a4c 100644 --- a/src/Mod/Draft/importAirfoilDAT.py +++ b/src/Mod/Draft/importAirfoilDAT.py @@ -157,9 +157,9 @@ def process(doc, filename): with the parsed information. """ # Regex to identify data rows and throw away unused metadata - xval = '(?P(\-|\d*)\.\d+(E\-?\d+)?)' - yval = '(?P\-?\s*\d*\.\d+(E\-?\d+)?)' - _regex = '^\s*' + xval + '\,?\s*' + yval + '\s*$' + xval = r'(?P(\-|\d*)\.*\d*([Ee]\-?\d+)?)' + yval = r'(?P\-?\s*\d*\.*\d*([Ee]\-?\d+)?)' + _regex = r'^\s*' + xval + r'\,?\s*' + yval + r'\s*$' regex = re.compile(_regex) afile = pythonopen(filename, 'r') diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index dfa107766f..3246fbe4b5 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -171,6 +171,8 @@ # include # include # include +# include +# include #if OCC_VERSION_HEX < 0x070300 # include @@ -4161,26 +4163,13 @@ bool TopoShape::findPlane(gp_Pln &pln, double tol) const { if(_Shape.IsNull()) return false; TopoDS_Shape shape = _Shape; - TopExp_Explorer exp(_Shape,TopAbs_FACE); + TopExp_Explorer exp(_Shape,TopAbs_EDGE); if(exp.More()) { - auto face = exp.Current(); + TopoDS_Shape edge = exp.Current(); exp.Next(); - if(!exp.More()) { - BRepAdaptor_Surface adapt(TopoDS::Face(face)); - if(adapt.GetType() != GeomAbs_Plane) - return false; - pln = adapt.Plane(); - return true; - } - }else{ - TopExp_Explorer exp(_Shape,TopAbs_EDGE); - if(exp.More()) { - TopoDS_Shape edge = exp.Current(); - exp.Next(); - if(!exp.More()) { - // To deal with OCCT bug of wrong edge transformation - shape = BRepBuilderAPI_Copy(edge).Shape(); - } + if (!exp.More()) { + // To deal with OCCT bug of wrong edge transformation + shape = BRepBuilderAPI_Copy(_Shape).Shape(); } } try { @@ -4188,6 +4177,24 @@ bool TopoShape::findPlane(gp_Pln &pln, double tol) const { if (!finder.Found()) return false; pln = GeomAdaptor_Surface(finder.Surface()).Plane(); + + // To make the returned plane normal more stable, if the shape has any + // face, use the normal of the first face. + TopExp_Explorer exp(shape, TopAbs_FACE); + if(exp.More()) { + BRepAdaptor_Surface adapt(TopoDS::Face(exp.Current())); + double u = adapt.FirstUParameter() + + (adapt.LastUParameter() - adapt.FirstUParameter())/2.; + double v = adapt.FirstVParameter() + + (adapt.LastVParameter() - adapt.FirstVParameter())/2.; + BRepLProp_SLProps prop(adapt,u,v,2,Precision::Confusion()); + if(prop.IsNormalDefined()) { + gp_Pnt pnt; gp_Vec vec; + // handles the orientation state of the shape + BRepGProp_Face(TopoDS::Face(exp.Current())).Normal(u,v,pnt,vec); + pln = gp_Pln(pnt, gp_Dir(vec)); + } + } return true; }catch (Standard_Failure &e) { // For some reason the above BRepBuilderAPI_Copy failed to copy diff --git a/src/Mod/Path/App/Area.cpp b/src/Mod/Path/App/Area.cpp index 0f80a7094d..b3f2440dcc 100644 --- a/src/Mod/Path/App/Area.cpp +++ b/src/Mod/Path/App/Area.cpp @@ -2963,20 +2963,19 @@ std::list Area::sortWires(const std::list &shapes, pstart = *_pstart; bool use_bound = !has_start || _pstart==NULL; - if(use_bound || sort_mode == SortMode2D5 || sort_mode == SortModeGreedy) { - //Second stage, group shape by its plane, and find overall boundary + //Second stage, group shape by its plane, and find overall boundary - if(arcPlaneFound || use_bound) { - for(auto &info : shape_list) { - if(arcPlaneFound) { - info.myShape.Move(trsf); - if(info.myPlanar) info.myPln.Transform(trsf); - } - if(use_bound) - BRepBndLib::Add(info.myShape, bounds, Standard_False); - } + for(auto &info : shape_list) { + if(arcPlaneFound) { + info.myShape.Move(trsf); + if(info.myPlanar) info.myPln.Transform(trsf); } + BRepBndLib::Add(info.myShape, bounds, Standard_False); + } + + if(use_bound || sort_mode == SortMode2D5 || sort_mode == SortModeGreedy) { + for(auto itNext=shape_list.begin(),it=itNext;it!=shape_list.end();it=itNext) { ++itNext; if(!it->myPlanar) continue; @@ -3005,16 +3004,36 @@ std::list Area::sortWires(const std::list &shapes, //FC_DURATION_DECL_INIT(td); + bounds.SetGap(0.0); + Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; + bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax); + AREA_TRACE("bound (" << xMin<<", "<::iterator i = getTooltablePtr()->Tools.begin(); i != getTooltablePtr()->Tools.end(); ++i) { PyObject *tool = new Path::ToolPy(i->second); - PyDict_SetItem(dict,PYINT_FROMLONG(i->first),tool); + dict.setItem(Py::Long(i->first), Py::asObject(tool)); } - return Py::Dict(dict); + return dict; } void TooltablePy::setTools(Py::Dict arg) diff --git a/src/Mod/Path/PathScripts/PathEngraveBase.py b/src/Mod/Path/PathScripts/PathEngraveBase.py index 4fdbc18a6b..abaf413dc8 100644 --- a/src/Mod/Path/PathScripts/PathEngraveBase.py +++ b/src/Mod/Path/PathScripts/PathEngraveBase.py @@ -30,6 +30,7 @@ import copy # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader DraftGeomUtils = LazyLoader('DraftGeomUtils', globals(), 'DraftGeomUtils') +Part = LazyLoader('Part', globals(), 'Part') from PySide import QtCore @@ -69,9 +70,11 @@ class ObjectOp(PathOp.ObjectOp): # reorder the wire if hasattr(obj, 'StartVertex'): - offset = DraftGeomUtils.rebaseWire(offset, obj.StartVertex) + start_idx = obj.StartVertex edges = copy.copy(PathOpTools.orientWire(offset, forward).Edges) + edges = Part.sortEdges(edges)[0]; + last = None for z in zValues: diff --git a/src/Mod/Path/PathScripts/PathToolControllerGui.py b/src/Mod/Path/PathScripts/PathToolControllerGui.py index 34224a3535..62709086e0 100644 --- a/src/Mod/Path/PathScripts/PathToolControllerGui.py +++ b/src/Mod/Path/PathScripts/PathToolControllerGui.py @@ -253,6 +253,8 @@ class ToolControllerEditor(object): self.form.vertFeed.editingFinished.connect(self.refresh) self.form.horizRapid.editingFinished.connect(self.refresh) self.form.vertRapid.editingFinished.connect(self.refresh) + self.form.spindleSpeed.editingFinished.connect(self.refresh) + self.form.spindleDirection.currentIndexChanged.connect(self.refresh) class TaskPanel: diff --git a/src/Mod/TechDraw/App/DrawViewBalloon.cpp b/src/Mod/TechDraw/App/DrawViewBalloon.cpp index b58c3328fd..9f8a397c39 100644 --- a/src/Mod/TechDraw/App/DrawViewBalloon.cpp +++ b/src/Mod/TechDraw/App/DrawViewBalloon.cpp @@ -105,11 +105,16 @@ DrawViewBalloon::DrawViewBalloon(void) ADD_PROPERTY_TYPE(ShapeScale,(1.0),"",(App::PropertyType)(App::Prop_None),"Balloon shape scale"); ShapeScale.setConstraints(&SymbolScaleRange); + ADD_PROPERTY_TYPE(EndTypeScale,(1.0),"",(App::PropertyType)(App::Prop_None),"EndType shape scale"); + ShapeScale.setConstraints(&SymbolScaleRange); + ADD_PROPERTY_TYPE(TextWrapLen,(-1),"",(App::PropertyType)(App::Prop_None),"Text wrap length; -1 means no wrap"); ADD_PROPERTY_TYPE(KinkLength,(prefKinkLength()),"",(App::PropertyType)(App::Prop_None), "Distance from symbol to leader kink"); + ADD_PROPERTY_TYPE(LineVisible,(true),"",(App::PropertyType)(App::Prop_None),"Balloon line visible or hidden"); + SourceView.setScope(App::LinkScope::Global); Rotation.setStatus(App::Property::Hidden,true); Caption.setStatus(App::Property::Hidden,true); diff --git a/src/Mod/TechDraw/App/DrawViewBalloon.h b/src/Mod/TechDraw/App/DrawViewBalloon.h index a039ca2398..0892aac32a 100644 --- a/src/Mod/TechDraw/App/DrawViewBalloon.h +++ b/src/Mod/TechDraw/App/DrawViewBalloon.h @@ -49,15 +49,17 @@ public: DrawViewBalloon(); virtual ~DrawViewBalloon(); - App::PropertyLink SourceView; - App::PropertyString Text; - App::PropertyEnumeration EndType; - App::PropertyEnumeration BubbleShape; + App::PropertyLink SourceView; + App::PropertyString Text; + App::PropertyEnumeration EndType; + App::PropertyEnumeration BubbleShape; App::PropertyFloatConstraint ShapeScale; - App::PropertyDistance OriginX; - App::PropertyDistance OriginY; - App::PropertyFloat TextWrapLen; - App::PropertyDistance KinkLength; + App::PropertyFloatConstraint EndTypeScale; + App::PropertyDistance OriginX; + App::PropertyDistance OriginY; + App::PropertyFloat TextWrapLen; + App::PropertyDistance KinkLength; + App::PropertyBool LineVisible; short mustExecute() const override; diff --git a/src/Mod/TechDraw/App/DrawViewDimension.cpp b/src/Mod/TechDraw/App/DrawViewDimension.cpp index ef1dea950b..8849cedead 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.cpp +++ b/src/Mod/TechDraw/App/DrawViewDimension.cpp @@ -691,21 +691,12 @@ std::string DrawViewDimension::formatValue(qreal value, QString qFormatSpec, int // - the value in the base unit but without displayed unit // - the value + unit (not necessarily the base unit!) // the user can overwrite the decimal settings, so we must in every case use the formatSpecifier - // if useDecimals(), then formatSpecifier = global decimals, otherwise it is %.2f + // the default is: if useDecimals(), then formatSpecifier = global decimals, otherwise it is %.2f QLocale loc; double userVal; - bool checkDecimals = true; if (showUnits() || (Type.isValue("Angle")) || (Type.isValue("Angle3Pt"))) { - formattedValue = qUserString; // result value + unit (not necessarily base unit!) - // remove unit - formattedValue.remove(rxUnits); - // to number - userVal = loc.toDouble(formattedValue); - if (userVal >= 1.0) - // we can assure we didn't make an error > 10% via getUserString() - checkDecimals = false; - } - if (checkDecimals){ + userVal = asQuantity.getValue(); + } else { // get value in the base unit with default decimals // for the conversion we use the same method as in DlgUnitsCalculator::valueChanged // get the conversion factor for the unit @@ -750,7 +741,6 @@ std::string DrawViewDimension::formatValue(qreal value, QString qFormatSpec, int //qUserString from Quantity includes units - prefix + R + nnn ft + suffix qMultiValueStr = formatPrefix + qGenPrefix + qUserString + formatSuffix; } - formattedValue = qMultiValueStr; } diff --git a/src/Mod/TechDraw/Gui/AppTechDrawGuiPy.cpp b/src/Mod/TechDraw/Gui/AppTechDrawGuiPy.cpp index c15f0ec13c..14dc2882c3 100644 --- a/src/Mod/TechDraw/Gui/AppTechDrawGuiPy.cpp +++ b/src/Mod/TechDraw/Gui/AppTechDrawGuiPy.cpp @@ -193,7 +193,11 @@ private: } else { vpp->showMDIViewPage(); mdi = vpp->getMDIViewPage(); - mdi->printPdf(filePath); + if (mdi) { + mdi->printPdf(filePath); + } else { + throw Py::TypeError("Page not available! Is it Hidden?"); + } } } } @@ -234,7 +238,11 @@ private: } else { vpp->showMDIViewPage(); mdi = vpp->getMDIViewPage(); - mdi->saveSVG(filePath); + if (mdi) { + mdi->saveSVG(filePath); + } else { + throw Py::TypeError("Page not available! Is it Hidden?"); + } } } } diff --git a/src/Mod/TechDraw/Gui/QGIViewBalloon.cpp b/src/Mod/TechDraw/Gui/QGIViewBalloon.cpp index 9b590d6b03..1b7b062a0e 100644 --- a/src/Mod/TechDraw/Gui/QGIViewBalloon.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewBalloon.cpp @@ -717,14 +717,14 @@ void QGIViewBalloon::draw() double yAdj = 0.0; int endType = balloon->EndType.getValue(); double arrowAdj = QGIArrow::getOverlapAdjust(endType, - QGIArrow::getPrefArrowSize()); + balloon->EndTypeScale.getValue()*QGIArrow::getPrefArrowSize()); if (endType == ArrowType::NONE) { arrow->hide(); } else { arrow->setStyle(endType); - arrow->setSize(QGIArrow::getPrefArrowSize()); + arrow->setSize(balloon->EndTypeScale.getValue()*QGIArrow::getPrefArrowSize()); arrow->draw(); Base::Vector3d arrowTipPos(arrowTipX, arrowTipY, 0.0); @@ -738,7 +738,7 @@ void QGIViewBalloon::draw() float arAngle = atan2(dirballoonLinesLine.y, dirballoonLinesLine.x) * 180 / M_PI; arrow->setPos(arrowTipX, arrowTipY); - if ( (endType == ArrowType::FILLED_TRIANGLE) && + if ( (endType == ArrowType::FILLED_TRIANGLE) && (prefOrthoPyramid()) ) { if (arAngle < 0.0) { arAngle += 360.0; @@ -765,6 +765,12 @@ void QGIViewBalloon::draw() dLinePath.lineTo(arrowTipX - xAdj, arrowTipY - yAdj); balloonLines->setPath(dLinePath); + // This overwrites the previously created QPainterPath with empty one, in case it should be hidden. Should be refactored. + if (!balloon->LineVisible.getValue()) { + arrow->hide(); + balloonLines->setPath(QPainterPath()); + } + // redraw the Balloon and the parent View if (hasHover && !isSelected()) { setPrettyPre(); diff --git a/src/Tools/freecad-thumbnailer b/src/Tools/freecad-thumbnailer index b141a2905d..8e3a439b0a 100644 --- a/src/Tools/freecad-thumbnailer +++ b/src/Tools/freecad-thumbnailer @@ -3,22 +3,32 @@ Installation: - This executable file should be on the PATH so it can be found - "$ sudo cp freecad-thumbnailer /usr/share/bin" -- the application/x-extension-fcstd MIME type should be registered - Check that a corresponding /usr/share/mime/packages/freecad.xml file exists - Make sure the MIME database is up to date - "$ sudo update-mime-database /usr/share/mime" -- Register this thumbnailer - Adding a file /usr/share/thumbnailers/FreeCAD.thumbnailer with the following content: + "$ sudo cp freecad-thumbnailer /usr/bin" + and must have execution rights + "$ sudo chmod +x /usr/bin/freecad-thumbnailer" - [Thumbnailer Entry] - TryExec=freecad-thumbnailer - Exec=freecad-thumbnailer -s %s %i %o - MimeType=application/x-extension-fcstd; +- If a FreeCAD project file doesn't include a thumbnail the file freecad.png is used. + Thus, the file src/Gui/Icons/freecad-icon-48.png must be installed. + "$ sudo cp freecad-icon-48.png /usr/share/icons/hicolor/48x48/apps/freecad.png" + +- The application/x-extension-fcstd MIME type should be registered + Check that a corresponding /usr/share/mime/packages/freecad.xml file exists + Make sure the MIME database is up to date + "$ sudo update-mime-database /usr/share/mime" + +- Register this thumbnailer + Adding a file /usr/share/thumbnailers/FreeCAD.thumbnailer with the following content: + + [Thumbnailer Entry] + TryExec=freecad-thumbnailer + Exec=freecad-thumbnailer -s %s %i %o + MimeType=application/x-extension-fcstd; + +HINT: Make sure that the symlink /usr/bin/python exists and points to the Python executable NOTE: To make sure FreeCAD saves thumbnail information: - Edit -> Preferences... -> Document -> Save thumbnail into project when saving document + Edit -> Preferences... -> Document -> Save thumbnail into project when saving document """ import sys import zipfile