diff --git a/src/Mod/Draft/draftviewproviders/view_dimension.py b/src/Mod/Draft/draftviewproviders/view_dimension.py index af2d42f427..0646b33cb9 100644 --- a/src/Mod/Draft/draftviewproviders/view_dimension.py +++ b/src/Mod/Draft/draftviewproviders/view_dimension.py @@ -32,17 +32,22 @@ They inherit their behavior from the base Annotation viewprovider. # \brief Provides the Draft Dimension viewprovider classes. import pivy.coin as coin +import lazy_loader.lazy_loader as lz from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD as App import DraftVecUtils -import DraftGeomUtils +import draftutils.units as units import draftutils.utils as utils import draftutils.gui_utils as gui_utils from draftviewproviders.view_draft_annotation \ import ViewProviderDraftAnnotation +# Delay import of module until first use because it is heavy +Part = lz.LazyLoader("Part", globals(), "Part") +DraftGeomUtils = lz.LazyLoader("DraftGeomUtils", globals(), "DraftGeomUtils") + class ViewProviderDimensionBase(ViewProviderDraftAnnotation): """The base viewprovider for the Draft Dimensions object. @@ -330,9 +335,12 @@ class ViewProviderDimensionBase(ViewProviderDraftAnnotation): class ViewProviderLinearDimension(ViewProviderDimensionBase): + """The viewprovider for the Linear Dimension objects. + + This includes straight edge measurement, as well as measurement + of circular edges, and circumferences. """ - A View Provider for the Draft Linear Dimension object - """ + def __init__(self, vobj): super(ViewProviderLinearDimension, self).__init__(vobj) super(ViewProviderLinearDimension, self).set_properties(vobj) @@ -340,29 +348,36 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase): self.Object = vobj.Object vobj.Proxy = self - def attach(self, vobj): - '''Setup the scene sub-graph of the view provider''' + """Set up the scene sub-graph of the viewprovider.""" self.Object = vobj.Object + self.color = coin.SoBaseColor() self.font = coin.SoFont() self.font3d = coin.SoFont() - self.text = coin.SoAsciiText() - self.text3d = coin.SoText2() - self.text.string = "d" # some versions of coin crash if string is not set + self.text = coin.SoAsciiText() # Can be oriented in 3D space + self.text3d = coin.SoText2() # Faces the camera always + + # The text string needs to be initialized to something, + # otherwise it may cause a crash of the system + self.text.string = "d" self.text3d.string = "d" self.textpos = coin.SoTransform() - self.text.justification = self.text3d.justification = coin.SoAsciiText.CENTER + self.text.justification = coin.SoAsciiText.CENTER + self.text3d.justification = coin.SoAsciiText.CENTER + label = coin.SoSeparator() label.addChild(self.textpos) label.addChild(self.color) label.addChild(self.font) label.addChild(self.text) + label3d = coin.SoSeparator() label3d.addChild(self.textpos) label3d.addChild(self.color) label3d.addChild(self.font3d) label3d.addChild(self.text3d) + self.coord1 = coin.SoCoordinate3() self.trans1 = coin.SoTransform() self.coord2 = coin.SoCoordinate3() @@ -371,12 +386,14 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase): self.transDimOvershoot2 = coin.SoTransform() self.transExtOvershoot1 = coin.SoTransform() self.transExtOvershoot2 = coin.SoTransform() + self.marks = coin.SoSeparator() self.marksDimOvershoot = coin.SoSeparator() self.marksExtOvershoot = coin.SoSeparator() self.drawstyle = coin.SoDrawStyle() self.line = coin.SoType.fromName("SoBrepEdgeSet").createInstance() self.coords = coin.SoCoordinate3() + self.node = coin.SoGroup() self.node.addChild(self.color) self.node.addChild(self.drawstyle) @@ -389,6 +406,7 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase): self.lineswitch2.addChild(self.marksDimOvershoot) self.lineswitch2.addChild(self.marksExtOvershoot) self.node.addChild(label) + self.node3d = coin.SoGroup() self.node3d.addChild(self.color) self.node3d.addChild(self.drawstyle) @@ -401,254 +419,346 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase): self.lineswitch3.addChild(self.marksDimOvershoot) self.lineswitch3.addChild(self.marksExtOvershoot) self.node3d.addChild(label3d) - vobj.addDisplayMode(self.node,"2D") - vobj.addDisplayMode(self.node3d,"3D") - self.updateData(vobj.Object,"Start") - self.onChanged(vobj,"FontSize") - self.onChanged(vobj,"FontName") - self.onChanged(vobj,"ArrowType") - self.onChanged(vobj,"LineColor") - self.onChanged(vobj,"DimOvershoot") - self.onChanged(vobj,"ExtOvershoot") + + vobj.addDisplayMode(self.node, "2D") + vobj.addDisplayMode(self.node3d, "3D") + self.updateData(vobj.Object, "Start") + self.onChanged(vobj, "FontSize") + self.onChanged(vobj, "FontName") + self.onChanged(vobj, "ArrowType") + self.onChanged(vobj, "LineColor") + self.onChanged(vobj, "DimOvershoot") + self.onChanged(vobj, "ExtOvershoot") def updateData(self, obj, prop): - """called when the base object is changed""" - import DraftGui - if prop in ["Start","End","Dimline","Direction"]: + """Execute when a property from the Proxy class is changed. - if obj.Start == obj.End: - return + It only runs if `Start`, `End`, `Dimline`, or `Direction` changed. + """ + if prop not in ("Start", "End", "Dimline", "Direction"): + return - if not hasattr(self,"node"): - return + if obj.Start == obj.End: + return - import Part, DraftGeomUtils - from pivy import coin + if not hasattr(self, "node"): + return - # calculate the 4 points - self.p1 = obj.Start - self.p4 = obj.End - base = None - if hasattr(obj,"Direction"): - if not DraftVecUtils.isNull(obj.Direction): - v2 = self.p1.sub(obj.Dimline) - v3 = self.p4.sub(obj.Dimline) - v2 = DraftVecUtils.project(v2,obj.Direction) - v3 = DraftVecUtils.project(v3,obj.Direction) - self.p2 = obj.Dimline.add(v2) - self.p3 = obj.Dimline.add(v3) - if DraftVecUtils.equals(self.p2,self.p3): - base = None - proj = None - else: - base = Part.LineSegment(self.p2,self.p3).toShape() - proj = DraftGeomUtils.findDistance(self.p1,base) - if proj: - proj = proj.negative() - if not base: - if DraftVecUtils.equals(self.p1,self.p4): - base = None - proj = None - else: - base = Part.LineSegment(self.p1,self.p4).toShape() - proj = DraftGeomUtils.findDistance(obj.Dimline,base) + vobj = obj.ViewObject + + # Calculate the 4 points + # + # | d | + # ---p2-------------c----p3---- c + # | | + # | | + # p1 p4 + # + # - `c` is the `Dimline`, a point that lies on the dimension line + # or on its extension. + # - The line itself between `p2` to `p3` is the `base`. + # - The distance between `p2` (`base`) to `p1` is `proj`, an extension + # line from the dimension to the measured object. + # - If the `proj` distance is zero, `p1` and `p2` are the same point, + # and same with `p3` and `p4`. + # + self.p1 = obj.Start + self.p4 = obj.End + base = None + + if (hasattr(obj, "Direction") + and not DraftVecUtils.isNull(obj.Direction)): + v2 = self.p1 - obj.Dimline + v3 = self.p4 - obj.Dimline + v2 = DraftVecUtils.project(v2, obj.Direction) + v3 = DraftVecUtils.project(v3, obj.Direction) + self.p2 = obj.Dimline + v2 + self.p3 = obj.Dimline + v3 + if DraftVecUtils.equals(self.p2, self.p3): + base = None + proj = None + else: + base = Part.LineSegment(self.p2, self.p3).toShape() + proj = DraftGeomUtils.findDistance(self.p1, base) if proj: - self.p2 = self.p1.add(proj.negative()) - self.p3 = self.p4.add(proj.negative()) - else: - self.p2 = self.p1 - self.p3 = self.p4 + proj = proj.negative() + + if not base: + if DraftVecUtils.equals(self.p1, self.p4): + base = None + proj = None + else: + base = Part.LineSegment(self.p1, self.p4).toShape() + proj = DraftGeomUtils.findDistance(obj.Dimline, base) + if proj: - if hasattr(obj.ViewObject,"ExtLines") and hasattr(obj.ViewObject, "ScaleMultiplier"): - dmax = obj.ViewObject.ExtLines.Value * obj.ViewObject.ScaleMultiplier - if dmax and (proj.Length > dmax): - if (dmax > 0): - self.p1 = self.p2.add(DraftVecUtils.scaleTo(proj,dmax)) - self.p4 = self.p3.add(DraftVecUtils.scaleTo(proj,dmax)) - else: - rest = proj.Length + dmax - self.p1 = self.p2.add(DraftVecUtils.scaleTo(proj,rest)) - self.p4 = self.p3.add(DraftVecUtils.scaleTo(proj,rest)) + self.p2 = self.p1 + proj.negative() + self.p3 = self.p4 + proj.negative() else: - proj = (self.p3.sub(self.p2)).cross(App.Vector(0,0,1)) + self.p2 = self.p1 + self.p3 = self.p4 - # calculate the arrows positions - self.trans1.translation.setValue((self.p2.x,self.p2.y,self.p2.z)) - self.coord1.point.setValue((self.p2.x,self.p2.y,self.p2.z)) - self.trans2.translation.setValue((self.p3.x,self.p3.y,self.p3.z)) - self.coord2.point.setValue((self.p3.x,self.p3.y,self.p3.z)) - - # calculate dimension and extension lines overshoots positions - self.transDimOvershoot1.translation.setValue((self.p2.x,self.p2.y,self.p2.z)) - self.transDimOvershoot2.translation.setValue((self.p3.x,self.p3.y,self.p3.z)) - self.transExtOvershoot1.translation.setValue((self.p2.x,self.p2.y,self.p2.z)) - self.transExtOvershoot2.translation.setValue((self.p3.x,self.p3.y,self.p3.z)) - - # calculate the text position and orientation - if hasattr(obj,"Normal"): - if DraftVecUtils.isNull(obj.Normal): - if proj: - norm = (self.p3.sub(self.p2).cross(proj)).negative() + if proj: + if hasattr(vobj, "ExtLines") and hasattr(vobj, "ScaleMultiplier"): + # The scale multiplier also affects the value + # of the extension line; this makes sure a maximum length + # is used if the calculated value is larger than it. + dmax = vobj.ExtLines.Value * vobj.ScaleMultiplier + if dmax and proj.Length > dmax: + if dmax > 0: + self.p1 = self.p2 + DraftVecUtils.scaleTo(proj, dmax) + self.p4 = self.p3 + DraftVecUtils.scaleTo(proj, dmax) else: - norm = App.Vector(0,0,1) - else: - norm = App.Vector(obj.Normal) - else: - if proj: - norm = (self.p3.sub(self.p2).cross(proj)).negative() - else: - norm = App.Vector(0,0,1) - if not DraftVecUtils.isNull(norm): - norm.normalize() - u = self.p3.sub(self.p2) - u.normalize() - v1 = norm.cross(u) - rot1 = App.Placement(DraftVecUtils.getPlaneRotation(u,v1,norm)).Rotation.Q - self.transDimOvershoot1.rotation.setValue((rot1[0],rot1[1],rot1[2],rot1[3])) - self.transDimOvershoot2.rotation.setValue((rot1[0],rot1[1],rot1[2],rot1[3])) - if hasattr(obj.ViewObject,"FlipArrows"): - if obj.ViewObject.FlipArrows: - u = u.negative() - v2 = norm.cross(u) - rot2 = App.Placement(DraftVecUtils.getPlaneRotation(u,v2,norm)).Rotation.Q - self.trans1.rotation.setValue((rot2[0],rot2[1],rot2[2],rot2[3])) - self.trans2.rotation.setValue((rot2[0],rot2[1],rot2[2],rot2[3])) - if self.p1 != self.p2: - u3 = self.p1.sub(self.p2) - u3.normalize() - v3 = norm.cross(u3) - rot3 = App.Placement(DraftVecUtils.getPlaneRotation(u3,v3,norm)).Rotation.Q - self.transExtOvershoot1.rotation.setValue((rot3[0],rot3[1],rot3[2],rot3[3])) - self.transExtOvershoot2.rotation.setValue((rot3[0],rot3[1],rot3[2],rot3[3])) - if hasattr(obj.ViewObject,"TextSpacing")and hasattr(obj.ViewObject, "ScaleMultiplier"): - ts = obj.ViewObject.TextSpacing.Value * obj.ViewObject.ScaleMultiplier - offset = DraftVecUtils.scaleTo(v1,ts) - else: - offset = DraftVecUtils.scaleTo(v1,0.05) - rott = rot1 - if hasattr(obj.ViewObject,"FlipText"): - if obj.ViewObject.FlipText: - rott = App.Rotation(*rott).multiply(App.Rotation(norm,180)).Q - offset = offset.negative() - # setting text - try: - m = obj.ViewObject.DisplayMode - except: # swallow all exceptions here since it always fails on first run (Displaymode enum no set yet) - m = ["2D","3D"][utils.get_param("dimstyle",0)] - if m == "3D": - offset = offset.negative() - self.tbase = (self.p2.add((self.p3.sub(self.p2).multiply(0.5)))).add(offset) - if hasattr(obj.ViewObject,"TextPosition"): - if not DraftVecUtils.isNull(obj.ViewObject.TextPosition): - self.tbase = obj.ViewObject.TextPosition - self.textpos.translation.setValue([self.tbase.x,self.tbase.y,self.tbase.z]) - self.textpos.rotation = coin.SbRotation(rott[0],rott[1],rott[2],rott[3]) - su = True - if hasattr(obj.ViewObject,"ShowUnit"): - su = obj.ViewObject.ShowUnit - # set text value - l = self.p3.sub(self.p2).Length - unit = None - if hasattr(obj.ViewObject,"UnitOverride"): - unit = obj.ViewObject.UnitOverride - # special representation if "Building US" scheme - if App.ParamGet("User parameter:BaseApp/Preferences/Units").GetInt("UserSchema",0) == 5: - s = App.Units.Quantity(l,App.Units.Length).UserString - self.string = s.replace("' ","'- ") - self.string = s.replace("+"," ") - elif hasattr(obj.ViewObject,"Decimals"): - self.string = DraftGui.displayExternal(l,obj.ViewObject.Decimals,'Length',su,unit) - else: - self.string = DraftGui.displayExternal(l,None,'Length',su,unit) - if hasattr(obj.ViewObject,"Override"): - if obj.ViewObject.Override: - self.string = obj.ViewObject.Override.replace("$dim",\ - self.string) - self.text.string = self.text3d.string = utils.string_encode_coin(self.string) + rest = proj.Length + dmax + self.p1 = self.p2 + DraftVecUtils.scaleTo(proj, rest) + self.p4 = self.p3 + DraftVecUtils.scaleTo(proj, rest) + else: + proj = (self.p3 - self.p2).cross(App.Vector(0, 0, 1)) - # set the lines - if m == "3D": - # calculate the spacing of the text - textsize = (len(self.string)*obj.ViewObject.FontSize.Value)/4.0 - spacing = ((self.p3.sub(self.p2)).Length/2.0) - textsize - self.p2a = self.p2.add(DraftVecUtils.scaleTo(self.p3.sub(self.p2),spacing)) - self.p2b = self.p3.add(DraftVecUtils.scaleTo(self.p2.sub(self.p3),spacing)) - self.coords.point.setValues([[self.p1.x,self.p1.y,self.p1.z], - [self.p2.x,self.p2.y,self.p2.z], - [self.p2a.x,self.p2a.y,self.p2a.z], - [self.p2b.x,self.p2b.y,self.p2b.z], - [self.p3.x,self.p3.y,self.p3.z], - [self.p4.x,self.p4.y,self.p4.z]]) - #self.line.numVertices.setValues([3,3]) - self.line.coordIndex.setValues(0,7,(0,1,2,-1,3,4,5)) - else: - self.coords.point.setValues([[self.p1.x,self.p1.y,self.p1.z], - [self.p2.x,self.p2.y,self.p2.z], - [self.p3.x,self.p3.y,self.p3.z], - [self.p4.x,self.p4.y,self.p4.z]]) - #self.line.numVertices.setValue(4) - self.line.coordIndex.setValues(0,4,(0,1,2,3)) + # Calculate the arrow positions + p2 = (self.p2.x, self.p2.y, self.p2.z) + p3 = (self.p3.x, self.p3.y, self.p3.z) + + self.trans1.translation.setValue(p2) + self.coord1.point.setValue(p2) + self.trans2.translation.setValue(p3) + self.coord2.point.setValue(p3) + + # Calculate dimension and extension lines overshoots positions + self.transDimOvershoot1.translation.setValue(p2) + self.transDimOvershoot2.translation.setValue(p3) + self.transExtOvershoot1.translation.setValue(p2) + self.transExtOvershoot2.translation.setValue(p3) + + # Determine the orientation of the text by using a normal direction. + # By default the value of +Z will be used, or a calculated value + # from p2 and p3. So the text will lie on the XY plane + # or a plane coplanar with p2 and p3. + u = self.p3 - self.p2 + u.normalize() + + if proj: + _norm = u.cross(proj) + norm = _norm.negative() + else: + norm = App.Vector(0, 0, 1) + + # If `Normal` exists and is different from the default `(0,0,0)`, + # it will be used. + if hasattr(obj, "Normal") and not DraftVecUtils.isNull(obj.Normal): + norm = App.Vector(obj.Normal) + + if not DraftVecUtils.isNull(norm): + norm.normalize() + + # Calculate the position of the arrows and extension lines + v1 = norm.cross(u) + _plane_rot = DraftVecUtils.getPlaneRotation(u, v1, norm) + rot1 = App.Placement(_plane_rot).Rotation.Q + self.transDimOvershoot1.rotation.setValue((rot1[0], rot1[1], + rot1[2], rot1[3])) + self.transDimOvershoot2.rotation.setValue((rot1[0], rot1[1], + rot1[2], rot1[3])) + + if hasattr(vobj, "FlipArrows") and vobj.FlipArrows: + u = u.negative() + + v2 = norm.cross(u) + _plane_rot = DraftVecUtils.getPlaneRotation(u, v2, norm) + rot2 = App.Placement(_plane_rot).Rotation.Q + self.trans1.rotation.setValue((rot2[0], rot2[1], + rot2[2], rot2[3])) + self.trans2.rotation.setValue((rot2[0], rot2[1], + rot2[2], rot2[3])) + + if self.p1 != self.p2: + u3 = self.p1 - self.p2 + u3.normalize() + v3 = norm.cross(u3) + _plane_rot = DraftVecUtils.getPlaneRotation(u3, v3, norm) + rot3 = App.Placement(_plane_rot).Rotation.Q + self.transExtOvershoot1.rotation.setValue((rot3[0], rot3[1], + rot3[2], rot3[3])) + self.transExtOvershoot2.rotation.setValue((rot3[0], rot3[1], + rot3[2], rot3[3])) + + # Offset is the distance from the dimension line to the textual + # element that displays the value of the measurement + if hasattr(vobj, "TextSpacing") and hasattr(vobj, "ScaleMultiplier"): + ts = vobj.TextSpacing.Value * vobj.ScaleMultiplier + offset = DraftVecUtils.scaleTo(v1, ts) + else: + offset = DraftVecUtils.scaleTo(v1, 0.05) + + rott = rot1 + if hasattr(vobj, "FlipText") and vobj.FlipText: + _rott = App.Rotation(rott[0], rott[1], rott[2], rott[3]) + rott = _rott.multiply(App.Rotation(norm, 180)).Q + offset = offset.negative() + + # On first run the `DisplayMode` enumeration is not set, so we trap + # the exception and set the display mode using the value + # in the parameter database + try: + m = vobj.DisplayMode + except AssertionError: + m = ["2D", "3D"][utils.get_param("dimstyle", 0)] + + if m == "3D": + offset = offset.negative() + + # The position of the text element in the dimension is provided + # in absolute coordinates by the value of `TextPosition`, + # if it is different from the default `(0,0,0)` + if (hasattr(vobj, "TextPosition") + and not DraftVecUtils.isNull(vobj.TextPosition)): + self.tbase = vobj.TextPosition + else: + # Otherwise the position is calculated from the end points + # of the dimension line, and the offset that depends + # on `TextSpacing` + center = self.p2 + (self.p3 - self.p2).multiply(0.5) + self.tbase = center + offset + + self.textpos.translation.setValue([self.tbase.x, + self.tbase.y, + self.tbase.z]) + self.textpos.rotation = coin.SbRotation(rott[0], rott[1], + rott[2], rott[3]) + + show_unit = True + if hasattr(vobj, "ShowUnit"): + show_unit = vobj.ShowUnit + + # Set text element showing the value of the dimension + length = (self.p3 - self.p2).Length + unit = None + + if hasattr(vobj, "UnitOverride"): + unit = vobj.UnitOverride + + # Special representation if we use 'Building US' scheme + u_params = App.ParamGet("User parameter:BaseApp/Preferences/Units") + if u_params.GetInt("UserSchema", 0) == 5: + s = App.Units.Quantity(length, App.Units.Length).UserString + self.string = s.replace("' ", "'- ") # feet + self.string = s.replace("+", " ") + elif hasattr(vobj, "Decimals"): + self.string = units.display_external(length, + vobj.Decimals, + 'Length', show_unit, unit) + else: + self.string = units.display_external(length, + None, + 'Length', show_unit, unit) + + if hasattr(vobj, "Override") and vobj.Override: + self.string = vobj.Override.replace("$dim", self.string) + + self.text.string = utils.string_encode_coin(self.string) + self.text3d.string = utils.string_encode_coin(self.string) + + # Set the lines + if m == "3D": + # Calculate the spacing of the text + textsize = len(self.string) * vobj.FontSize.Value / 4.0 + spacing = (self.p3 - self.p2).Length/2.0 - textsize + + self.p2a = self.p2 + DraftVecUtils.scaleTo(self.p3 - self.p2, + spacing) + self.p2b = self.p3 + DraftVecUtils.scaleTo(self.p2 - self.p3, + spacing) + self.coords.point.setValues([[self.p1.x, self.p1.y, self.p1.z], + [self.p2.x, self.p2.y, self.p2.z], + [self.p2a.x, self.p2a.y, self.p2a.z], + [self.p2b.x, self.p2b.y, self.p2b.z], + [self.p3.x, self.p3.y, self.p3.z], + [self.p4.x, self.p4.y, self.p4.z]]) + # self.line.numVertices.setValues([3, 3]) + self.line.coordIndex.setValues(0, 7, (0, 1, 2, -1, 3, 4, 5)) + else: + self.coords.point.setValues([[self.p1.x, self.p1.y, self.p1.z], + [self.p2.x, self.p2.y, self.p2.z], + [self.p3.x, self.p3.y, self.p3.z], + [self.p4.x, self.p4.y, self.p4.z]]) + # self.line.numVertices.setValue(4) + self.line.coordIndex.setValues(0, 4, (0, 1, 2, 3)) def onChanged(self, vobj, prop): """Execute when a view property is changed.""" super(ViewProviderLinearDimension, self).onChanged(vobj, prop) - if prop == "ScaleMultiplier" and hasattr(vobj, "ScaleMultiplier"): - # update all dimension values - if hasattr(self,"font"): + obj = vobj.Object + properties = vobj.PropertiesList + + if prop == "ScaleMultiplier" and "ScaleMultiplier" in properties: + # Update all dimension values + if hasattr(self, "font"): self.font.size = vobj.FontSize.Value * vobj.ScaleMultiplier - if hasattr(self,"font3d"): - self.font3d.size = vobj.FontSize.Value * 100 * vobj.ScaleMultiplier - if hasattr(self,"node") and hasattr(self,"p2") and hasattr(vobj,"ArrowSize"): + if hasattr(self, "font3d"): + self.font3d.size = \ + vobj.FontSize.Value * 10 * vobj.ScaleMultiplier + if (hasattr(self, "node") and hasattr(self, "p2") + and "ArrowSize" in properties): self.remove_dim_arrows() self.draw_dim_arrows(vobj) - if hasattr(vobj,"DimOvershoot"): + if "DimOvershoot" in properties: self.remove_dim_overshoot() self.draw_dim_overshoot(vobj) - if hasattr(vobj,"ExtOvershoot"): + if "ExtOvershoot" in properties: self.remove_ext_overshoot() self.draw_ext_overshoot(vobj) - self.updateData(vobj.Object,"Start") - vobj.Object.touch() - - elif (prop == "FontSize") and hasattr(vobj,"FontSize") and hasattr(vobj, "ScaleMultiplier"): - if hasattr(self,"font"): + + self.updateData(obj, "Start") + obj.touch() + + elif (prop == "FontSize" and "FontSize" in properties + and "ScaleMultiplier" in properties): + if hasattr(self, "font"): self.font.size = vobj.FontSize.Value * vobj.ScaleMultiplier - if hasattr(self,"font3d"): - self.font3d.size = vobj.FontSize.Value * 100 * vobj.ScaleMultiplier - vobj.Object.touch() - - elif (prop == "FontName") and hasattr(vobj,"FontName"): - if hasattr(self,"font") and hasattr(self,"font3d"): - self.font.name = self.font3d.name = str(vobj.FontName) - vobj.Object.touch() - - elif (prop == "LineColor") and hasattr(vobj,"LineColor"): - if hasattr(self,"color"): - c = vobj.LineColor - self.color.rgb.setValue(c[0],c[1],c[2]) - - elif (prop == "LineWidth") and hasattr(vobj,"LineWidth"): - if hasattr(self,"drawstyle"): - self.drawstyle.lineWidth = vobj.LineWidth - - elif (prop in ["ArrowSize","ArrowType"]) and hasattr(vobj,"ArrowSize") and hasattr(vobj, "ScaleMultiplier"): - if hasattr(self,"node") and hasattr(self,"p2"): - self.remove_dim_arrows() - self.draw_dim_arrows(vobj) - vobj.Object.touch() - - elif (prop == "DimOvershoot") and hasattr(vobj,"DimOvershoot") and hasattr(vobj, "ScaleMultiplier"): + if hasattr(self, "font3d"): + self.font3d.size = \ + vobj.FontSize.Value * 10 * vobj.ScaleMultiplier + obj.touch() + + elif (prop == "FontName" and "FontName" in properties + and hasattr(self, "font") and hasattr(self, "font3d")): + self.font.name = str(vobj.FontName) + self.font3d.name = str(vobj.FontName) + obj.touch() + + elif (prop == "LineColor" and "LineColor" in properties + and hasattr(self, "color")): + col = vobj.LineColor + self.color.rgb.setValue(col[0], col[1], col[2]) + + elif (prop == "LineWidth" and "LineWidth" in properties + and hasattr(self, "drawstyle")): + self.drawstyle.lineWidth = vobj.LineWidth + + elif (prop in ("ArrowSize", "ArrowType") + and "ArrowSize" in properties + and "ScaleMultiplier" in properties + and hasattr(self, "node") and hasattr(self, "p2")): + self.remove_dim_arrows() + self.draw_dim_arrows(vobj) + obj.touch() + + elif (prop == "DimOvershoot" + and "DimOvershoot" in properties + and "ScaleMultiplier" in properties): self.remove_dim_overshoot() self.draw_dim_overshoot(vobj) - vobj.Object.touch() - - elif (prop == "ExtOvershoot") and hasattr(vobj,"ExtOvershoot") and hasattr(vobj, "ScaleMultiplier"): + obj.touch() + + elif (prop == "ExtOvershoot" + and "ExtOvershoot" in properties + and "ScaleMultiplier" in properties): self.remove_ext_overshoot() self.draw_ext_overshoot(vobj) - vobj.Object.touch() - - elif (prop == "ShowLine") and hasattr(vobj,"ShowLine"): + obj.touch() + + elif prop == "ShowLine" and "ShowLine" in properties: if vobj.ShowLine: self.lineswitch2.whichChild = -3 self.lineswitch3.whichChild = -3 @@ -656,17 +766,19 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase): self.lineswitch2.whichChild = -1 self.lineswitch3.whichChild = -1 else: - self.updateData(vobj.Object,"Start") - + self.updateData(obj, "Start") + def remove_dim_arrows(self): - # remove existing nodes + """Remove dimension arrows in the dimension lines. + + Remove the existing nodes. + """ self.node.removeChild(self.marks) self.node3d.removeChild(self.marks) def draw_dim_arrows(self, vobj): - from pivy import coin - - if not hasattr(vobj,"ArrowType"): + """Draw dimension arrows.""" + if not hasattr(vobj, "ArrowType"): return if self.p3.x < self.p2.x: @@ -674,105 +786,112 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase): else: inv = True - # set scale + # Set scale symbol = utils.ARROW_TYPES.index(vobj.ArrowType) s = vobj.ArrowSize.Value * vobj.ScaleMultiplier - self.trans1.scaleFactor.setValue((s,s,s)) - self.trans2.scaleFactor.setValue((s,s,s)) + self.trans1.scaleFactor.setValue((s, s, s)) + self.trans2.scaleFactor.setValue((s, s, s)) - - # set new nodes + # Set new nodes self.marks = coin.SoSeparator() self.marks.addChild(self.color) + s1 = coin.SoSeparator() if symbol == "Circle": s1.addChild(self.coord1) else: s1.addChild(self.trans1) - s1.addChild(gui_utils.dim_symbol(symbol,invert=not(inv))) + + s1.addChild(gui_utils.dim_symbol(symbol, invert=not inv)) self.marks.addChild(s1) + s2 = coin.SoSeparator() if symbol == "Circle": s2.addChild(self.coord2) else: s2.addChild(self.trans2) - s2.addChild(gui_utils.dim_symbol(symbol,invert=inv)) + + s2.addChild(gui_utils.dim_symbol(symbol, invert=inv)) self.marks.addChild(s2) - self.node.insertChild(self.marks,2) - self.node3d.insertChild(self.marks,2) + + self.node.insertChild(self.marks, 2) + self.node3d.insertChild(self.marks, 2) def remove_dim_overshoot(self): + """Remove the dimension overshoot lines.""" self.node.removeChild(self.marksDimOvershoot) self.node3d.removeChild(self.marksDimOvershoot) - def draw_dim_overshoot(self, vobj): - from pivy import coin - - # set scale + """Draw dimension overshoot lines.""" + # Set scale s = vobj.DimOvershoot.Value * vobj.ScaleMultiplier - self.transDimOvershoot1.scaleFactor.setValue((s,s,s)) - self.transDimOvershoot2.scaleFactor.setValue((s,s,s)) + self.transDimOvershoot1.scaleFactor.setValue((s, s, s)) + self.transDimOvershoot2.scaleFactor.setValue((s, s, s)) - # remove existing nodes - - # set new nodes + # Remove existing nodes, and set new nodes self.marksDimOvershoot = coin.SoSeparator() if vobj.DimOvershoot.Value: self.marksDimOvershoot.addChild(self.color) + s1 = coin.SoSeparator() s1.addChild(self.transDimOvershoot1) - s1.addChild(gui_utils.dimDash((-1,0,0),(0,0,0))) + s1.addChild(gui_utils.dimDash((-1, 0, 0), (0, 0, 0))) self.marksDimOvershoot.addChild(s1) + s2 = coin.SoSeparator() s2.addChild(self.transDimOvershoot2) - s2.addChild(gui_utils.dimDash((0,0,0),(1,0,0))) + s2.addChild(gui_utils.dimDash((0, 0, 0), (1, 0, 0))) self.marksDimOvershoot.addChild(s2) - self.node.insertChild(self.marksDimOvershoot,2) - self.node3d.insertChild(self.marksDimOvershoot,2) - + self.node.insertChild(self.marksDimOvershoot, 2) + self.node3d.insertChild(self.marksDimOvershoot, 2) + def remove_ext_overshoot(self): + """Remove dimension extension overshoot lines.""" self.node.removeChild(self.marksExtOvershoot) self.node3d.removeChild(self.marksExtOvershoot) - def draw_ext_overshoot(self, vobj): - from pivy import coin - - # set scale + """Draw dimension extension overshoot lines.""" + # Set scale s = vobj.ExtOvershoot.Value * vobj.ScaleMultiplier - self.transExtOvershoot1.scaleFactor.setValue((s,s,s)) - self.transExtOvershoot2.scaleFactor.setValue((s,s,s)) + self.transExtOvershoot1.scaleFactor.setValue((s, s, s)) + self.transExtOvershoot2.scaleFactor.setValue((s, s, s)) - # set new nodes + # Set new nodes self.marksExtOvershoot = coin.SoSeparator() if vobj.ExtOvershoot.Value: self.marksExtOvershoot.addChild(self.color) s1 = coin.SoSeparator() s1.addChild(self.transExtOvershoot1) - s1.addChild(gui_utils.dimDash((0,0,0),(-1,0,0))) + s1.addChild(gui_utils.dimDash((0, 0, 0), (-1, 0, 0))) self.marksExtOvershoot.addChild(s1) + s2 = coin.SoSeparator() s2.addChild(self.transExtOvershoot2) - s2.addChild(gui_utils.dimDash((0,0,0),(-1,0,0))) + s2.addChild(gui_utils.dimDash((0, 0, 0), (-1, 0, 0))) self.marksExtOvershoot.addChild(s2) - self.node.insertChild(self.marksExtOvershoot,2) - self.node3d.insertChild(self.marksExtOvershoot,2) + + self.node.insertChild(self.marksExtOvershoot, 2) + self.node3d.insertChild(self.marksExtOvershoot, 2) def is_linked_to_circle(self): - _obj = self.Object - if _obj.LinkedGeometry and len(_obj.LinkedGeometry) == 1: - lobj = _obj.LinkedGeometry[0][0] - lsub = _obj.LinkedGeometry[0][1] - if len(lsub) == 1 and "Edge" in lsub[0]: - n = int(lsub[0][4:]) - 1 - edge = lobj.Shape.Edges[n] + """Return true if the dimension measures a circular edge.""" + obj = self.Object + if obj.LinkedGeometry and len(obj.LinkedGeometry) == 1: + linked_obj = obj.LinkedGeometry[0][0] + subelements = obj.LinkedGeometry[0][1] + if len(subelements) == 1 and "Edge" in subelements[0]: + sub = subelements[0] + index = int(sub[4:]) - 1 + edge = linked_obj.Shape.Edges[index] if DraftGeomUtils.geomType(edge) == "Circle": return True return False def getIcon(self): + """Return the path to the icon used by the viewprovider.""" if self.is_linked_to_circle(): return ":/icons/Draft_DimensionRadius.svg" return ":/icons/Draft_Dimension_Tree.svg"