def execute(self, obj): """Execute when the object is created or recomputed. Set start point and end point according to the linked geometry and the number of subelements. If it has one subelement, we assume a straight edge or a circular edge. If it has two subelements, we assume a straight edge (two vertices). """ if obj.LinkedGeometry: if len(obj.LinkedGeometry) == 1: linked_obj = obj.LinkedGeometry[0][0] sub_list = obj.LinkedGeometry[0][1] if len(sub_list) == 1: # If it has one subelement, we assume an edge # that can be a straight line, or a circular edge subelement = sub_list[0] (obj.Start, obj.End) = measure_one_obj_edge(linked_obj, subelement, obj.Dimline, obj.Diameter) elif len(sub_list) == 2: # If it has two subelements, we assume a straight edge # that is measured by two vertices (obj.Start, obj.End) = measure_one_obj_vertices(linked_obj, sub_list) elif len(obj.LinkedGeometry) == 2: # If the list has two objects, it measures the distance # between the two vertices in those two objects (obj.Start, obj.End) = measure_two_objects(obj.LinkedGeometry[0], obj.LinkedGeometry[1]) # Update the distance property by comparing the floats # with the precision net_length = (obj.Start.sub(obj.End)).Length rounded_1 = round(obj.Distance.Value, utils.precision()) rounded_2 = round(net_length, utils.precision()) if rounded_1 != rounded_2: obj.Distance = net_length # The lines and text are created in the viewprovider, so we should # update it whenever the object is recomputed if App.GuiUp and obj.ViewObject: obj.ViewObject.update()
def update_arrow(self, obj, vobj): """Update the arrow tip of the line.""" if hasattr(self, "symbol"): if self.arrow.findChild(self.symbol) != -1: self.arrow.removeChild(self.symbol) s = utils.ARROW_TYPES.index(vobj.ArrowType) self.symbol = gui_utils.dim_symbol(s) self.arrow.addChild(self.symbol) prec = 10**(-utils.precision()) x_axis = App.Vector(1, 0, 0) target_dir = None # search in Points to get first point != to TargetPoint and use it # to get the target line direction for pnt in obj.Points[-2::-1]: if not pnt.isEqual(obj.Points[-1], prec): target_dir = pnt.sub(obj.Points[-1]) break if target_dir is None: target_dir = x_axis target_dir_xy = obj.Placement.Rotation.inverted() * target_dir angle = target_dir_xy.getAngle(x_axis) * App.Units.Radian axis = x_axis.cross(target_dir_xy) rot = App.Rotation(axis, angle) self.arrowpos.rotation.setValue((obj.Placement.Rotation * rot).Q) self.arrowpos.translation.setValue(obj.Points[-1])
def updateData(self, obj, prop): if hasattr(self, "arc"): from pivy import coin import Part, DraftGeomUtils import DraftGui arcsegs = 24 # calculate the arc data if DraftVecUtils.isNull(obj.Normal): norm = App.Vector(0, 0, 1) else: norm = obj.Normal radius = (obj.Dimline.sub(obj.Center)).Length self.circle = Part.makeCircle(radius, obj.Center, norm, obj.FirstAngle.Value, obj.LastAngle.Value) self.p2 = self.circle.Vertexes[0].Point self.p3 = self.circle.Vertexes[-1].Point mp = DraftGeomUtils.findMidpoint(self.circle.Edges[0]) ray = mp.sub(obj.Center) # set text value if obj.LastAngle.Value > obj.FirstAngle.Value: a = obj.LastAngle.Value - obj.FirstAngle.Value else: a = (360 - obj.FirstAngle.Value) + obj.LastAngle.Value su = True if hasattr(obj.ViewObject, "ShowUnit"): su = obj.ViewObject.ShowUnit if hasattr(obj.ViewObject, "Decimals"): self.string = DraftGui.displayExternal(a, obj.ViewObject.Decimals, 'Angle', su) else: self.string = DraftGui.displayExternal(a, None, 'Angle', su) 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) # check display mode 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)] # set the arc if m == "3D": # calculate the spacing of the text spacing = (len(self.string) * obj.ViewObject.FontSize.Value) / 8.0 pts1 = [] cut = None pts2 = [] for i in range(arcsegs + 1): p = self.circle.valueAt(self.circle.FirstParameter + ( (self.circle.LastParameter - self.circle.FirstParameter) / arcsegs) * i) if (p.sub(mp)).Length <= spacing: if cut is None: cut = i else: if cut is None: pts1.append([p.x, p.y, p.z]) else: pts2.append([p.x, p.y, p.z]) self.coords.point.setValues(pts1 + pts2) i1 = len(pts1) i2 = i1 + len(pts2) self.arc.coordIndex.setValues( 0, len(pts1) + len(pts2) + 1, list(range(len(pts1))) + [-1] + list(range(i1, i2))) if (len(pts1) >= 3) and (len(pts2) >= 3): self.circle1 = Part.Arc( App.Vector(pts1[0][0], pts1[0][1], pts1[0][2]), App.Vector(pts1[1][0], pts1[1][1], pts1[1][2]), App.Vector(pts1[-1][0], pts1[-1][1], pts1[-1][2])).toShape() self.circle2 = Part.Arc( App.Vector(pts2[0][0], pts2[0][1], pts2[0][2]), App.Vector(pts2[1][0], pts2[1][1], pts2[1][2]), App.Vector(pts2[-1][0], pts2[-1][1], pts2[-1][2])).toShape() else: pts = [] for i in range(arcsegs + 1): p = self.circle.valueAt(self.circle.FirstParameter + ( (self.circle.LastParameter - self.circle.FirstParameter) / arcsegs) * i) pts.append([p.x, p.y, p.z]) self.coords.point.setValues(pts) self.arc.coordIndex.setValues(0, arcsegs + 1, list(range(arcsegs + 1))) # set the arrow coords and rotation 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 small chords to make arrows look better arrowlength = 4 * obj.ViewObject.ArrowSize.Value u1 = (self.circle.valueAt(self.circle.FirstParameter + arrowlength) ).sub(self.circle.valueAt( self.circle.FirstParameter)).normalize() u2 = (self.circle.valueAt(self.circle.LastParameter)).sub( self.circle.valueAt(self.circle.LastParameter - arrowlength)).normalize() if hasattr(obj.ViewObject, "FlipArrows"): if obj.ViewObject.FlipArrows: u1 = u1.negative() u2 = u2.negative() w2 = self.circle.Curve.Axis w1 = w2.negative() v1 = w1.cross(u1) v2 = w2.cross(u2) q1 = App.Placement(DraftVecUtils.getPlaneRotation(u1, v1, w1)).Rotation.Q q2 = App.Placement(DraftVecUtils.getPlaneRotation(u2, v2, w2)).Rotation.Q self.trans1.rotation.setValue((q1[0], q1[1], q1[2], q1[3])) self.trans2.rotation.setValue((q2[0], q2[1], q2[2], q2[3])) # setting text pos & rot self.tbase = mp if hasattr(obj.ViewObject, "TextPosition"): if not DraftVecUtils.isNull(obj.ViewObject.TextPosition): self.tbase = obj.ViewObject.TextPosition u3 = ray.cross(norm).normalize() v3 = norm.cross(u3) r = App.Placement(DraftVecUtils.getPlaneRotation(u3, v3, norm)).Rotation offset = r.multVec(App.Vector(0, 1, 0)) if hasattr(obj.ViewObject, "TextSpacing"): offset = DraftVecUtils.scaleTo( offset, obj.ViewObject.TextSpacing.Value) else: offset = DraftVecUtils.scaleTo(offset, 0.05) if m == "3D": offset = offset.negative() self.tbase = self.tbase.add(offset) q = r.Q self.textpos.translation.setValue( [self.tbase.x, self.tbase.y, self.tbase.z]) self.textpos.rotation = coin.SbRotation(q[0], q[1], q[2], q[3]) # set the angle property if round(obj.Angle, utils.precision()) != round( a, utils.precision()): obj.Angle = a
def updateData(self, obj, prop): """Execute when a property from the Proxy class is changed.""" if not hasattr(self, "arc"): return arcsegs = 24 vobj = obj.ViewObject # Determine the orientation of the text by using a normal direction. # Also calculate the arc data. if DraftVecUtils.isNull(obj.Normal): norm = App.Vector(0, 0, 1) else: norm = obj.Normal radius = (obj.Dimline - obj.Center).Length self.circle = Part.makeCircle(radius, obj.Center, norm, obj.FirstAngle.Value, obj.LastAngle.Value) self.p2 = self.circle.Vertexes[0].Point self.p3 = self.circle.Vertexes[-1].Point midp = DraftGeomUtils.findMidpoint(self.circle.Edges[0]) ray = midp - obj.Center # Set text value if obj.LastAngle.Value > obj.FirstAngle.Value: angle = obj.LastAngle.Value - obj.FirstAngle.Value else: angle = (360 - obj.FirstAngle.Value) + obj.LastAngle.Value show_unit = True if hasattr(vobj, "ShowUnit"): show_unit = vobj.ShowUnit if hasattr(vobj, "Decimals"): self.string = units.display_external(angle, vobj.Decimals, 'Angle', show_unit) else: self.string = units.display_external(angle, None, 'Angle', show_unit) if 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) # 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)] # Set the arc first = self.circle.FirstParameter last = self.circle.LastParameter if m == "3D": # Calculate the spacing of the text spacing = len(self.string) * vobj.FontSize.Value / 8.0 pts1 = [] cut = None pts2 = [] for i in range(arcsegs + 1): p = self.circle.valueAt(first + (last - first) / arcsegs * i) if (p - midp).Length <= spacing: if cut is None: cut = i else: if cut is None: pts1.append([p.x, p.y, p.z]) else: pts2.append([p.x, p.y, p.z]) self.coords.point.setValues(pts1 + pts2) pts1_num = len(pts1) pts2_num = len(pts2) i1 = pts1_num i2 = i1 + pts2_num self.arc.coordIndex.setValues( 0, pts1_num + pts2_num + 1, list(range(pts1_num)) + [-1] + list(range(i1, i2))) if pts1_num >= 3 and pts2_num >= 3: self.circle1 = Part.Arc( App.Vector(pts1[0][0], pts1[0][1], pts1[0][2]), App.Vector(pts1[1][0], pts1[1][1], pts1[1][2]), App.Vector(pts1[-1][0], pts1[-1][1], pts1[-1][2])).toShape() self.circle2 = Part.Arc( App.Vector(pts2[0][0], pts2[0][1], pts2[0][2]), App.Vector(pts2[1][0], pts2[1][1], pts2[1][2]), App.Vector(pts2[-1][0], pts2[-1][1], pts2[-1][2])).toShape() else: pts = [] for i in range(arcsegs + 1): p = self.circle.valueAt(first + (last - first) / arcsegs * i) pts.append([p.x, p.y, p.z]) self.coords.point.setValues(pts) self.arc.coordIndex.setValues(0, arcsegs + 1, list(range(arcsegs + 1))) # Set the arrow coords and rotation 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 small chords to make arrows look better arrowlength = 4 * vobj.ArrowSize.Value u1 = (self.circle.valueAt(first + arrowlength) - self.circle.valueAt(first)).normalize() u2 = (self.circle.valueAt(last) - self.circle.valueAt(last - arrowlength)).normalize() if hasattr(vobj, "FlipArrows") and vobj.FlipArrows: u1 = u1.negative() u2 = u2.negative() w2 = self.circle.Curve.Axis w1 = w2.negative() v1 = w1.cross(u1) v2 = w2.cross(u2) _plane_rot_1 = DraftVecUtils.getPlaneRotation(u1, v1, w1) _plane_rot_2 = DraftVecUtils.getPlaneRotation(u2, v2, w2) q1 = App.Placement(_plane_rot_1).Rotation.Q q2 = App.Placement(_plane_rot_2).Rotation.Q self.trans1.rotation.setValue((q1[0], q1[1], q1[2], q1[3])) self.trans2.rotation.setValue((q2[0], q2[1], q2[2], q2[3])) # Set text position and rotation self.tbase = midp if (hasattr(vobj, "TextPosition") and not DraftVecUtils.isNull(vobj.TextPosition)): self.tbase = vobj.TextPosition u3 = ray.cross(norm).normalize() v3 = norm.cross(u3) _plane_rot_3 = DraftVecUtils.getPlaneRotation(u3, v3, norm) r = App.Placement(_plane_rot_3).Rotation offset = r.multVec(App.Vector(0, 1, 0)) if hasattr(vobj, "TextSpacing"): offset = DraftVecUtils.scaleTo(offset, vobj.TextSpacing.Value) else: offset = DraftVecUtils.scaleTo(offset, 0.05) if m == "3D": offset = offset.negative() self.tbase = self.tbase.add(offset) q = r.Q self.textpos.translation.setValue( [self.tbase.x, self.tbase.y, self.tbase.z]) self.textpos.rotation = coin.SbRotation(q[0], q[1], q[2], q[3]) # Set the angle property _round_1 = round(obj.Angle, utils.precision()) _round_2 = round(angle, utils.precision()) if _round_1 != _round_2: obj.Angle = angle