コード例 #1
0
    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
コード例 #2
0
    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))