def getPlacement(entity): "returns a placement from the given entity" if DEBUG: print "getting placement ",entity if not entity: return None pl = None if entity.type == "IFCAXIS2PLACEMENT3D": x = getVector(entity.RefDirection) z = getVector(entity.Axis) y = z.cross(x) loc = getVector(entity.Location) m = DraftVecUtils.getPlaneRotation(x,y,z) pl = FreeCAD.Placement(m) pl.move(loc) elif entity.type == "IFCLOCALPLACEMENT": pl = getPlacement(entity.PlacementRelTo) relpl = getPlacement(entity.RelativePlacement) if pl and relpl: pl = relpl.multiply(pl) elif relpl: pl = relpl elif entity.type == "IFCCARTESIANPOINT": loc = getVector(entity) pl = FreeCAD.Placement() pl.move(loc) if DEBUG: print "made placement for",entity.id,":",pl return pl
def getRotation(self): """Return a placement describing the plane orientation only. If `FreeCAD.GuiUp` is `True`, that is, if the graphical interface is loaded, it will test if the active object is an `Arch` container and will calculate the placement accordingly. Returns ------- Base::Placement A placement, comprised of a `Base` (`Base::Vector3`), and a `Rotation` (`Base::Rotation`). """ m = DraftVecUtils.getPlaneRotation(self.u, self.v, self.axis) p = FreeCAD.Placement(m) # Arch active container if FreeCAD.GuiUp: import FreeCADGui if FreeCADGui.ActiveDocument: view = FreeCADGui.ActiveDocument.ActiveView if view and hasattr(view, "getActiveOject"): a = view.getActiveObject("Arch") if a: p = a.Placement.inverse().multiply(p) return p
def getPlacement(entity): "returns a placement from the given entity" # only used by internal parser if DEBUG: print "getting placement ", entity if not entity: return None pl = None if entity.type == "IFCAXIS2PLACEMENT3D": x = getVector(entity.RefDirection) z = getVector(entity.Axis) y = z.cross(x) loc = getVector(entity.Location) m = DraftVecUtils.getPlaneRotation(x, y, z) pl = FreeCAD.Placement(m) pl.move(loc) elif entity.type == "IFCLOCALPLACEMENT": pl = getPlacement(entity.PlacementRelTo) relpl = getPlacement(entity.RelativePlacement) if pl and relpl: pl = relpl.multiply(pl) elif relpl: pl = relpl elif entity.type == "IFCCARTESIANPOINT": loc = getVector(entity) pl = FreeCAD.Placement() pl.move(loc) if DEBUG: print "made placement for", entity.id, ":", pl return pl
def getPlacement(entity,scaling=1000): """returns a placement from the given entity""" if not entity: return None import DraftVecUtils pl = None if entity.is_a("IfcAxis2Placement3D"): x = getVector(entity.RefDirection,scaling) z = getVector(entity.Axis,scaling) if x and z: y = z.cross(x) m = DraftVecUtils.getPlaneRotation(x,y,z) pl = FreeCAD.Placement(m) else: pl = FreeCAD.Placement() loc = getVector(entity.Location,scaling) if loc: pl.move(loc) elif entity.is_a("IfcLocalPlacement"): pl = getPlacement(entity.PlacementRelTo,1) # original placement relpl = getPlacement(entity.RelativePlacement,1) # relative transf if pl and relpl: pl = pl.multiply(relpl) elif relpl: pl = relpl elif entity.is_a("IfcCartesianPoint"): loc = getVector(entity,scaling) pl = FreeCAD.Placement() pl.move(loc) if pl: pl.Base = FreeCAD.Vector(pl.Base).multiply(scaling) return pl
def getPlacement(entity): "returns a placement from the given entity" if DEBUG: print " getting placement ", entity if not entity: return None if IOC_ADVANCED: if isinstance(entity, int): entity = ifc.by_id(entity) entitytype = str(entity).split("=")[1].split("(")[0].upper() entityid = int(str(entity).split("=")[0].strip("#")) else: entitytype = entity.type.upper() entityid = entity.id pl = None if entitytype == "IFCAXIS2PLACEMENT3D": x = getVector(getAttr(entity, "RefDirection")) z = getVector(getAttr(entity, "Axis")) y = z.cross(x) loc = getVector(getAttr(entity, "Location")) m = DraftVecUtils.getPlaneRotation(x, y, z) pl = FreeCAD.Placement(m) pl.move(loc) elif entitytype == "IFCLOCALPLACEMENT": pl = getPlacement(getAttr(entity, "PlacementRelTo")) relpl = getPlacement(getAttr(entity, "RelativePlacement")) if pl and relpl: pl = relpl.multiply(pl) elif relpl: pl = relpl elif entitytype == "IFCCARTESIANPOINT": loc = getVector(entity) pl = FreeCAD.Placement() pl.move(loc) if DEBUG: print " made placement for ", entityid, ":", pl return pl
def getPlacement(entity): "returns a placement from the given entity" if DEBUG: print " getting placement ",entity if not entity: return None if IOC_ADVANCED: if isinstance(entity,int): entity = ifc.by_id(entity) entitytype = str(entity).split("=")[1].split("(")[0].upper() entityid = int(str(entity).split("=")[0].strip("#")) else: entitytype = entity.type.upper() entityid = entity.id pl = None if entitytype == "IFCAXIS2PLACEMENT3D": x = getVector(getAttr(entity,"RefDirection")) z = getVector(getAttr(entity,"Axis")) y = z.cross(x) loc = getVector(getAttr(entity,"Location")) m = DraftVecUtils.getPlaneRotation(x,y,z) pl = FreeCAD.Placement(m) pl.move(loc) elif entitytype == "IFCLOCALPLACEMENT": pl = getPlacement(getAttr(entity,"PlacementRelTo")) relpl = getPlacement(getAttr(entity,"RelativePlacement")) if pl and relpl: pl = relpl.multiply(pl) elif relpl: pl = relpl elif entitytype == "IFCCARTESIANPOINT": loc = getVector(entity) pl = FreeCAD.Placement() pl.move(loc) if DEBUG: print " made placement for ",entityid,":",pl return pl
def getRotation(self): "returns a placement describing the working plane orientation ONLY" m = DraftVecUtils.getPlaneRotation(self.u, self.v, self.axis) p = FreeCAD.Placement(m) # Arch active container if FreeCAD.GuiUp: import FreeCADGui a = FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch") if a: p = a.Placement.inverse().multiply(p) return p
def getRotation(self): "returns a placement describing the working plane orientation ONLY" m = DraftVecUtils.getPlaneRotation(self.u,self.v,self.axis) p = FreeCAD.Placement(m) # Arch active container if FreeCAD.GuiUp: import FreeCADGui if FreeCADGui.ActiveDocument.ActiveView: a = FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch") if a: p = a.Placement.inverse().multiply(p) return p
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) if vobj.ArrowType == "Circle": # TODO: fix behavior of the 'Circle' marker. # Instead of appearing at the tip of the line # the 'Circle' marker appears displaced and duplicated # a certain distance from the tip, which is the `TargetPoint`. # Somehow the translation is added to the position of the tip # resulting in a wrong value. # So the arrow position is reset; nevertheless, this doesn't # entirely fix the issue. coords2 = coin.SoCoordinate3() coords2.point.setValues([obj.Points[-1]]) self.arrow.addChild(coords2) self.arrowpos.translation.setValue((0, 0, 0)) else: self.arrowpos.translation.setValue(obj.Points[-1]) self.arrow.addChild(self.symbol) v1 = obj.Points[-2].sub(obj.Points[-1]) if not DraftVecUtils.isNull(v1): v1.normalize() v2 = App.Vector(0, 0, 1) if round(v2.getAngle(v1), 4) in [0, round(math.pi, 4)]: v2 = App.Vector(0, 1, 0) v3 = v1.cross(v2).negative() _rot_mat = DraftVecUtils.getPlaneRotation(v1, v3, v2) q = App.Placement(_rot_mat).Rotation.Q self.arrowpos.rotation.setValue((q[0], q[1], q[2], q[3]))
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): """called when the base object is changed""" import DraftGui if prop in ["Start", "End", "Dimline", "Direction"]: if obj.Start == obj.End: return if not hasattr(self, "node"): return import Part, DraftGeomUtils from pivy import coin # 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) 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 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)) else: proj = (self.p3.sub(self.p2)).cross(App.Vector(0, 0, 1)) # 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() 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) # 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))
def getRotation(self): "returns a placement describing the working plane orientation ONLY" m = DraftVecUtils.getPlaneRotation(self.u, self.v, self.axis) return FreeCAD.Placement(m)
def getRotation(self): "returns a placement describing the working plane orientation ONLY" m = DraftVecUtils.getPlaneRotation(self.u,self.v,self.axis) return FreeCAD.Placement(m)
def onChanged(self,vobj,prop): if prop == "ScaleMultiplier": if not hasattr(vobj,"ScaleMultiplier"): return if hasattr(vobj,"TextSize") and hasattr(vobj,"TextAlignment"): self.update_label(vobj) if hasattr(vobj,"ArrowSize"): s = vobj.ArrowSize.Value * vobj.ScaleMultiplier if s: self.arrowpos.scaleFactor.setValue((s,s,s)) elif prop == "LineColor": if hasattr(vobj,"LineColor"): l = vobj.LineColor self.matline.diffuseColor.setValue([l[0],l[1],l[2]]) elif prop == "TextColor": if hasattr(vobj,"TextColor"): l = vobj.TextColor self.mattext.diffuseColor.setValue([l[0],l[1],l[2]]) elif prop == "LineWidth": if hasattr(vobj,"LineWidth"): self.drawstyle.lineWidth = vobj.LineWidth elif (prop == "TextFont"): if hasattr(vobj,"TextFont"): self.font.name = vobj.TextFont.encode("utf8") elif prop in ["TextSize","TextAlignment"] and hasattr(vobj,"ScaleMultiplier"): if hasattr(vobj,"TextSize") and hasattr(vobj,"TextAlignment"): self.update_label(vobj) elif prop == "Line": if hasattr(vobj,"Line"): if vobj.Line: self.lineswitch.whichChild = 0 else: self.lineswitch.whichChild = -1 elif prop == "ArrowType": if hasattr(vobj,"ArrowType"): if len(vobj.Object.Points) > 1: 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) self.arrowpos.translation.setValue(vobj.Object.Points[-1]) v1 = vobj.Object.Points[-2].sub(vobj.Object.Points[-1]) if not DraftVecUtils.isNull(v1): v1.normalize() v2 = App.Vector(0,0,1) if round(v2.getAngle(v1),4) in [0,round(math.pi,4)]: v2 = App.Vector(0,1,0) v3 = v1.cross(v2).negative() q = App.Placement(DraftVecUtils.getPlaneRotation(v1,v3,v2)).Rotation.Q self.arrowpos.rotation.setValue((q[0],q[1],q[2],q[3])) elif prop == "ArrowSize": if hasattr(vobj,"ArrowSize") and hasattr(vobj,"ScaleMultiplier"): s = vobj.ArrowSize.Value * vobj.ScaleMultiplier if s: self.arrowpos.scaleFactor.setValue((s,s,s)) elif prop == "Frame": if hasattr(vobj,"Frame"): self.frame.coordIndex.deleteValues(0) if vobj.Frame == "Rectangle": tsize = self.getTextSize(vobj) pts = [] base = vobj.Object.Placement.Base.sub(App.Vector(self.textpos.translation.getValue().getValue())) pts.append(base.add(App.Vector(0,tsize[1]*3,0))) pts.append(pts[-1].add(App.Vector(-tsize[0]*6,0,0))) pts.append(pts[-1].add(App.Vector(0,-tsize[1]*6,0))) pts.append(pts[-1].add(App.Vector(tsize[0]*6,0,0))) pts.append(pts[0]) self.fcoords.point.setValues(pts) self.frame.coordIndex.setValues(0,len(pts),range(len(pts)))
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
def updateData(self, obj, prop): """Execute when a property from the Proxy class is changed. It only runs if `Start`, `End`, `Dimline`, or `Direction` changed. """ if prop not in ("Start", "End", "Dimline", "Direction"): return if obj.Start == obj.End: return if not hasattr(self, "node"): return 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: 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: self.p2 = self.p1 + proj.negative() self.p3 = self.p4 + proj.negative() else: self.p2 = self.p1 self.p3 = self.p4 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: 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)) # 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))