Example #1
0
    def doTasks():
        """Execute the commands stored in the lists.

        The lists are `itinerary`, `commitlist` and `afteritinerary`.
        """
        if _DEBUG:
            _msg("Debug: doing delayed tasks.\n"
                 "itinerary: {0}\n"
                 "commitlist: {1}\n"
                 "afteritinerary: {2}\n".format(todo.itinerary,
                                                todo.commitlist,
                                                todo.afteritinerary))
        try:
            for f, arg in todo.itinerary:
                try:
                    if _DEBUG_inner:
                        _msg("Debug: executing.\n" "function: {}\n".format(f))
                    if arg or (arg is False):
                        f(arg)
                    else:
                        f()
                except Exception:
                    _log(traceback.format_exc())
                    wrn = ("ToDo.doTasks, Unexpected error:\n"
                           "{0}\n"
                           "in {1}({2})".format(sys.exc_info()[0], f, arg))
                    _wrn(wrn)
        except ReferenceError:
            _wrn("Debug: ToDo.doTasks: "
                 "queue contains a deleted object, skipping")
        todo.itinerary = []

        if todo.commitlist:
            for name, func in todo.commitlist:
                if six.PY2:
                    if isinstance(name, six.text_type):
                        name = name.encode("utf8")
                if _DEBUG_inner:
                    _msg("Debug: committing.\n" "name: {}\n".format(name))
                try:
                    name = str(name)
                    FreeCAD.ActiveDocument.openTransaction(name)
                    if isinstance(func, list):
                        for string in func:
                            FreeCADGui.doCommand(string)
                    else:
                        func()
                    FreeCAD.ActiveDocument.commitTransaction()
                except Exception:
                    _log(traceback.format_exc())
                    wrn = ("ToDo.doTasks, Unexpected error:\n"
                           "{0}\n"
                           "in {1}".format(sys.exc_info()[0], func))
                    _wrn(wrn)
            # Restack Draft screen widgets after creation
            if hasattr(FreeCADGui, "Snapper"):
                FreeCADGui.Snapper.restack()
        todo.commitlist = []

        for f, arg in todo.afteritinerary:
            try:
                if _DEBUG_inner:
                    _msg("Debug: executing after.\n"
                         "function: {}\n".format(f))
                if arg:
                    f(arg)
                else:
                    f()
            except Exception:
                _log(traceback.format_exc())
                wrn = ("ToDo.doTasks, Unexpected error:\n"
                       "{0}\n"
                       "in {1}({2})".format(sys.exc_info()[0], f, arg))
                _wrn(wrn)
        todo.afteritinerary = []
Example #2
0
def get_svg(obj,
            scale=1, linewidth=0.35, fontsize=12,
            fillstyle="shape color", direction=None, linestyle=None,
            color=None, linespacing=None, techdraw=False, rotation=0,
            fillspaces=False, override=True):
    """Return a string containing an SVG representation of the object.

    Paramaeters
    -----------
    scale: float, optional
        It defaults to 1.
        It allows scaling line widths down, so they are resolution-independent.

    linewidth: float, optional
        It defaults to 0.35.

    fontsize: float, optional
        It defaults to 12, which is interpreted as `pt` unit (points).
        It is used if the given object contains any text.

    fillstyle: str, optional
        It defaults to 'shape color'.

    direction: Base::Vector3, optional
        It defaults to `None`.
        It is an arbitrary projection vector or a `WorkingPlane.Plane`
        instance.

    linestyle: optional
        It defaults to `None`.

    color: optional
        It defaults to `None`.

    linespacing: float, optional
        It defaults to `None`.

    techdraw: bool, optional
        It defaults to `False`.
        If it is `True`, it sets some options for generating SVG strings
        for displaying inside TechDraw.

    rotation: float, optional
        It defaults to 0.

    fillspaces: bool, optional
        It defaults to `False`.

    override: bool, optional
        It defaults to `True`.
    """
    # If this is a group, recursively call this function to gather
    # all the SVG strings from the contents of the group
    if hasattr(obj, "isDerivedFrom"):
        if (obj.isDerivedFrom("App::DocumentObjectGroup")
                or utils.get_type(obj) == "Layer"):
            svg = ""
            for child in obj.Group:
                svg += get_svg(child,
                               scale, linewidth, fontsize,
                               fillstyle, direction, linestyle,
                               color, linespacing, techdraw,
                               rotation, fillspaces, override)
            return svg

    pathdata = []
    svg = ""
    linewidth = float(linewidth)/scale
    if not override:
        if hasattr(obj, "ViewObject") and hasattr(obj.ViewObject, "LineWidth"):
            if hasattr(obj.ViewObject.LineWidth, "Value"):
                lw = obj.ViewObject.LineWidth.Value
            else:
                lw = obj.ViewObject.LineWidth
            linewidth = lw * linewidth

    fontsize = (float(fontsize)/scale)/2
    if linespacing:
        linespacing = float(linespacing)/scale
    else:
        linespacing = 0.5

    # print(obj.Label, "line spacing", linespacing, "scale", scale)

    # The number of times the dots are smaller than the arrow size
    pointratio = 0.75
    plane = None

    if direction:
        if isinstance(direction, App.Vector):
            if direction != App.Vector(0, 0, 0):
                plane = WorkingPlane.plane()
                plane.alignToPointAndAxis_SVG(App.Vector(0, 0, 0),
                                              direction.negative().negative(),
                                              0)
            else:
                raise ValueError("'direction' cannot be: Vector(0, 0, 0)")
        elif isinstance(direction, WorkingPlane.plane):
            plane = direction

    stroke = "#000000"
    if color and override:
        if "#" in color:
            stroke = color
        else:
            stroke = utils.get_rgb(color)
    elif App.GuiUp:
        # find print color
        pc = get_print_color(obj)
        if pc:
            stroke = utils.get_rgb(pc)
        # get line color
        elif hasattr(obj, "ViewObject"):
            if hasattr(obj.ViewObject, "LineColor"):
                stroke = utils.get_rgb(obj.ViewObject.LineColor)
            elif hasattr(obj.ViewObject, "TextColor"):
                stroke = utils.get_rgb(obj.ViewObject.TextColor)

    lstyle = "none"
    if override:
        lstyle = get_line_style(linestyle, scale)
    else:
        if hasattr(obj, "ViewObject") and hasattr(obj.ViewObject, "DrawStyle"):
            lstyle = get_line_style(obj.ViewObject.DrawStyle, scale)

    if not obj:
        pass

    elif isinstance(obj, Part.Shape):
        svg = _svg_shape(svg, obj, plane,
                         fillstyle, pathdata, stroke, linewidth, lstyle)

    elif utils.get_type(obj) in ["Dimension", "LinearDimension"]:
        svg = _svg_dimension(obj, plane, scale, linewidth, fontsize,
                             stroke, pointratio, techdraw, rotation)

    elif utils.get_type(obj) == "AngularDimension":
        if not App.GuiUp:
            _wrn("Export of dimensions to SVG is only available in GUI mode")

        if App.GuiUp:
            if obj.ViewObject.Proxy:
                if hasattr(obj.ViewObject.Proxy, "circle"):
                    prx = obj.ViewObject.Proxy

                    # drawing arc
                    fill = "none"
                    if obj.ViewObject.DisplayMode == "2D":
                        svg += get_path(obj, plane,
                                        fill, pathdata, stroke, linewidth,
                                        lstyle, fill_opacity=None,
                                        edges=[prx.circle])
                    else:
                        if hasattr(prx, "circle1"):
                            svg += get_path(obj, plane,
                                            fill, pathdata, stroke, linewidth,
                                            lstyle, fill_opacity=None,
                                            edges=[prx.circle1])
                            svg += get_path(obj, plane,
                                            fill, pathdata, stroke, linewidth,
                                            lstyle, fill_opacity=None,
                                            edges=[prx.circle2])
                        else:
                            svg += get_path(obj, plane,
                                            fill, pathdata, stroke, linewidth,
                                            lstyle, fill_opacity=None,
                                            edges=[prx.circle])

                    # drawing arrows
                    if hasattr(obj.ViewObject, "ArrowType"):
                        p2 = get_proj(prx.p2, plane)
                        p3 = get_proj(prx.p3, plane)
                        arrowsize = obj.ViewObject.ArrowSize.Value/pointratio
                        arrowlength = 4*obj.ViewObject.ArrowSize.Value

                        _v1a = prx.circle.valueAt(prx.circle.FirstParameter
                                                  + arrowlength)
                        _v1b = prx.circle.valueAt(prx.circle.FirstParameter)

                        _v2a = prx.circle.valueAt(prx.circle.LastParameter
                                                  - arrowlength)
                        _v2b = prx.circle.valueAt(prx.circle.LastParameter)

                        u1 = get_proj(_v1a - _v1b, plane)
                        u2 = get_proj(_v2a - _v2b, plane)
                        angle1 = -DraftVecUtils.angle(u1)
                        angle2 = -DraftVecUtils.angle(u2)

                        if hasattr(obj.ViewObject, "FlipArrows"):
                            if obj.ViewObject.FlipArrows:
                                angle1 = angle1 + math.pi
                                angle2 = angle2 + math.pi

                        svg += get_arrow(obj,
                                         obj.ViewObject.ArrowType,
                                         p2, arrowsize, stroke, linewidth,
                                         angle1)
                        svg += get_arrow(obj,
                                         obj.ViewObject.ArrowType,
                                         p3, arrowsize, stroke, linewidth,
                                         angle2)

                    # drawing text
                    if obj.ViewObject.DisplayMode == "2D":
                        _diff = (prx.circle.LastParameter
                                 - prx.circle.FirstParameter)
                        t = prx.circle.tangentAt(prx.circle.FirstParameter
                                                 + _diff/2.0)
                        t = get_proj(t, plane)
                        tangle = DraftVecUtils.angle(t)
                        if (tangle <= -math.pi/2) or (tangle > math.pi/2):
                            tangle = tangle + math.pi

                        _diff = (prx.circle.LastParameter
                                 - prx.circle.FirstParameter)
                        _va = prx.circle.valueAt(prx.circle.FirstParameter
                                                 + _diff/2.0)
                        tbase = get_proj(_va, plane)

                        _v = App.Vector(0, 2.0/scale, 0)
                        tbase = tbase + DraftVecUtils.rotate(_v, tangle)
                        # print(tbase)
                    else:
                        tangle = 0
                        tbase = get_proj(prx.tbase, plane)

                    svg += svgtext.get_text(plane, techdraw,
                                            stroke, fontsize,
                                            obj.ViewObject.FontName,
                                            tangle, tbase, prx.string)

    elif utils.get_type(obj) == "Label":
        if getattr(obj.ViewObject, "Line", True):
            # Some Labels may have no Line property
            # Draw multisegment line
            proj_points = list(map(lambda x: get_proj(x, plane), obj.Points))
            path_dir_list = [format_point(proj_points[0], action='M')]
            path_dir_list += map(format_point, proj_points[1:])
            path_dir_str = " ".join(path_dir_list)

            svg_path = '<path '
            svg_path += 'fill="none" '
            svg_path += 'stroke="{}" '.format(stroke)
            svg_path += 'stroke-width="{}" '.format(linewidth)
            svg_path += 'd="{}"'.format(path_dir_str)
            svg_path += '/>'
            svg += svg_path

            # Draw arrow.
            # We are different here from 3D view
            # if Line is set to 'off', no arrow is drawn
            if hasattr(obj.ViewObject, "ArrowType") and len(obj.Points) >= 2:
                last_segment = App.Vector(obj.Points[-1] - obj.Points[-2])
                _v = get_proj(last_segment, plane)
                angle = -DraftVecUtils.angle(_v) + math.pi
                svg += get_arrow(obj,
                                 obj.ViewObject.ArrowType,
                                 proj_points[-1],
                                 obj.ViewObject.ArrowSize.Value/pointratio,
                                 stroke, linewidth, angle)

        if not App.GuiUp:
            _wrn("Export of texts to SVG is only available in GUI mode")

        # print text
        if App.GuiUp:
            fontname = obj.ViewObject.TextFont
            position = get_proj(obj.Placement.Base, plane)
            rotation = obj.Placement.Rotation
            justification = obj.ViewObject.TextAlignment
            text = obj.Text
            svg += svgtext.get_text(plane, techdraw,
                                    stroke, fontsize, fontname,
                                    rotation, position, text,
                                    linespacing, justification)

    elif utils.get_type(obj) in ["Annotation", "DraftText", "Text"]:
        # returns an svg representation of a document annotation
        if not App.GuiUp:
            _wrn("Export of texts to SVG is only available in GUI mode")

        if App.GuiUp:
            n = obj.ViewObject.FontName
            if utils.get_type(obj) == "Annotation":
                p = get_proj(obj.Position, plane)
                r = obj.ViewObject.Rotation.getValueAs("rad")
                t = obj.LabelText
            else:  # DraftText (old) or Text (new, 0.19)
                p = get_proj(obj.Placement.Base, plane)
                r = obj.Placement.Rotation
                t = obj.Text

            j = obj.ViewObject.Justification
            svg += svgtext.get_text(plane, techdraw,
                                    stroke, fontsize, n,
                                    r, p, t,
                                    linespacing, j)

    elif utils.get_type(obj) == "Axis":
        # returns the SVG representation of an Arch Axis system
        if not App.GuiUp:
            _wrn("Export of axes to SVG is only available in GUI mode")

        if App.GuiUp:
            vobj = obj.ViewObject
            lorig = lstyle
            fill = 'none'
            rad = vobj.BubbleSize.Value/2
            n = 0
            for e in obj.Shape.Edges:
                lstyle = lorig
                svg += get_path(obj, plane,
                                fill, pathdata, stroke, linewidth, lstyle,
                                fill_opacity=None,
                                edges=[e])
                lstyle = "none"
                pos = ["Start"]
                if hasattr(vobj, "BubblePosition"):
                    if vobj.BubblePosition == "Both":
                        pos = ["Start", "End"]
                    else:
                        pos = [vobj.BubblePosition]
                for p in pos:
                    if p == "Start":
                        p1 = e.Vertexes[0].Point
                        p2 = e.Vertexes[1].Point
                    else:
                        p1 = e.Vertexes[1].Point
                        p2 = e.Vertexes[0].Point
                    dv = p2.sub(p1)
                    dv.normalize()
                    center = p2.add(dv.scale(rad, rad, rad))
                    svg += get_circle(plane,
                                      fill, stroke, linewidth, lstyle,
                                      Part.makeCircle(rad, center))
                    if (hasattr(vobj.Proxy, "bubbletexts")
                            and len(vobj.Proxy.bubbletexts) >= n):
                        bubb = vobj.Proxy.bubbletexts
                        svg += '<text '
                        svg += 'fill="{}" '.format(stroke)
                        svg += 'font-size="{}" '.format(rad)
                        svg += 'style="text-anchor:middle;'
                        svg += 'text-align:center;'
                        svg += 'font-family: sans;" '
                        svg += 'transform="'
                        svg += 'translate({},{}) '.format(center.x + rad/4.0,
                                                          center.y - rad/3.0)
                        svg += 'scale(1,-1)"> '
                        svg += '<tspan>'
                        svg += bubb[n].string.getValues()[0]
                        svg += '</tspan>\n'
                        svg += '</text>\n'
                        n += 1
            lstyle = lorig

    elif utils.get_type(obj) == "Pipe":
        fill = stroke
        if obj.Base and obj.Diameter:
            svg += get_path(obj, plane,
                            fill, pathdata, stroke, linewidth, lstyle,
                            fill_opacity=None,
                            edges=obj.Base.Shape.Edges)
        for f in obj.Shape.Faces:
            if len(f.Edges) == 1:
                if isinstance(f.Edges[0].Curve, Part.Circle):
                    svg += get_circle(plane,
                                      fill, stroke, linewidth, lstyle,
                                      f.Edges[0])

    elif utils.get_type(obj) == "Rebar":
        fill = "none"
        basewire = obj.Base.Shape.Wires[0].copy()
        # Not applying rounding because the results are not correct
        # if hasattr(obj, "Rounding") and obj.Rounding:
        #     basewire = DraftGeomUtils.filletWire(
        #         basewire, obj.Rounding * obj.Diameter.Value
        #     )
        wires = []
        for placement in obj.PlacementList:
            wire = basewire.copy()
            wire.Placement = placement.multiply(basewire.Placement)
            wires.append(wire)
        svg += get_path(obj, plane,
                        fill, pathdata, stroke, linewidth, lstyle,
                        fill_opacity=None,
                        wires=wires)

    elif utils.get_type(obj) == "PipeConnector":
        pass

    elif utils.get_type(obj) == "Space":
        fill_opacity = 1

        # returns an SVG fragment for the text of a space
        if not App.GuiUp:
            _wrn("Export of spaces to SVG is only available in GUI mode")

        if App.GuiUp:
            vobj = obj.ViewObject
            if fillspaces and hasattr(obj, "Proxy"):
                if not hasattr(obj.Proxy, "face"):
                    obj.Proxy.getArea(obj, notouch=True)
                if hasattr(obj.Proxy, "face"):
                    # setting fill
                    if App.GuiUp:
                        fill = utils.get_rgb(vobj.ShapeColor,
                                             testbw=False)
                        fill_opacity = 1 - vobj.Transparency / 100.0
                    else:
                        fill = "#888888"
                    svg += get_path(obj, plane,
                                    fill, pathdata, stroke, linewidth,
                                    lstyle, fill_opacity=fill_opacity,
                                    wires=[obj.Proxy.face.OuterWire])
            c = utils.get_rgb(vobj.TextColor)
            n = vobj.FontName
            a = 0
            if rotation != 0:
                a = math.radians(rotation)

            t1 = vobj.Proxy.text1.string.getValues()
            t2 = vobj.Proxy.text2.string.getValues()
            scale = vobj.FirstLine.Value/vobj.FontSize.Value
            f1 = fontsize * scale

            if round(plane.axis.getAngle(App.Vector(0,0,1)),2) not in [0,3.14]:
                # if not in XY view, place the label at center
                p2 = obj.Shape.CenterOfMass
            else:
                _v = vobj.Proxy.coords.translation.getValue().getValue()
                p2 = obj.Placement.multVec(App.Vector(_v))

            _h = vobj.Proxy.header.translation.getValue().getValue()
            lspc = App.Vector(_h)
            p1 = p2 + lspc
            j = vobj.TextAlign
            t3 = svgtext.get_text(plane, techdraw,
                                  c, f1, n,
                                  a, get_proj(p1, plane), t1,
                                  linespacing, j, flip=True)
            svg += t3
            if t2:
                ofs = App.Vector(0, -lspc.Length, 0)
                if a:
                    Z = App.Vector(0, 0, 1)
                    ofs = App.Rotation(Z, -rotation).multVec(ofs)
                t4 = svgtext.get_text(plane, techdraw,
                                      c, fontsize, n,
                                      a, get_proj(p1, plane).add(ofs), t2,
                                      linespacing, j, flip=True)
                svg += t4

    elif hasattr(obj, 'Shape'):
        # In the past we tested for a Part Feature
        # elif obj.isDerivedFrom('Part::Feature'):
        #
        # however, this doesn't work for App::Links; instead we
        # test for a 'Shape'. All Part::Features should have a Shape,
        # and App::Links can have one as well.
        if obj.Shape.isNull():
            return ''

        fill_opacity = 1
        # setting fill
        if obj.Shape.Faces:
            if App.GuiUp:
                try:
                    m = obj.ViewObject.DisplayMode
                except AttributeError:
                    m = None

                vobj = obj.ViewObject
                if m != "Wireframe":
                    if fillstyle == "shape color":
                        fill = utils.get_rgb(vobj.ShapeColor,
                                             testbw=False)
                        fill_opacity = 1 - vobj.Transparency / 100.0
                    elif fillstyle in ("none",None):
                        fill = "none"
                    else:
                        fill = 'url(#'+fillstyle+')'
                        svg += get_pattern(fillstyle)
                else:
                    fill = "none"
            else:
                fill = "#888888"
        else:
            fill = 'none'

        if len(obj.Shape.Vertexes) > 1:
            wiredEdges = []
            if obj.Shape.Faces:
                for i, f in enumerate(obj.Shape.Faces):
                    # place outer wire first
                    wires = [f.OuterWire]
                    wires.extend([w for w in f.Wires if w.hashCode() != f.OuterWire.hashCode()])
                    svg += get_path(obj, plane,
                                    fill, pathdata, stroke, linewidth, lstyle,
                                    fill_opacity=fill_opacity,
                                    wires=f.Wires,
                                    pathname='%s_f%04d' % (obj.Name, i))
                    wiredEdges.extend(f.Edges)
            else:
                for i, w in enumerate(obj.Shape.Wires):
                    svg += get_path(obj, plane,
                                    fill, pathdata, stroke, linewidth, lstyle,
                                    fill_opacity=fill_opacity,
                                    edges=w.Edges,
                                    pathname='%s_w%04d' % (obj.Name, i))
                    wiredEdges.extend(w.Edges)
            if len(wiredEdges) != len(obj.Shape.Edges):
                for i, e in enumerate(obj.Shape.Edges):
                    if DraftGeomUtils.findEdge(e, wiredEdges) is None:
                        svg += get_path(obj, plane,
                                        fill, pathdata, stroke, linewidth,
                                        lstyle, fill_opacity=fill_opacity,
                                        edges=[e],
                                        pathname='%s_nwe%04d' % (obj.Name, i))
        else:
            # closed circle or spline
            if obj.Shape.Edges:
                if isinstance(obj.Shape.Edges[0].Curve, Part.Circle):
                    svg = get_circle(plane,
                                     fill, stroke, linewidth, lstyle,
                                     obj.Shape.Edges[0])
                else:
                    svg = get_path(obj, plane,
                                   fill, pathdata, stroke, linewidth, lstyle,
                                   fill_opacity=fill_opacity,
                                   edges=obj.Shape.Edges)

        if (App.GuiUp
                and hasattr(obj.ViewObject, "EndArrow")
                and obj.ViewObject.EndArrow
                and hasattr(obj.ViewObject, "ArrowType")
                and len(obj.Shape.Vertexes) > 1):
            p1 = get_proj(obj.Shape.Vertexes[-1].Point, plane)
            p2 = get_proj(obj.Shape.Vertexes[-2].Point, plane)
            angle = -DraftVecUtils.angle(p2 - p1)

            arrowsize = obj.ViewObject.ArrowSize.Value/pointratio
            svg += get_arrow(obj,
                             obj.ViewObject.ArrowType,
                             p1, arrowsize, stroke, linewidth, angle)

    # techdraw expects bottom-to-top coordinates
    if techdraw:
        svg = '<g transform ="scale(1,-1)">\n    ' + svg + '</g>\n'

    return svg
Example #3
0
def _create_objects(doc=None,
                    font_file="/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
                    ):
    """Create the objects of the test file.

    Parameters
    ----------
    doc: App::Document, optional
        It defaults to `None`, which then defaults to the current
        active document, or creates a new document.
    """
    if not doc:
        doc = App.activeDocument()
    if not doc:
        doc = App.newDocument()

    # Line, wire, and fillet
    _msg(16 * "-")
    _msg("Line")
    Draft.make_line(Vector(0, 0, 0), Vector(500, 500, 0))
    t_xpos = -50
    t_ypos = -200
    _set_text(["Line"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("Wire")
    Draft.make_wire(
        [Vector(500, 0, 0),
         Vector(1000, 500, 0),
         Vector(1000, 1000, 0)])
    t_xpos += 500
    _set_text(["Wire"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("Fillet")
    line_h_1 = Draft.make_line(Vector(1500, 0, 0), Vector(1500, 500, 0))
    line_h_2 = Draft.make_line(Vector(1500, 500, 0), Vector(2000, 500, 0))
    if App.GuiUp:
        line_h_1.ViewObject.DrawStyle = "Dotted"
        line_h_2.ViewObject.DrawStyle = "Dotted"
    doc.recompute()

    Draft.make_fillet([line_h_1, line_h_2], 400)
    t_xpos += 900
    _set_text(["Fillet"], Vector(t_xpos, t_ypos, 0))

    # Circle, arc, arc by 3 points
    _msg(16 * "-")
    _msg("Circle")
    circle = Draft.make_circle(350)
    circle.Placement.Base = Vector(2500, 500, 0)
    t_xpos += 1050
    _set_text(["Circle"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("Circular arc")
    arc = Draft.make_circle(350, startangle=0, endangle=100)
    arc.Placement.Base = Vector(3200, 500, 0)
    t_xpos += 800
    _set_text(["Circular arc"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("Circular arc 3 points")
    Draft.make_arc_3points(
        [Vector(4600, 0, 0),
         Vector(4600, 800, 0),
         Vector(4000, 1000, 0)])
    t_xpos += 600
    _set_text(["Circular arc 3 points"], Vector(t_xpos, t_ypos, 0))

    # Ellipse, polygon, rectangle
    _msg(16 * "-")
    _msg("Ellipse")
    ellipse = Draft.make_ellipse(500, 300)
    ellipse.Placement.Base = Vector(5500, 250, 0)
    t_xpos += 1600
    _set_text(["Ellipse"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("Polygon")
    polygon = Draft.make_polygon(5, 250)
    polygon.Placement.Base = Vector(6500, 500, 0)
    t_xpos += 950
    _set_text(["Polygon"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("Rectangle")
    rectangle = Draft.make_rectangle(500, 1000, 0)
    rectangle.Placement.Base = Vector(7000, 0, 0)
    t_xpos += 650
    _set_text(["Rectangle"], Vector(t_xpos, t_ypos, 0))

    # Text
    _msg(16 * "-")
    _msg("Text")
    text = Draft.make_text(["Testing", "text"], Vector(7700, 500, 0))
    if App.GuiUp:
        text.ViewObject.FontSize = 100
    t_xpos += 700
    _set_text(["Text"], Vector(t_xpos, t_ypos, 0))

    # Linear dimension
    _msg(16 * "-")
    _msg("Linear dimension")
    line = Draft.make_wire([Vector(8700, 200, 0), Vector(8700, 1200, 0)])

    dimension = Draft.make_linear_dimension(Vector(8600, 200, 0),
                                            Vector(8600, 1000, 0),
                                            Vector(8400, 750, 0))
    if App.GuiUp:
        dimension.ViewObject.ArrowSize = 15
        dimension.ViewObject.ExtLines = 1000
        dimension.ViewObject.ExtOvershoot = 100
        dimension.ViewObject.DimOvershoot = 50
        dimension.ViewObject.FontSize = 100
        dimension.ViewObject.ShowUnit = False
    doc.recompute()

    dim_obj = Draft.make_linear_dimension_obj(line, 1, 2, Vector(9000, 750, 0))
    if App.GuiUp:
        dim_obj.ViewObject.ArrowSize = 15
        dim_obj.ViewObject.ArrowType = "Arrow"
        dim_obj.ViewObject.ExtLines = 100
        dim_obj.ViewObject.ExtOvershoot = 100
        dim_obj.ViewObject.DimOvershoot = 50
        dim_obj.ViewObject.FontSize = 100
        dim_obj.ViewObject.ShowUnit = False

    t_xpos += 680
    _set_text(["Dimension"], Vector(t_xpos, t_ypos, 0))

    # Radius and diameter dimension
    _msg(16 * "-")
    _msg("Radius and diameter dimension")
    arc_h = Draft.make_circle(500, startangle=0, endangle=90)
    arc_h.Placement.Base = Vector(9500, 0, 0)
    doc.recompute()

    dimension_r = Draft.make_radial_dimension_obj(arc_h, 1, "radius",
                                                  Vector(9750, 200, 0))
    if App.GuiUp:
        dimension_r.ViewObject.ArrowSize = 15
        dimension_r.ViewObject.FontSize = 100
        dimension_r.ViewObject.ShowUnit = False

    arc_h2 = Draft.make_circle(450, startangle=-120, endangle=80)
    arc_h2.Placement.Base = Vector(10000, 1000, 0)
    doc.recompute()

    dimension_d = Draft.make_radial_dimension_obj(arc_h2, 1, "diameter",
                                                  Vector(10750, 900, 0))
    if App.GuiUp:
        dimension_d.ViewObject.ArrowSize = 15
        dimension_d.ViewObject.FontSize = 100
        dimension_d.ViewObject.ShowUnit = False
    t_xpos += 950
    _set_text(["Radius dimension", "Diameter dimension"],
              Vector(t_xpos, t_ypos, 0))

    # Angular dimension
    _msg(16 * "-")
    _msg("Angular dimension")
    Draft.make_line(Vector(10500, 300, 0), Vector(11500, 1000, 0))
    Draft.make_line(Vector(10500, 300, 0), Vector(11500, 0, 0))
    angle1 = -20
    angle2 = 40
    dimension_a = Draft.make_angular_dimension(Vector(10500, 300, 0),
                                               [angle1, angle2],
                                               Vector(11500, 300, 0))
    if App.GuiUp:
        dimension_a.ViewObject.ArrowSize = 15
        dimension_a.ViewObject.FontSize = 100
    t_xpos += 1700
    _set_text(["Angle dimension"], Vector(t_xpos, t_ypos, 0))

    # BSpline
    _msg(16 * "-")
    _msg("BSpline")
    Draft.make_bspline([
        Vector(12500, 0, 0),
        Vector(12500, 500, 0),
        Vector(13000, 500, 0),
        Vector(13000, 1000, 0)
    ])
    t_xpos += 1500
    _set_text(["BSpline"], Vector(t_xpos, t_ypos, 0))

    # Point
    _msg(16 * "-")
    _msg("Point")
    point = Draft.make_point(13500, 500, 0)
    if App.GuiUp:
        point.ViewObject.PointSize = 10
    t_xpos += 900
    _set_text(["Point"], Vector(t_xpos, t_ypos, 0))

    # Shapestring
    _msg(16 * "-")
    _msg("Shapestring")
    try:
        shape_string = Draft.make_shapestring("Testing", font_file, 100)
        shape_string.Placement.Base = Vector(14000, 500)
    except Exception:
        _wrn("Shapestring could not be created")
        _wrn("Possible cause: the font file may not exist")
        _wrn(font_file)
        rect = Draft.make_rectangle(500, 100)
        rect.Placement.Base = Vector(14000, 500)
    t_xpos += 600
    _set_text(["Shapestring"], Vector(t_xpos, t_ypos, 0))

    # Facebinder
    _msg(16 * "-")
    _msg("Facebinder")
    box = doc.addObject("Part::Box", "Cube")
    box.Length = 200
    box.Width = 500
    box.Height = 100
    box.Placement.Base = Vector(15000, 0, 0)
    if App.GuiUp:
        box.ViewObject.Visibility = False

    facebinder = Draft.make_facebinder([(box, ("Face1", "Face3", "Face6"))])
    facebinder.Extrusion = 10
    t_xpos += 780
    _set_text(["Facebinder"], Vector(t_xpos, t_ypos, 0))

    # Cubic bezier curve, n-degree bezier curve
    _msg(16 * "-")
    _msg("Cubic bezier")
    Draft.make_bezcurve([
        Vector(15500, 0, 0),
        Vector(15578, 485, 0),
        Vector(15879, 154, 0),
        Vector(15975, 400, 0),
        Vector(16070, 668, 0),
        Vector(16423, 925, 0),
        Vector(16500, 500, 0)
    ],
                        degree=3)
    t_xpos += 680
    _set_text(["Cubic bezier"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("N-degree bezier")
    Draft.make_bezcurve([
        Vector(16500, 0, 0),
        Vector(17000, 500, 0),
        Vector(17500, 500, 0),
        Vector(17500, 1000, 0),
        Vector(17000, 1000, 0),
        Vector(17063, 1256, 0),
        Vector(17732, 1227, 0),
        Vector(17790, 720, 0),
        Vector(17702, 242, 0)
    ])
    t_xpos += 1200
    _set_text(["n-Bezier"], Vector(t_xpos, t_ypos, 0))

    # Label
    _msg(16 * "-")
    _msg("Label")
    place = App.Placement(Vector(18500, 500, 0), App.Rotation())
    label = Draft.make_label(target_point=Vector(18000, 0, 0),
                             placement=place,
                             custom_text="Example label",
                             distance=-250)
    label.Text = "Testing"
    if App.GuiUp:
        label.ViewObject.ArrowSize = 15
        label.ViewObject.TextSize = 100
    doc.recompute()
    t_xpos += 1200
    _set_text(["Label"], Vector(t_xpos, t_ypos, 0))

    # Orthogonal array and orthogonal link array
    _msg(16 * "-")
    _msg("Orthogonal array")
    rect_h = Draft.make_rectangle(500, 500)
    rect_h.Placement.Base = Vector(1500, 2500, 0)
    if App.GuiUp:
        rect_h.ViewObject.Visibility = False

    Draft.make_ortho_array(rect_h,
                           Vector(600, 0, 0),
                           Vector(0, 600, 0),
                           Vector(0, 0, 0),
                           3,
                           2,
                           1,
                           use_link=False)
    t_xpos = 1700
    t_ypos = 2200
    _set_text(["Array"], Vector(t_xpos, t_ypos, 0))

    rect_h_2 = Draft.make_rectangle(500, 100)
    rect_h_2.Placement.Base = Vector(1500, 5000, 0)
    if App.GuiUp:
        rect_h_2.ViewObject.Visibility = False

    _msg(16 * "-")
    _msg("Orthogonal link array")
    Draft.make_ortho_array(rect_h_2,
                           Vector(800, 0, 0),
                           Vector(0, 500, 0),
                           Vector(0, 0, 0),
                           2,
                           4,
                           1,
                           use_link=True)
    t_ypos += 2600
    _set_text(["Link array"], Vector(t_xpos, t_ypos, 0))

    # Polar array and polar link array
    _msg(16 * "-")
    _msg("Polar array")
    wire_h = Draft.make_wire([
        Vector(5500, 3000, 0),
        Vector(6000, 3500, 0),
        Vector(6000, 3200, 0),
        Vector(5800, 3200, 0)
    ])
    if App.GuiUp:
        wire_h.ViewObject.Visibility = False

    Draft.make_polar_array(wire_h,
                           8,
                           200,
                           Vector(5000, 3000, 0),
                           use_link=False)

    t_xpos = 4600
    t_ypos = 2200
    _set_text(["Polar array"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("Polar link array")
    wire_h_2 = Draft.make_wire([
        Vector(5500, 6000, 0),
        Vector(6000, 6000, 0),
        Vector(5800, 5700, 0),
        Vector(5800, 5750, 0)
    ])
    if App.GuiUp:
        wire_h_2.ViewObject.Visibility = False

    Draft.make_polar_array(wire_h_2,
                           8,
                           200,
                           Vector(5000, 6000, 0),
                           use_link=True)
    t_ypos += 3200
    _set_text(["Polar link array"], Vector(t_xpos, t_ypos, 0))

    # Circular array and circular link array
    _msg(16 * "-")
    _msg("Circular array")
    poly_h = Draft.make_polygon(5, 200)
    poly_h.Placement.Base = Vector(8000, 3000, 0)
    if App.GuiUp:
        poly_h.ViewObject.Visibility = False

    Draft.make_circular_array(poly_h,
                              500,
                              600,
                              3,
                              1,
                              Vector(0, 0, 1),
                              Vector(0, 0, 0),
                              use_link=False)
    t_xpos = 7700
    t_ypos = 1700
    _set_text(["Circular array"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("Circular link array")
    poly_h_2 = Draft.make_polygon(6, 150)
    poly_h_2.Placement.Base = Vector(8000, 6250, 0)
    if App.GuiUp:
        poly_h_2.ViewObject.Visibility = False

    Draft.make_circular_array(poly_h_2,
                              550,
                              450,
                              3,
                              1,
                              Vector(0, 0, 1),
                              Vector(0, 0, 0),
                              use_link=True)
    t_ypos += 3100
    _set_text(["Circular link array"], Vector(t_xpos, t_ypos, 0))

    # Path array and path link array
    _msg(16 * "-")
    _msg("Path array")
    poly_h = Draft.make_polygon(3, 250)
    poly_h.Placement.Base = Vector(10000, 3000, 0)
    if App.GuiUp:
        poly_h.ViewObject.Visibility = False

    bspline_path = Draft.make_bspline([
        Vector(10500, 2500, 0),
        Vector(11000, 3000, 0),
        Vector(11500, 3200, 0),
        Vector(12000, 4000, 0)
    ])

    Draft.make_path_array(poly_h, bspline_path, 5, use_link=False)
    t_xpos = 10400
    t_ypos = 2200
    _set_text(["Path array"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("Path link array")
    poly_h_2 = Draft.make_polygon(4, 200)
    poly_h_2.Placement.Base = Vector(10000, 5000, 0)
    if App.GuiUp:
        poly_h_2.ViewObject.Visibility = False

    bspline_path_2 = Draft.make_bspline([
        Vector(10500, 4500, 0),
        Vector(11000, 6800, 0),
        Vector(11500, 6000, 0),
        Vector(12000, 5200, 0)
    ])

    Draft.make_path_array(poly_h_2, bspline_path_2, 6, use_link=True)
    t_ypos += 2000
    _set_text(["Path link array"], Vector(t_xpos, t_ypos, 0))

    # Point array
    _msg(16 * "-")
    _msg("Point array")
    poly_h = Draft.make_polygon(3, 250)
    poly_h.Placement.Base = Vector(12500, 2500, 0)

    point_1 = Draft.make_point(13000, 3000, 0)
    point_2 = Draft.make_point(13000, 3500, 0)
    point_3 = Draft.make_point(14000, 2500, 0)
    point_4 = Draft.make_point(14000, 3000, 0)

    add_list, delete_list = Draft.upgrade([point_1, point_2, point_3, point_4])
    compound = add_list[0]
    if App.GuiUp:
        compound.ViewObject.PointSize = 5

    Draft.make_point_array(poly_h, compound)
    t_xpos = 13000
    t_ypos = 2200
    _set_text(["Point array"], Vector(t_xpos, t_ypos, 0))

    # Clone and mirror
    _msg(16 * "-")
    _msg("Clone")
    wire_h = Draft.make_wire([
        Vector(15000, 2500, 0),
        Vector(15200, 3000, 0),
        Vector(15500, 2500, 0),
        Vector(15200, 2300, 0)
    ])

    Draft.make_clone(wire_h, Vector(0, 1000, 0))
    t_xpos = 15000
    t_ypos = 2100
    _set_text(["Clone"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("Mirror")
    wire_h = Draft.make_wire([
        Vector(17000, 2500, 0),
        Vector(16500, 4000, 0),
        Vector(16000, 2700, 0),
        Vector(16500, 2500, 0),
        Vector(16700, 2700, 0)
    ])

    Draft.mirror(wire_h, Vector(17100, 2000, 0), Vector(17100, 4000, 0))
    t_xpos = 17000
    t_ypos = 2200
    _set_text(["Mirror"], Vector(t_xpos, t_ypos, 0))

    _msg(16 * "-")
    _msg("Layer")
    layer = Draft.make_layer("Custom layer",
                             line_color=(0.33, 0.0, 0.49),
                             shape_color=(0.56, 0.89, 0.56),
                             line_width=4,
                             transparency=50)
    cube = doc.addObject('Part::Box')
    cube.Length = 350
    cube.Width = 300
    cube.Height = 250
    cube.Placement.Base = Vector(14000, 5500, 0)

    cone = doc.addObject('Part::Cone')
    cone.Radius1 = 400
    cone.Height = 600
    cone.Angle = 270
    cone.Placement.Base = Vector(15000, 6000, 0)

    sphere = doc.addObject('Part::Sphere')
    sphere.Radius = 450
    sphere.Angle1 = -45
    sphere.Angle2 = 45
    sphere.Angle3 = 300
    sphere.Placement.Base = Vector(14000, 7000, 0)

    layer.Proxy.addObject(layer, cube)
    layer.Proxy.addObject(layer, cone)
    layer.Proxy.addObject(layer, sphere)

    t_xpos = 14000
    t_ypos = 5000
    _set_text(["Layer"], Vector(t_xpos, t_ypos, 0))
    doc.recompute()
Example #4
0
def get_arrow(obj,
              arrowtype, point, arrowsize, color, linewidth, angle=0):
    """Get the SVG representation from an arrow."""
    svg = ""

    if not App.GuiUp or not obj.ViewObject:
        return svg

    _cx_cy_r = 'cx="{}" cy="{}" r="{}"'.format(point.x, point.y, arrowsize)
    _rotate = 'rotate({},{},{})'.format(math.degrees(angle),
                                        point.x, point.y)
    _transl = 'translate({},{})'.format(point.x, point.y)
    _scale = 'scale({size},{size})'.format(size=arrowsize)
    _style = 'style="stroke-miterlimit:4;stroke-dasharray:none"'

    if obj.ViewObject.ArrowType == "Circle":
        svg += '<circle '
        svg += _cx_cy_r + ' '
        svg += 'fill="{}" stroke="{}" '.format("none", color)
        svg += 'style="stroke-width:{};'.format(linewidth)
        svg += 'stroke-miterlimit:4;stroke-dasharray:none" '
        svg += 'freecad:skip="1"'
        svg += '/>\n'
    elif obj.ViewObject.ArrowType == "Dot":
        svg += '<circle '
        svg += _cx_cy_r + ' '
        svg += 'fill="{}" stroke="{}" '.format(color, "none")
        svg += _style + ' '
        svg += 'freecad:skip="1"'
        svg += '/>\n'
    elif obj.ViewObject.ArrowType == "Arrow":
        svg += '<path '
        svg += 'transform="'
        svg += _rotate + ' '
        svg += _transl + ' '
        svg += _scale + '" '
        svg += 'freecad:skip="1" '
        svg += 'fill="{}" stroke="{}" '.format(color, "none")
        svg += _style + ' '
        svg += 'd="M 0 0 L 4 1 L 4 -1 Z"'
        svg += '/>\n'
    elif obj.ViewObject.ArrowType == "Tick":
        svg += '<path '
        svg += 'transform="'
        svg += _rotate + ' '
        svg += _transl + ' '
        svg += _scale + '" '
        svg += 'freecad:skip="1" '
        svg += 'fill="{}" stroke="{}" '.format(color, "none")
        svg += _style + ' '
        svg += 'd="M -1 -2 L 0 2 L 1 2 L 0 -2 Z"'
        svg += '/>\n'
    elif obj.ViewObject.ArrowType == "Tick-2":
        svg += '<line '
        svg += 'transform="'
        svg += 'rotate({},{},{}) '.format(math.degrees(angle) + 45,
                                          point.x, point.y)
        svg += _transl + '" '
        svg += 'freecad:skip="1" '
        svg += 'fill="{}" stroke="{}" '.format("none", color)
        svg += 'style="stroke-dasharray:none;stroke-linecap:square;'
        svg += 'stroke-width:{}" '.format(linewidth)
        svg += 'x1="-{}" y1="0" '.format(2 * arrowsize)
        svg += 'x2="{}" y2="0"'.format(2 * arrowsize)
        svg += '/>\n'
    else:
        _wrn("getSVG: arrow type not implemented")

    return svg
Example #5
0
def _svg_dimension(obj, plane, scale, linewidth, fontsize,
                   stroke, pointratio, techdraw, rotation):
    """Return the SVG representation of a linear dimension."""
    if not App.GuiUp:
        _wrn("'{}': SVG can only be generated "
             "in GUI mode".format(obj.Label))
        return ""

    if not hasattr(obj.ViewObject, "Proxy") or not obj.ViewObject.Proxy:
        _err("'{}': doesn't have Proxy, "
             "SVG cannot be generated".format(obj.Label))
        return ""

    vobj = obj.ViewObject
    prx = vobj.Proxy

    if not hasattr(prx, "p1"):
        _err("'{}': doesn't have points, "
             "SVG cannot be generated".format(obj.Label))
        return ""

    ts = len(prx.string) * vobj.FontSize.Value / 4.0
    rm = (prx.p3 - prx.p2).Length/2.0 - ts

    _diff32 = prx.p3 - prx.p2
    _diff23 = prx.p2 - prx.p3

    _v32 = DraftVecUtils.scaleTo(_diff32, rm)
    _v23 = DraftVecUtils.scaleTo(_diff23, rm)

    p2a = get_proj(prx.p2 + _v32, plane)
    p2b = get_proj(prx.p3 + _v23, plane)
    p1 = get_proj(prx.p1, plane)
    p2 = get_proj(prx.p2, plane)
    p3 = get_proj(prx.p3, plane)
    p4 = get_proj(prx.p4, plane)

    tbase = get_proj(prx.tbase, plane)
    r = prx.textpos.rotation.getValue().getValue()
    _rv = App.Rotation(r[0], r[1], r[2], r[3])
    rv = _rv.multVec(App.Vector(1, 0, 0))
    angle = -DraftVecUtils.angle(get_proj(rv, plane))
    # angle = -DraftVecUtils.angle(p3.sub(p2))

    svg = ''
    nolines = False
    if hasattr(vobj, "ShowLine"):
        if not vobj.ShowLine:
            nolines = True

    # drawing lines
    if not nolines:
        svg += '<path '

    if vobj.DisplayMode == "2D":
        tangle = angle
        if tangle > math.pi/2:
            tangle = tangle-math.pi
        # elif (tangle <= -math.pi/2) or (tangle > math.pi/2):
        #    tangle = tangle + math.pi

        if rotation != 0:
            # print("dim: tangle:", tangle,
            #       " rot: ", rotation,
            #       " text: ", prx.string)
            if abs(tangle + math.radians(rotation)) < 0.0001:
                tangle += math.pi
                _v = App.Vector(0, 2.0/scale, 0)
                _rot = DraftVecUtils.rotate(_v, tangle)
                tbase = tbase + _rot

        if not nolines:
            svg += 'd="M ' + str(p1.x) + ' ' + str(p1.y) + ' '
            svg += 'L ' + str(p2.x) + ' ' + str(p2.y) + ' '
            svg += 'L ' + str(p3.x) + ' ' + str(p3.y) + ' '
            svg += 'L ' + str(p4.x) + ' ' + str(p4.y) + '" '
    else:
        tangle = 0
        if rotation != 0:
            tangle = -math.radians(rotation)

        tbase = tbase + App.Vector(0, -2.0/scale, 0)
        if not nolines:
            svg += 'd="M ' + str(p1.x) + ' ' + str(p1.y) + ' '
            svg += 'L ' + str(p2.x) + ' ' + str(p2.y) + ' '
            svg += 'L ' + str(p2a.x) + ' ' + str(p2a.y) + ' '
            svg += 'M ' + str(p2b.x) + ' ' + str(p2b.y) + ' '
            svg += 'L ' + str(p3.x) + ' ' + str(p3.y) + ' '
            svg += 'L ' + str(p4.x) + ' ' + str(p4.y) + '" '

    if not nolines:
        svg += 'fill="none" stroke="'
        svg += stroke + '" '
        svg += 'stroke-width="' + str(linewidth) + ' px" '
        svg += 'style="stroke-width:' + str(linewidth)
        svg += ';stroke-miterlimit:4;stroke-dasharray:none" '
        svg += 'freecad:basepoint1="'+str(p1.x)+' '+str(p1.y)+'" '
        svg += 'freecad:basepoint2="'+str(p4.x)+' '+str(p4.y)+'" '
        svg += 'freecad:dimpoint="'+str(p2.x)+' '+str(p2.y)+'"'
        svg += '/>\n'

        # drawing dimension and extension lines overshoots
        if hasattr(vobj, "DimOvershoot") and vobj.DimOvershoot.Value:
            shootsize = vobj.DimOvershoot.Value/pointratio
            svg += get_overshoot(p2, shootsize, stroke,
                                 linewidth, angle)
            svg += get_overshoot(p3, shootsize, stroke,
                                 linewidth, angle + math.pi)

        if hasattr(vobj, "ExtOvershoot") and vobj.ExtOvershoot.Value:
            shootsize = vobj.ExtOvershoot.Value/pointratio
            shootangle = -DraftVecUtils.angle(p1 - p2)
            svg += get_overshoot(p2, shootsize, stroke,
                                 linewidth, shootangle)
            svg += get_overshoot(p3, shootsize, stroke,
                                 linewidth, shootangle)

        # drawing arrows
        if hasattr(vobj, "ArrowType"):
            arrowsize = vobj.ArrowSize.Value/pointratio
            if hasattr(vobj, "FlipArrows"):
                if vobj.FlipArrows:
                    angle = angle + math.pi

            svg += get_arrow(obj,
                             vobj.ArrowType,
                             p2, arrowsize, stroke, linewidth,
                             angle)
            svg += get_arrow(obj,
                             vobj.ArrowType,
                             p3, arrowsize, stroke, linewidth,
                             angle + math.pi)

    # drawing text
    svg += svgtext.get_text(plane, techdraw,
                            stroke, fontsize, vobj.FontName,
                            tangle, tbase, prx.string)

    return svg
Example #6
0
def dim_symbol(symbol=None, invert=False):
    """Return the specified dimension symbol.

    Parameters
    ----------
    symbol: int, optional
        It defaults to `None`, in which it gets the value from the parameter
        database, `get_param("dimsymbol", 0)`.

        A numerical value defines different markers
         * 0, `SoSphere`
         * 1, `SoMarkerSet` with a circle
         * 2, `SoSeparator` with a `soCone`
         * 3, `SoSeparator` with a `SoFaceSet`
         * 4, `SoSeparator` with a `SoLineSet`, calling `dim_dash`
         * Otherwise, `SoSphere`

    invert: bool, optional
        It defaults to `False`.
        If it is `True` and `symbol=2`, the cone will be rotated
        -90 degrees around the Z axis, otherwise the rotation is positive,
        +90 degrees.

    Returns
    -------
    Coin.SoNode
        A `Coin.SoSphere`, or `Coin.SoMarkerSet` (circle),
        or `Coin.SoSeparator` (cone, face, line)
        that will be used as a dimension symbol.
    """
    if symbol is None:
        symbol = utils.get_param("dimsymbol", 0)

    if symbol == 0:
        # marker = coin.SoMarkerSet()
        # marker.markerIndex = 80

        # Returning a sphere means that the bounding box will
        # be 3-dimensional; a marker will always be planar seen from any
        # orientation but it currently doesn't work correctly
        marker = coin.SoSphere()
        return marker
    elif symbol == 1:
        marker = coin.SoMarkerSet()
        # Should be the same as
        # marker.markerIndex = 10
        marker.markerIndex = Gui.getMarkerIndex("circle", 9)
        return marker
    elif symbol == 2:
        marker = coin.SoSeparator()
        t = coin.SoTransform()
        t.translation.setValue((0, -2, 0))
        t.center.setValue((0, 2, 0))
        if invert:
            t.rotation.setValue(coin.SbVec3f((0, 0, 1)), -math.pi / 2)
        else:
            t.rotation.setValue(coin.SbVec3f((0, 0, 1)), math.pi / 2)
        c = coin.SoCone()
        c.height.setValue(4)
        marker.addChild(t)
        marker.addChild(c)
        return marker
    elif symbol == 3:
        marker = coin.SoSeparator()
        c = coin.SoCoordinate3()
        c.point.setValues([(-1, -2, 0), (0, 2, 0), (1, 2, 0), (0, -2, 0)])
        f = coin.SoFaceSet()
        marker.addChild(c)
        marker.addChild(f)
        return marker
    elif symbol == 4:
        return dimDash((-1.5, -1.5, 0), (1.5, 1.5, 0))
    else:
        _wrn(_tr("Symbol not implemented. Use a default symbol."))
        return coin.SoSphere()
Example #7
0
def make_linear_dimension_obj(edge_object, i1=1, i2=2, dim_line=None):
    """Create a linear dimension from an object.

    Parameters
    ----------
    edge_object: Part::Feature
        The object which has an edge which will be measured.
        It must have a `Part::TopoShape`, and at least one element
        in `Shape.Vertexes`, to be able to measure a distance.

    i1: int, optional
        It defaults to `1`.
        It is the index of the first vertex in `edge_object` from which
        the measurement will be taken.
        The minimum value should be `1`, which will be interpreted
        as `'Vertex1'`.

        If the value is below `1`, it will be set to `1`.

    i2: int, optional
        It defaults to `2`, which will be converted to `'Vertex2'`.
        It is the index of the second vertex in `edge_object` that determines
        the endpoint of the measurement.

        If it is the same value as `i1`, the resulting measurement will be
        made from the origin `(0, 0, 0)` to the vertex indicated by `i1`.

        If the value is below `1`, it will be set to the last vertex
        in `edge_object`.

        Then to measure the first and last, this could be used
        ::
            make_linear_dimension_obj(edge_object, i1=1, i2=-1)

    dim_line: Base::Vector3
        It defaults to `None`.
        This is a point through which the extension of the dimension line
        will pass.
        This point controls how close or how far the dimension line is
        positioned from the measured segment in `edge_object`.

        If it is `None`, this point will be calculated from the intermediate
        distance betwwen the vertices defined by `i1` and `i2`.

    Returns
    -------
    App::FeaturePython
        A scripted object of type `'LinearDimension'`.
        This object does not have a `Shape` attribute, as the text and lines
        are created on screen by Coin (pivy).

    None
        If there is a problem it will return `None`.
    """
    _name = "make_linear_dimension_obj"
    utils.print_header(_name, "Linear dimension")

    found, doc = utils.find_doc(App.activeDocument())
    if not found:
        _err(_tr("No active document. Aborting."))
        return None

    if isinstance(edge_object, str):
        edge_object_str = edge_object

    if isinstance(edge_object, (list, tuple)):
        _msg("edge_object: {}".format(edge_object))
        _err(_tr("Wrong input: object must not be a list."))
        return None

    found, edge_object = utils.find_object(edge_object, doc)
    if not found:
        _msg("edge_object: {}".format(edge_object_str))
        _err(_tr("Wrong input: object not in document."))
        return None

    _msg("edge_object: {}".format(edge_object.Label))
    if not hasattr(edge_object, "Shape"):
        _err(_tr("Wrong input: object doesn't have a 'Shape' to measure."))
        return None
    if (not hasattr(edge_object.Shape, "Vertexes")
            or len(edge_object.Shape.Vertexes) < 1):
        _err(_tr("Wrong input: object doesn't have at least one element "
                 "in 'Vertexes' to use for measuring."))
        return None

    _msg("i1: {}".format(i1))
    try:
        utils.type_check([(i1, int)], name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be an integer."))
        return None

    if i1 < 1:
        i1 = 1
        _wrn(_tr("i1: values below 1 are not allowed; will be set to 1."))

    vx1 = edge_object.getSubObject("Vertex" + str(i1))
    if not vx1:
        _err(_tr("Wrong input: vertex not in object."))
        return None

    _msg("i2: {}".format(i2))
    try:
        utils.type_check([(i2, int)], name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be a vector."))
        return None

    if i2 < 1:
        i2 = len(edge_object.Shape.Vertexes)
        _wrn(_tr("i2: values below 1 are not allowed; "
                 "will be set to the last vertex in the object."))

    vx2 = edge_object.getSubObject("Vertex" + str(i2))
    if not vx2:
        _err(_tr("Wrong input: vertex not in object."))
        return None

    _msg("dim_line: {}".format(dim_line))
    if dim_line:
        try:
            utils.type_check([(dim_line, App.Vector)], name=_name)
        except TypeError:
            _err(_tr("Wrong input: must be a vector."))
            return None
    else:
        diff = vx2.Point.sub(vx1.Point)
        diff.multiply(0.5)
        dim_line = vx1.Point.add(diff)

    # TODO: the internal function expects an index starting with 0
    # so we need to decrease the value here.
    # This should be changed in the future in the internal function.
    i1 -= 1
    i2 -= 1

    new_obj = make_dimension(edge_object, i1, i2, dim_line)

    return new_obj
Example #8
0
def make_label(target_point=App.Vector(0, 0, 0),
               placement=App.Vector(30, 30, 0),
               target_object=None,
               subelements=None,
               label_type="Custom",
               custom_text="Label",
               direction="Horizontal",
               distance=-10,
               points=None):
    """Create a Label object containing different types of information.

    The current color and text height and font specified in preferences
    are used.

    Parameters
    ----------
    target_point: Base::Vector3, optional
        It defaults to the origin `App.Vector(0, 0, 0)`.
        This is the point which is pointed to by the label's leader line.
        This point can be adorned with a marker like an arrow or circle.

    placement: Base::Placement, Base::Vector3, or Base::Rotation, optional
        It defaults to `App.Vector(30, 30, 0)`.
        If it is provided, it defines the base point of the textual
        label.
        The input could be a full placement, just a vector indicating
        the translation, or just a rotation.

    target_object: Part::Feature or str, optional
        It defaults to `None`.
        If it exists it should be an object which will be used to provide
        information to the label, as long as `label_type` is different
        from `'Custom'`.

        If it is a string, it must be the `Label` of that object.
        Since a `Label` is not guaranteed to be unique in a document,
        it will use the first object found with this `Label`.

    subelements: str, optional
        It defaults to `None`.
        If `subelements` is provided, `target_object` should be provided
        as well, otherwise it is ignored.

        It should be a string indicating a subelement name, either
        `'VertexN'`, `'EdgeN'`, or `'FaceN'` which should exist
        within `target_object`.
        In this case `'N'` is an integer that indicates the specific number
        of vertex, edge, or face in `target_object`.

        Both `target_object` and `subelements` are used to link the label
        to a particular object, or to the particular vertex, edge, or face,
        and get information from them.
        ::
            make_label(..., target_object=App.ActiveDocument.Box)
            make_label(..., target_object="My box", subelements="Face3")

        These two parameters can be can be obtained from the `Gui::Selection`
        module.
        ::
            sel_object = Gui.Selection.getSelectionEx()[0]
            target_object = sel_object.Object
            subelements = sel_object.SubElementNames[0]

    label_type: str, optional
        It defaults to `'Custom'`.
        It indicates the type of information that will be shown in the label.
        See the get_label_types function in label.py for supported types.

        Only `'Custom'` allows you to manually set the text
        by defining `custom_text`. The other types take their information
        from the object included in `target`.

        - `'Position'` will show the base position of the target object,
          or of the indicated `'VertexN'` in `target`.
        - `'Length'` will show the `Length` of the target object's `Shape`,
          or of the indicated `'EdgeN'` in `target`.
        - `'Area'` will show the `Area` of the target object's `Shape`,
          or of the indicated `'FaceN'` in `target`.

    custom_text: str, or list of str, optional
        It defaults to `'Label'`.
        If it is a list, each element in the list represents a new text line.

        It is the text that will be displayed by the label when
        `label_type` is `'Custom'`.

    direction: str, optional
        It defaults to `'Horizontal'`.
        It can be `'Horizontal'`, `'Vertical'`, or `'Custom'`.
        It indicates the direction of the straight segment of the leader line
        that ends up next to the textual label.

        If `'Custom'` is selected, the leader line can be manually drawn
        by specifying the value of `points`.
        Normally, the leader line has only three points, but with `'Custom'`
        you can specify as many points as needed.

    distance: int, float, Base::Quantity, optional
        It defaults to -10.
        It indicates the length of the horizontal or vertical segment
        of the leader line.

        The leader line is composed of two segments, the first segment is
        inclined, while the second segment is either horizontal or vertical
        depending on the value of `direction`.
        ::
            T
            |
            |
            o------- L text

        The `oL` segment's length is defined by `distance`
        while the `oT` segment is automatically calculated depending
        on the values of `placement` (L) and `distance` (o).

        This `distance` is oriented, meaning that if it is positive
        the segment will be to the right and above of the textual
        label, depending on if `direction` is `'Horizontal'` or `'Vertical'`,
        respectively.
        If it is negative, the segment will be to the left
        and below of the text.

    points: list of Base::Vector3, optional
        It defaults to `None`.
        It is a list of vectors defining the shape of the leader line;
        the list must have at least two points.
        This argument must be used together with `direction='Custom'`
        to display this custom leader.

        However, notice that if the Label's `StraightDirection` property
        is later changed to `'Horizontal'` or `'Vertical'`,
        the custom point list will be overwritten with a new,
        automatically calculated three-point list.

        For the object to use custom points, `StraightDirection`
        must remain `'Custom'`, and then the `Points` property
        can be overwritten by a suitable list of points.

    Returns
    -------
    App::FeaturePython
        A scripted object of type `'Label'`.
        This object does not have a `Shape` attribute, as the text and lines
        are created on screen by Coin (pivy).

    None
        If there is a problem it will return `None`.
    """
    _name = "make_label"
    utils.print_header(_name, "Label")

    found, doc = utils.find_doc(App.activeDocument())
    if not found:
        _err(translate("draft", "No active document. Aborting."))
        return None

    _msg("target_point: {}".format(target_point))
    if not target_point:
        target_point = App.Vector(0, 0, 0)
    try:
        utils.type_check([(target_point, App.Vector)], name=_name)
    except TypeError:
        _err(translate("draft", "Wrong input: must be a vector."))
        return None

    _msg("placement: {}".format(placement))
    if not placement:
        placement = App.Placement()
    try:
        utils.type_check([(placement,
                           (App.Placement, App.Vector, App.Rotation))],
                         name=_name)
    except TypeError:
        _err(
            translate(
                "draft",
                "Wrong input: must be a placement, a vector, or a rotation."))
        return None

    # Convert the vector or rotation to a full placement
    if isinstance(placement, App.Vector):
        placement = App.Placement(placement, App.Rotation())
    elif isinstance(placement, App.Rotation):
        placement = App.Placement(App.Vector(), placement)

    if isinstance(target_object, str):
        target_object_str = target_object

    if target_object:
        if isinstance(target_object, (list, tuple)):
            _msg("target_object: {}".format(target_object))
            _err(translate("draft", "Wrong input: object must not be a list."))
            return None

        found, target_object = utils.find_object(target_object, doc)
        if not found:
            _msg("target_object: {}".format(target_object_str))
            _err(translate("draft", "Wrong input: object not in document."))
            return None

        _msg("target_object: {}".format(target_object.Label))

    if target_object and subelements:
        _msg("subelements: {}".format(subelements))
        try:
            # Make a list
            if isinstance(subelements, str):
                subelements = [subelements]

            utils.type_check([(subelements, (list, tuple, str))], name=_name)
        except TypeError:
            _err(
                translate(
                    "draft",
                    "Wrong input: must be a list or tuple of strings, or a single string."
                ))
            return None

        # The subelements list is used to build a special list
        # called a LinkSub, which includes the target_object
        # and the subelements.
        # Single: (target_object, "Edge1")
        # Multiple: (target_object, ("Edge1", "Edge2"))
        for sub in subelements:
            _sub = target_object.getSubObject(sub)
            if not _sub:
                _err("subelement: {}".format(sub))
                _err(
                    translate("draft",
                              "Wrong input: subelement not in object."))
                return None

    _msg("label_type: {}".format(label_type))
    if not label_type:
        label_type = "Custom"
    try:
        utils.type_check([(label_type, str)], name=_name)
    except TypeError:
        _err(translate("draft", "Wrong input: label_type must be a string."))
        return None

    types = label.get_label_types()
    if label_type not in types:
        _err(
            translate(
                "draft",
                "Wrong input: label_type must be one of the following: ") +
            str(types).strip("[]"))
        return None

    _msg("custom_text: {}".format(custom_text))
    if not custom_text:
        custom_text = "Label"
    try:
        utils.type_check([(custom_text, (str, list))], name=_name)
    except TypeError:
        _err(
            translate(
                "draft",
                "Wrong input: must be a list of strings or a single string."))
        return None

    if (type(custom_text) is list
            and not all(isinstance(element, str) for element in custom_text)):
        _err(
            translate(
                "draft",
                "Wrong input: must be a list of strings or a single string."))
        return None

    _msg("direction: {}".format(direction))
    if not direction:
        direction = "Horizontal"
    try:
        utils.type_check([(direction, str)], name=_name)
    except TypeError:
        _err(
            translate(
                "draft",
                "Wrong input: must be a string, 'Horizontal', 'Vertical', or 'Custom'."
            ))
        return None

    if direction not in ("Horizontal", "Vertical", "Custom"):
        _err(
            translate(
                "draft",
                "Wrong input: must be a string, 'Horizontal', 'Vertical', or 'Custom'."
            ))
        return None

    _msg("distance: {}".format(distance))
    if not distance:
        distance = 1
    try:
        utils.type_check([(distance, (int, float))], name=_name)
    except TypeError:
        _err(translate("draft", "Wrong input: must be a number."))
        return None

    if points:
        _msg("points: {}".format(points))

        _err_msg = translate(
            "draft", "Wrong input: must be a list of at least two vectors.")
        try:
            utils.type_check([(points, (tuple, list))], name=_name)
        except TypeError:
            _err(_err_msg)
            return None

        if len(points) < 2:
            _err(_err_msg)
            return None

        if not all(isinstance(p, App.Vector) for p in points):
            _err(_err_msg)
            return None

    new_obj = doc.addObject("App::FeaturePython", "dLabel")
    label.Label(new_obj)

    new_obj.TargetPoint = target_point
    new_obj.Placement = placement
    if target_object:
        if subelements:
            new_obj.Target = [target_object, subelements]
        else:
            new_obj.Target = [target_object, []]

    new_obj.LabelType = label_type
    new_obj.CustomText = custom_text

    new_obj.StraightDirection = direction
    new_obj.StraightDistance = distance
    if points:
        if direction != "Custom":
            _wrn(
                translate("draft",
                          "Direction is not 'Custom'; points won't be used."))
        new_obj.Points = points

    if App.GuiUp:
        ViewProviderLabel(new_obj.ViewObject)
        h = utils.get_param("textheight", 0.20)
        new_obj.ViewObject.TextSize = h

        gui_utils.format_object(new_obj)
        gui_utils.select(new_obj)

    return new_obj
Example #9
0
def get_dxf(obj, direction=None):
    """Return a DXF entity from the given object.

    If direction is given, the object is projected in 2D.
    """
    plane = None
    result = ""
    if (obj.isDerivedFrom("Drawing::View")
            or obj.isDerivedFrom("TechDraw::DrawView")):
        if obj.Source.isDerivedFrom("App::DocumentObjectGroup"):
            for o in obj.Source.Group:
                result += get_dxf(o, obj.Direction)
        else:
            result += get_dxf(obj.Source, obj.Direction)
        return result

    if direction and isinstance(direction, App.Vector):
        if direction != App.Vector(0, 0, 0):
            plane = WorkingPlane.Plane()
            plane.alignToPointAndAxis(App.Vector(0, 0, 0), direction)

    if utils.get_type(obj) in ("Dimension", "LinearDimension"):
        p1 = _get_proj(obj.Start, plane=plane)
        p2 = _get_proj(obj.End, plane=plane)
        p3 = _get_proj(obj.Dimline, plane=plane)
        result += "0\nDIMENSION\n8\n0\n62\n0\n3\nStandard\n70\n1\n"
        result += "10\n"+str(p3.x)+"\n20\n"+str(p3.y)+"\n30\n"+str(p3.z)+"\n"
        result += "13\n"+str(p1.x)+"\n23\n"+str(p1.y)+"\n33\n"+str(p1.z)+"\n"
        result += "14\n"+str(p2.x)+"\n24\n"+str(p2.y)+"\n34\n"+str(p2.z)+"\n"

    elif utils.get_type(obj) == "Annotation":
        # Only for App::Annotation
        p = _get_proj(obj.Position, plane=plane)
        count = 0
        for t in obj.LabeLtext:
            result += "0\nTEXT\n8\n0\n62\n0\n"
            result += "10\n"
            result += str(p.x) + "\n20\n"
            result += str(p.y + count) + "\n30\n"
            result += str(p.z) + "\n"
            result += "40\n1\n"
            result += "1\n" + str(t) + "\n"
            result += "7\nSTANDARD\n"
            count += 1

    elif hasattr(obj, 'Shape'):
        # TODO do this the Draft way, for ex. using polylines and rectangles
        if not direction:
            direction = App.Vector(0, 0, -1)

        if DraftVecUtils.isNull(direction):
            direction = App.Vector(0, 0, -1)

        try:
            d = TechDraw.projectToDXF(obj.Shape, direction)
        except Exception:
            # TODO: trap only specific exception.
            # Impossible to generate DXF from Shape? Which exception is throw?
            _wrn("get_dxf: "
                 "unable to project '{}' to {}".format(obj.Label, direction))
        else:
            result += d
    else:
        _wrn("get_dxf: unsupported object, '{}'".format(obj.Label))

    return result
Example #10
0
def make_ortho_array(obj,
                     v_x=App.Vector(10, 0, 0),
                     v_y=App.Vector(0, 10, 0),
                     v_z=App.Vector(0, 0, 10),
                     n_x=2,
                     n_y=2,
                     n_z=1,
                     use_link=True):
    """Create an orthogonal array from the given object.

    Parameters
    ----------
    obj: Part::Feature
        Any type of object that has a `Part::TopoShape`
        that can be duplicated.
        This means most 2D and 3D objects produced
        with any workbench.

    v_x, v_y, v_z: Base::Vector3, optional
        The vector indicating the vector displacement between two elements
        in the specified orthogonal direction X, Y, Z.

        By default:
        ::
            v_x = App.Vector(10, 0, 0)
            v_y = App.Vector(0, 10, 0)
            v_z = App.Vector(0, 0, 10)

        Given that this is a vectorial displacement
        the next object can appear displaced in one, two or three axes
        at the same time.

        For example
        ::
            v_x = App.Vector(10, 5, 0)

        means that the next element in the X direction will be displaced
        10 mm in X, 5 mm in Y, and 0 mm in Z.

        A traditional "rectangular" array is obtained when
        the displacement vector only has its corresponding component,
        like in the default case.

        If these values are entered as single numbers instead
        of vectors, the single value is expanded into a vector
        of the corresponding direction, and the other components are assumed
        to be zero.

        For example
        ::
            v_x = 15
            v_y = 10
            v_z = 1
        becomes
        ::
            v_x = App.Vector(15, 0, 0)
            v_y = App.Vector(0, 10, 0)
            v_z = App.Vector(0, 0, 1)

    n_x, n_y, n_z: int, optional
        The number of copies in the specified orthogonal direction X, Y, Z.
        This number includes the original object, therefore, it must be
        at least 1.

        The values of `n_x` and `n_y` default to 2,
        while `n_z` defaults to 1.
        This means the array by default is a planar array.

    use_link: bool, optional
        It defaults to `True`.
        If it is `True` the produced copies are not `Part::TopoShape` copies,
        but rather `App::Link` objects.
        The Links repeat the shape of the original `obj` exactly,
        and therefore the resulting array is more memory efficient.

        Also, when `use_link` is `True`, the `Fuse` property
        of the resulting array does not work; the array doesn't
        contain separate shapes, it only has the original shape repeated
        many times, so there is nothing to fuse together.

        If `use_link` is `False` the original shape is copied many times.
        In this case the `Fuse` property is able to fuse
        all copies into a single object, if they touch each other.

    Returns
    -------
    Part::FeaturePython
        A scripted object with `Proxy.Type='Array'`.
        Its `Shape` is a compound of the copies of the original object.

    See Also
    --------
    make_ortho_array2d, make_rect_array, make_rect_array2d
    """
    _name = "make_ortho_array"
    utils.print_header(_name, _tr("Orthogonal array"))

    _msg("v_x: {}".format(v_x))
    _msg("v_y: {}".format(v_y))
    _msg("v_z: {}".format(v_z))

    try:
        utils.type_check([(v_x, (int, float, App.Vector)),
                          (v_y, (int, float, App.Vector)),
                          (v_z, (int, float, App.Vector))],
                         name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be a number or vector."))
        return None

    _text = "Input: single value expanded to vector."
    if not isinstance(v_x, App.Vector):
        v_x = App.Vector(v_x, 0, 0)
        _wrn(_tr(_text))
    if not isinstance(v_y, App.Vector):
        v_y = App.Vector(0, v_y, 0)
        _wrn(_tr(_text))
    if not isinstance(v_z, App.Vector):
        v_z = App.Vector(0, 0, v_z)
        _wrn(_tr(_text))

    _msg("n_x: {}".format(n_x))
    _msg("n_y: {}".format(n_y))
    _msg("n_z: {}".format(n_z))

    try:
        utils.type_check([(n_x, int), (n_y, int), (n_z, int)], name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be an integer number."))
        return None

    _text = ("Input: number of elements must be at least 1. "
             "It is set to 1.")
    if n_x < 1:
        _wrn(_tr(_text))
        n_x = 1
    if n_y < 1:
        _wrn(_tr(_text))
        n_y = 1
    if n_z < 1:
        _wrn(_tr(_text))
        n_z = 1

    _msg("use_link: {}".format(bool(use_link)))

    # new_obj = make_array.make_array()
    new_obj = Draft.makeArray(obj,
                              arg1=v_x,
                              arg2=v_y,
                              arg3=v_z,
                              arg4=n_x,
                              arg5=n_y,
                              arg6=n_z,
                              use_link=use_link)
    return new_obj
Example #11
0
def getColorFromStyledItem(styled_item):
    """Get color from the IfcStyledItem.

    Returns
    -------
    float, float, float, int
        A tuple with the red, green, blue, and transparency values.
        If the `IfcStyledItem` is a `IfcDraughtingPreDefinedColour`
        the transparency is set to 0.
        The first three values range from 0 to 1.0, while the transparency
        varies from 0 to 100.

    None
        Return `None` if `styled_item` is not of type `'IfcStyledItem'`
        or if there is any other problem getting a color.
    """

    if styled_item.is_a("IfcStyledRepresentation"):
        styled_item = styled_item.Items[0]

    if not styled_item.is_a("IfcStyledItem"):
        return None

    rgb_color = None
    transparency = None
    col = None

    # The `IfcStyledItem` holds presentation style information for products,
    # either explicitly for an `IfcGeometricRepresentationItem` being part of
    # an `IfcShapeRepresentation` assigned to a product, or by assigning
    # presentation information to `IfcMaterial` being assigned
    # as other representation for a product.

    # In current IFC release (IFC2x3) only one presentation style
    # assignment shall be assigned.
    # In IFC4 `IfcPresentationStyleAssignment` is deprecated
    # In IFC4 multiple styles are assigned to style in 'IfcStyleItem' instead

    # print(ifcfile[p])
    # print(styled_item)
    # print(styled_item.Styles)
    if len(styled_item.Styles) == 0:
        # IN IFC2x3, only one element in `Styles` should be available.
        _wrn("No 'Style' in 'IfcStyleItem', do nothing.")
        # ca 100x in 210_King_Merged.ifc
        # Empty styles, #4952778=IfcStyledItem(#4952779,(),$)
        # this is an error in the IFC file in my opinion
    else:
        # never seen an ifc with more than one Styles in IfcStyledItem
        # the above seams to only apply for IFC2x3, IFC4 can have them
        # see https://forum.freecadweb.org/viewtopic.php?f=39&t=33560&p=437056#p437056

        # Get the `IfcPresentationStyleAssignment`, there should only be one,
        if styled_item.Styles[0].is_a('IfcPresentationStyleAssignment'):
            assign_style = styled_item.Styles[0]
        else:
            # `IfcPresentationStyleAssignment` is deprecated in IFC4,
            # in favor of `IfcStyleAssignmentSelect`
            assign_style = styled_item
        # print(assign_style)  # IfcPresentationStyleAssignment

        # `IfcPresentationStyleAssignment` can hold various kinds and counts
        # of styles, see `IfcPresentationStyleSelect`
        if assign_style.Styles[0].is_a("IfcSurfaceStyle"):
            _style = assign_style.Styles[0]
            # Schependomlaan and Nova and others
            # `IfcSurfaceStyleRendering`
            # print(_style.Styles[0])
            # `IfcColourRgb`
            rgb_color = _style.Styles[0].SurfaceColour
            # print(rgb_color)
            if (_style.Styles[0].is_a('IfcSurfaceStyleShading')
                    and hasattr(_style.Styles[0], 'Transparency')
                    and _style.Styles[0].Transparency):
                transparency = _style.Styles[0].Transparency * 100
        elif assign_style.Styles[0].is_a("IfcCurveStyle"):
            if (len(assign_style.Styles) == 2
                    and assign_style.Styles[1].is_a("IfcSurfaceStyle")):
                # Allplan, new IFC export started in 2017
                # `IfcDraughtingPreDefinedColour`
                # print(assign_style.Styles[0].CurveColour)
                # TODO: check this; on index 1, is this what we need?!
                rgb_color = assign_style.Styles[1].Styles[0].SurfaceColour
                # print(rgb_color)
            else:
                # 2x Annotations in 210_King_Merged.ifc
                # print(ifcfile[p])
                # print(assign_style.Styles[0])
                # print(assign_style.Styles[0].CurveColour)
                rgb_color = assign_style.Styles[0].CurveColour

    if rgb_color:
        if rgb_color.is_a('IfcDraughtingPreDefinedColour'):
            if DEBUG_prod_colors:
                _msg("  '{}'= ".format(rgb_color.Name))

            col = predefined_to_rgb(rgb_color)

            if col:
                col = col + (0, )
        else:
            col = (rgb_color.Red, rgb_color.Green, rgb_color.Blue,
                   int(transparency) if transparency else 0)
    else:
        col = None

    if DEBUG_prod_colors:
        _msg("  {}".format(col))

    return col
Example #12
0
def make_ortho_array2d(obj,
                       v_x=App.Vector(10, 0, 0),
                       v_y=App.Vector(0, 10, 0),
                       n_x=2,
                       n_y=2,
                       use_link=True):
    """Create a 2D orthogonal array from the given object.

    This works the same as `make_ortho_array`.
    The Z component is ignored so it only considers vector displacements
    in X and Y directions.

    Parameters
    ----------
    obj: Part::Feature
        Any type of object that has a `Part::TopoShape`
        that can be duplicated.
        This means most 2D and 3D objects produced
        with any workbench.

    v_x, v_y: Base::Vector3, optional
        Vectorial displacement of elements
        in the corresponding X and Y directions.
        See `make_ortho_array`.

    n_x, n_y: int, optional
        Number of elements
        in the corresponding X and Y directions.
        See `make_ortho_array`.

    use_link: bool, optional
        If it is `True`, create `App::Link` array.
        See `make_ortho_array`.

    Returns
    -------
    Part::FeaturePython
        A scripted object with `Proxy.Type='Array'`.
        Its `Shape` is a compound of the copies of the original object.

    See Also
    --------
    make_ortho_array, make_rect_array, make_rect_array2d
    """
    _name = "make_ortho_array2d"
    utils.print_header(_name, _tr("Orthogonal array 2D"))

    _msg("v_x: {}".format(v_x))
    _msg("v_y: {}".format(v_y))

    try:
        utils.type_check([(v_x, (int, float, App.Vector)),
                          (v_y, (int, float, App.Vector))],
                         name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be a number or vector."))
        return None

    _text = "Input: single value expanded to vector."
    if not isinstance(v_x, App.Vector):
        v_x = App.Vector(v_x, 0, 0)
        _wrn(_tr(_text))
    if not isinstance(v_y, App.Vector):
        v_y = App.Vector(0, v_y, 0)
        _wrn(_tr(_text))

    _msg("n_x: {}".format(n_x))
    _msg("n_y: {}".format(n_y))

    try:
        utils.type_check([(n_x, int), (n_y, int)], name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be an integer number."))
        return None

    _text = ("Input: number of elements must be at least 1. "
             "It is set to 1.")
    if n_x < 1:
        _wrn(_tr(_text))
        n_x = 1
    if n_y < 1:
        _wrn(_tr(_text))
        n_y = 1

    _msg("use_link: {}".format(bool(use_link)))

    # new_obj = make_array.make_array()
    new_obj = Draft.makeArray(obj,
                              arg1=v_x,
                              arg2=v_y,
                              arg3=n_x,
                              arg4=n_y,
                              use_link=use_link)
    return new_obj
Example #13
0
def _get_path_circ_ellipse(plane, edge, vertex, edata, iscircle, isellipse,
                           fill, stroke, linewidth, lstyle):
    """Get the edge data from a path that is a circle or ellipse."""
    if hasattr(App, "DraftWorkingPlane"):
        drawing_plane_normal = App.DraftWorkingPlane.axis
    else:
        drawing_plane_normal = App.Vector(0, 0, 1)

    if plane:
        drawing_plane_normal = plane.axis

    center = edge.Curve
    ax = center.Axis

    # The angle between the curve axis and the plane is not 0 nor 180 degrees
    _angle = math.degrees(ax.getAngle(drawing_plane_normal))
    if round(_angle, 2) not in (0, 180):
        edata += get_discretized(edge, plane)
        return "edata", edata

    # The angle is 0 or 180, coplanar
    occversion = Part.OCC_VERSION.split(".")
    done = False
    if int(occversion[0]) >= 7 and int(occversion[1]) >= 1:
        # if using occ >= 7.1, use HLR algorithm
        snip = Drawing.projectToSVG(edge, drawing_plane_normal)

        if snip:
            try:
                _a = snip.split('path d="')[1]
                _a = _a.split('"')[0]
                _a = _a.split("A")[1]
                A = "A " + _a
            except IndexError:
                # TODO: trap only specific exception.
                # Check the problem. Split didn't produce a two element list?
                _wrn("Circle or ellipse: "
                     "cannot split the projection snip "
                     "obtained by 'projectToSVG', "
                     "continue manually.")
            else:
                edata += A
                done = True

    if not done:
        if len(edge.Vertexes) == 1 and iscircle:
            # Complete circle not only arc
            svg = get_circle(plane, fill, stroke, linewidth, lstyle, edge)
            # If it's a circle we will return the final SVG string,
            # otherwise it will process the `edata` further
            return "svg", svg
        elif len(edge.Vertexes) == 1 and isellipse:
            # Complete ellipse not only arc
            # svg = get_ellipse(plane,
            #                   fill, stroke, linewidth,
            #                   lstyle, edge)
            # return svg

            # Difference in angles
            _diff = (center.LastParameter - center.FirstParameter) / 2.0
            endpoints = [
                get_proj(center.value(_diff), plane),
                get_proj(vertex[-1].Point, plane)
            ]
        else:
            endpoints = [get_proj(vertex[-1].Point, plane)]

        # Arc with more than one vertex
        if iscircle:
            rx = ry = center.Radius
            rot = 0
        else:  # ellipse
            rx = center.MajorRadius
            ry = center.MinorRadius
            _rot = center.AngleXU * center.Axis * App.Vector(0, 0, 1)
            rot = math.degrees(_rot)
            if rot > 90:
                rot -= 180
            if rot < -90:
                rot += 180

        # Be careful with the sweep flag
        _diff = edge.ParameterRange[1] - edge.ParameterRange[0]
        _diff = _diff / math.pi
        flag_large_arc = (_diff % 2) > 1

        # flag_sweep = (center.Axis * drawing_plane_normal >= 0) \
        #     == (edge.LastParameter > edge.FirstParameter)
        #     == (edge.Orientation == "Forward")

        # Another method: check the direction of the angle
        # between tangents
        _diff = edge.LastParameter - edge.FirstParameter
        t1 = edge.tangentAt(edge.FirstParameter)
        t2 = edge.tangentAt(edge.FirstParameter + _diff / 10)
        flag_sweep = DraftVecUtils.angle(t1, t2, drawing_plane_normal) < 0

        for v in endpoints:
            edata += ('A {} {} {} '
                      '{} {} '
                      '{} {} '.format(rx, ry, rot, int(flag_large_arc),
                                      int(flag_sweep), v.x, v.y))

    return "edata", edata
Example #14
0
def make_radial_dimension_obj(edge_object, index=1, mode="radius",
                              dim_line=None):
    """Create a radial or diameter dimension from an arc object.

    Parameters
    ----------
    edge_object: Part::Feature
        The object which has a circular edge which will be measured.
        It must have a `Part::TopoShape`, and at least one element
        must be a circular edge in `Shape.Edges` to be able to measure
        its radius.

    index: int, optional
        It defaults to `1`.
        It is the index of the edge in `edge_object` which is going to
        be measured.
        The minimum value should be `1`, which will be interpreted
        as `'Edge1'`. If the value is below `1`, it will be set to `1`.

    mode: str, optional
        It defaults to `'radius'`; the other option is `'diameter'`.
        It determines whether the dimension will be shown as a radius
        or as a diameter.

    dim_line: Base::Vector3, optional
        It defaults to `None`.
        This is a point through which the extension of the dimension line
        will pass. The dimension line will be a radius or diameter
        of the measured arc, extending from the center to the arc itself.

        If it is `None`, this point will be set to one unit to the right
        of the center of the arc, which will create a dimension line that is
        horizontal, that is, parallel to the +X axis.

    Returns
    -------
    App::FeaturePython
        A scripted object of type `'LinearDimension'`.
        This object does not have a `Shape` attribute, as the text and lines
        are created on screen by Coin (pivy).

    None
        If there is a problem it will return `None`.
    """
    _name = "make_radial_dimension_obj"
    utils.print_header(_name, "Radial dimension")

    found, doc = utils.find_doc(App.activeDocument())
    if not found:
        _err(_tr("No active document. Aborting."))
        return None

    if isinstance(edge_object, str):
        edge_object_str = edge_object

    found, edge_object = utils.find_object(edge_object, doc)
    if not found:
        _msg("edge_object: {}".format(edge_object_str))
        _err(_tr("Wrong input: object not in document."))
        return None

    _msg("edge_object: {}".format(edge_object.Label))
    if not hasattr(edge_object, "Shape"):
        _err(_tr("Wrong input: object doesn't have a 'Shape' to measure."))
        return None
    if (not hasattr(edge_object.Shape, "Edges")
            or len(edge_object.Shape.Edges) < 1):
        _err(_tr("Wrong input: object doesn't have at least one element "
                 "in 'Edges' to use for measuring."))
        return None

    _msg("index: {}".format(index))
    try:
        utils.type_check([(index, int)], name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be an integer."))
        return None

    if index < 1:
        index = 1
        _wrn(_tr("index: values below 1 are not allowed; will be set to 1."))

    edge = edge_object.getSubObject("Edge" + str(index))
    if not edge:
        _err(_tr("Wrong input: index doesn't correspond to an edge "
                 "in the object."))
        return None

    if not hasattr(edge, "Curve") or edge.Curve.TypeId != 'Part::GeomCircle':
        _err(_tr("Wrong input: index doesn't correspond to a circular edge."))
        return None

    _msg("mode: {}".format(mode))
    try:
        utils.type_check([(mode, str)], name=_name)
    except TypeError:
        _err(_tr("Wrong input: must be a string, 'radius' or 'diameter'."))
        return None

    if mode not in ("radius", "diameter"):
        _err(_tr("Wrong input: must be a string, 'radius' or 'diameter'."))
        return None

    _msg("dim_line: {}".format(dim_line))
    if dim_line:
        try:
            utils.type_check([(dim_line, App.Vector)], name=_name)
        except TypeError:
            _err(_tr("Wrong input: must be a vector."))
            return None
    else:
        center = edge_object.Shape.Edges[index - 1].Curve.Center
        dim_line = center + App.Vector(1, 0, 0)

    # TODO: the internal function expects an index starting with 0
    # so we need to decrease the value here.
    # This should be changed in the future in the internal function.
    index -= 1

    new_obj = make_dimension(edge_object, index, mode, dim_line)

    return new_obj
Example #15
0
def create_test_file(
        file_name="draft_test_objects",
        file_path=os.environ["HOME"],
        save=False,
        font_file="/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"):
    """Create a complete test file of Draft objects.

    It draws a frame with information on the software used to create
    the test document, and fills it with every object that can be created.

    Parameters
    ----------
    file_name: str, optional
        It defaults to `'draft_test_objects'`.
        It is the name of the document that is created.

        The `file_name` will be appended to `file_path`
        to determine the actual path to save. The extension `.FCStd`
        will be added automatically.

    file_path: str, optional
        It defaults to the value of `os.environ['HOME']`
        which in Linux is usually `'/home/user'`.

        If it is the empty string `''` it will use the value
        returned by `App.getUserAppDataDir()`,
        for example, `'/home/user/.FreeCAD/'`.

    save: bool, optional
        It defaults to `False`. If it is `True` the new document
        will be saved to disk after creating all objects.

    font_file: str, optional
        It defaults to `'/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'`.
        It is the full path of a font in the system to be used
        to create a `Draft ShapeString`.
        If the font is not found, this object is not created.

    Returns
    -------
    App::Document
        A reference to the test document that was created.

    To Do
    -----
    Find a reliable way of getting a default font to be able to create
    the `Draft ShapeString`.
    """
    doc = App.newDocument(file_name)
    _msg(16 * "-")
    _msg("Filename: {}".format(file_name))
    _msg("If the units tests fail, this script may fail as well")

    _create_frame()

    # Line, wire, and fillet
    _msg(16 * "-")
    _msg("Line")
    Draft.make_line(Vector(0, 0, 0), Vector(500, 500, 0))
    t_xpos = -50
    t_ypos = -200
    _t = Draft.make_text(["Line"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    _msg(16 * "-")
    _msg("Wire")
    Draft.make_wire(
        [Vector(500, 0, 0),
         Vector(1000, 500, 0),
         Vector(1000, 1000, 0)])
    t_xpos += 500
    _t = Draft.make_text(["Wire"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    _msg(16 * "-")
    _msg("Fillet")
    line_h_1 = Draft.make_line(Vector(1500, 0, 0), Vector(1500, 500, 0))
    line_h_2 = Draft.make_line(Vector(1500, 500, 0), Vector(2000, 500, 0))
    if App.GuiUp:
        line_h_1.ViewObject.DrawStyle = "Dotted"
        line_h_2.ViewObject.DrawStyle = "Dotted"
    doc.recompute()

    Draft.make_fillet([line_h_1, line_h_2], 400)
    t_xpos += 900
    _t = Draft.make_text(["Fillet"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Circle, arc, arc by 3 points
    _msg(16 * "-")
    _msg("Circle")
    circle = Draft.make_circle(350)
    circle.Placement.Base = Vector(2500, 500, 0)
    t_xpos += 1050
    _t = Draft.make_text(["Circle"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    _msg(16 * "-")
    _msg("Circular arc")
    arc = Draft.make_circle(350, startangle=0, endangle=100)
    arc.Placement.Base = Vector(3200, 500, 0)
    t_xpos += 800
    _t = Draft.make_text(["Circular arc"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    _msg(16 * "-")
    _msg("Circular arc 3 points")
    Draft.make_arc_3points(
        [Vector(4600, 0, 0),
         Vector(4600, 800, 0),
         Vector(4000, 1000, 0)])
    t_xpos += 600
    _t = Draft.make_text(["Circular arc 3 points"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Ellipse, polygon, rectangle
    _msg(16 * "-")
    _msg("Ellipse")
    ellipse = Draft.make_ellipse(500, 300)
    ellipse.Placement.Base = Vector(5500, 250, 0)
    t_xpos += 1600
    _t = Draft.make_text(["Ellipse"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    _msg(16 * "-")
    _msg("Polygon")
    polygon = Draft.make_polygon(5, 250)
    polygon.Placement.Base = Vector(6500, 500, 0)
    t_xpos += 950
    _t = Draft.make_text(["Polygon"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    _msg(16 * "-")
    _msg("Rectangle")
    rectangle = Draft.make_rectangle(500, 1000, 0)
    rectangle.Placement.Base = Vector(7000, 0, 0)
    t_xpos += 650
    _t = Draft.make_text(["Rectangle"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Text
    _msg(16 * "-")
    _msg("Text")
    text = Draft.make_text(["Testing"], Vector(7700, 500, 0))
    if App.GuiUp:
        text.ViewObject.FontSize = 100
    t_xpos += 700
    _t = Draft.make_text(["Text"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Linear dimension
    _msg(16 * "-")
    _msg("Linear dimension")
    dimension = Draft.make_dimension(Vector(8500, 500,
                                            0), Vector(8500, 1000, 0),
                                     Vector(9000, 750, 0))
    if App.GuiUp:
        dimension.ViewObject.ArrowSize = 15
        dimension.ViewObject.ExtLines = 1000
        dimension.ViewObject.ExtOvershoot = 100
        dimension.ViewObject.FontSize = 100
        dimension.ViewObject.ShowUnit = False
    t_xpos += 680
    _t = Draft.make_text(["Dimension"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Radius and diameter dimension
    _msg(16 * "-")
    _msg("Radius and diameter dimension")
    arc_h = Draft.make_circle(500, startangle=0, endangle=90)
    arc_h.Placement.Base = Vector(9500, 0, 0)
    doc.recompute()

    dimension_r = Draft.make_dimension(arc_h, 0, "radius",
                                       Vector(9750, 200, 0))
    if App.GuiUp:
        dimension_r.ViewObject.ArrowSize = 15
        dimension_r.ViewObject.FontSize = 100
        dimension_r.ViewObject.ShowUnit = False

    arc_h2 = Draft.make_circle(450, startangle=-120, endangle=80)
    arc_h2.Placement.Base = Vector(10000, 1000, 0)
    doc.recompute()

    dimension_d = Draft.make_dimension(arc_h2, 0, "diameter",
                                       Vector(10750, 900, 0))
    if App.GuiUp:
        dimension_d.ViewObject.ArrowSize = 15
        dimension_d.ViewObject.FontSize = 100
        dimension_d.ViewObject.ShowUnit = False
    t_xpos += 950
    _t = Draft.make_text(["Radius dimension", "Diameter dimension"],
                         Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Angular dimension
    _msg(16 * "-")
    _msg("Angular dimension")
    Draft.make_line(Vector(10500, 300, 0), Vector(11500, 1000, 0))
    Draft.make_line(Vector(10500, 300, 0), Vector(11500, 0, 0))
    angle1 = math.radians(40)
    angle2 = math.radians(-20)
    dimension_a = Draft.make_angular_dimension(Vector(10500, 300, 0),
                                               [angle1, angle2],
                                               Vector(11500, 300, 0))
    if App.GuiUp:
        dimension_a.ViewObject.ArrowSize = 15
        dimension_a.ViewObject.FontSize = 100
    t_xpos += 1700
    _t = Draft.make_text(["Angle dimension"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # BSpline
    _msg(16 * "-")
    _msg("BSpline")
    Draft.make_bspline([
        Vector(12500, 0, 0),
        Vector(12500, 500, 0),
        Vector(13000, 500, 0),
        Vector(13000, 1000, 0)
    ])
    t_xpos += 1500
    _t = Draft.make_text(["BSpline"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Point
    _msg(16 * "-")
    _msg("Point")
    point = Draft.make_point(13500, 500, 0)
    if App.GuiUp:
        point.ViewObject.PointSize = 10
    t_xpos += 900
    _t = Draft.make_text(["Point"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Shapestring
    _msg(16 * "-")
    _msg("Shapestring")
    try:
        shape_string = Draft.make_shapestring("Testing", font_file, 100)
        shape_string.Placement.Base = Vector(14000, 500)
    except Exception:
        _wrn("Shapestring could not be created")
        _wrn("Possible cause: the font file may not exist")
        _wrn(font_file)
        rect = Draft.make_rectangle(500, 100)
        rect.Placement.Base = Vector(14000, 500)
    t_xpos += 600
    _t = Draft.make_text(["Shapestring"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Facebinder
    _msg(16 * "-")
    _msg("Facebinder")
    box = doc.addObject("Part::Box", "Cube")
    box.Length = 200
    box.Width = 500
    box.Height = 100
    box.Placement.Base = Vector(15000, 0, 0)
    if App.GuiUp:
        box.ViewObject.Visibility = False

    facebinder = Draft.make_facebinder([(box, ("Face1", "Face3", "Face6"))])
    facebinder.Extrusion = 10
    t_xpos += 780
    _t = Draft.make_text(["Facebinder"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Cubic bezier curve, n-degree bezier curve
    _msg(16 * "-")
    _msg("Cubic bezier")
    Draft.make_bezcurve([
        Vector(15500, 0, 0),
        Vector(15578, 485, 0),
        Vector(15879, 154, 0),
        Vector(15975, 400, 0),
        Vector(16070, 668, 0),
        Vector(16423, 925, 0),
        Vector(16500, 500, 0)
    ],
                        degree=3)
    t_xpos += 680
    _t = Draft.make_text(["Cubic bezier"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    _msg(16 * "-")
    _msg("N-degree bezier")
    Draft.make_bezcurve([
        Vector(16500, 0, 0),
        Vector(17000, 500, 0),
        Vector(17500, 500, 0),
        Vector(17500, 1000, 0),
        Vector(17000, 1000, 0),
        Vector(17063, 1256, 0),
        Vector(17732, 1227, 0),
        Vector(17790, 720, 0),
        Vector(17702, 242, 0)
    ])
    t_xpos += 1200
    _t = Draft.make_text(["n-Bezier"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Label
    _msg(16 * "-")
    _msg("Label")
    place = App.Placement(Vector(18500, 500, 0), App.Rotation())
    label = Draft.make_label(targetpoint=Vector(18000, 0, 0),
                             distance=-250,
                             placement=place)
    label.Text = "Testing"
    if App.GuiUp:
        label.ViewObject.ArrowSize = 15
        label.ViewObject.TextSize = 100
    doc.recompute()
    t_xpos += 1200
    _t = Draft.make_text(["Label"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Orthogonal array and orthogonal link array
    _msg(16 * "-")
    _msg("Orthogonal array")
    rect_h = Draft.make_rectangle(500, 500)
    rect_h.Placement.Base = Vector(1500, 2500, 0)
    if App.GuiUp:
        rect_h.ViewObject.Visibility = False

    Draft.makeArray(rect_h, Vector(600, 0, 0), Vector(0, 600, 0),
                    Vector(0, 0, 0), 3, 2, 1)
    t_xpos = 1700
    t_ypos = 2200
    _t = Draft.make_text(["Array"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    rect_h_2 = Draft.make_rectangle(500, 100)
    rect_h_2.Placement.Base = Vector(1500, 5000, 0)
    if App.GuiUp:
        rect_h_2.ViewObject.Visibility = False

    _msg(16 * "-")
    _msg("Orthogonal link array")
    Draft.makeArray(rect_h_2,
                    Vector(800, 0, 0),
                    Vector(0, 500, 0),
                    Vector(0, 0, 0),
                    2,
                    4,
                    1,
                    use_link=True)
    t_ypos += 2600
    _t = Draft.make_text(["Link array"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Polar array and polar link array
    _msg(16 * "-")
    _msg("Polar array")
    wire_h = Draft.make_wire([
        Vector(5500, 3000, 0),
        Vector(6000, 3500, 0),
        Vector(6000, 3200, 0),
        Vector(5800, 3200, 0)
    ])
    if App.GuiUp:
        wire_h.ViewObject.Visibility = False

    Draft.makeArray(wire_h, Vector(5000, 3000, 0), 200, 8)
    t_xpos = 4600
    t_ypos = 2200
    _t = Draft.make_text(["Polar array"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    _msg(16 * "-")
    _msg("Polar link array")
    wire_h_2 = Draft.make_wire([
        Vector(5500, 6000, 0),
        Vector(6000, 6000, 0),
        Vector(5800, 5700, 0),
        Vector(5800, 5750, 0)
    ])
    if App.GuiUp:
        wire_h_2.ViewObject.Visibility = False

    Draft.makeArray(wire_h_2, Vector(5000, 6000, 0), 200, 8, use_link=True)
    t_ypos += 3200
    _t = Draft.make_text(["Polar link array"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Circular array and circular link array
    _msg(16 * "-")
    _msg("Circular array")
    poly_h = Draft.make_polygon(5, 200)
    poly_h.Placement.Base = Vector(8000, 3000, 0)
    if App.GuiUp:
        poly_h.ViewObject.Visibility = False

    Draft.makeArray(poly_h, 500, 600, Vector(0, 0, 1), Vector(0, 0, 0), 3, 1)
    t_xpos = 7700
    t_ypos = 1700
    _t = Draft.make_text(["Circular array"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    _msg(16 * "-")
    _msg("Circular link array")
    poly_h_2 = Draft.make_polygon(6, 150)
    poly_h_2.Placement.Base = Vector(8000, 6250, 0)
    if App.GuiUp:
        poly_h_2.ViewObject.Visibility = False

    Draft.makeArray(poly_h_2,
                    550,
                    450,
                    Vector(0, 0, 1),
                    Vector(0, 0, 0),
                    3,
                    1,
                    use_link=True)
    t_ypos += 3100
    _t = Draft.make_text(["Circular link array"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Path array and path link array
    _msg(16 * "-")
    _msg("Path array")
    poly_h = Draft.make_polygon(3, 250)
    poly_h.Placement.Base = Vector(10500, 3000, 0)
    if App.GuiUp:
        poly_h.ViewObject.Visibility = False

    bspline_path = Draft.make_bspline([
        Vector(10500, 2500, 0),
        Vector(11000, 3000, 0),
        Vector(11500, 3200, 0),
        Vector(12000, 4000, 0)
    ])

    Draft.makePathArray(poly_h, bspline_path, 5)
    t_xpos = 10400
    t_ypos = 2200
    _t = Draft.make_text(["Path array"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    _msg(16 * "-")
    _msg("Path link array")
    poly_h_2 = Draft.make_polygon(4, 200)
    poly_h_2.Placement.Base = Vector(10500, 5000, 0)
    if App.GuiUp:
        poly_h_2.ViewObject.Visibility = False

    bspline_path_2 = Draft.make_bspline([
        Vector(10500, 4500, 0),
        Vector(11000, 6800, 0),
        Vector(11500, 6000, 0),
        Vector(12000, 5200, 0)
    ])

    Draft.makePathArray(poly_h_2, bspline_path_2, 6, use_link=True)
    t_ypos += 2000
    _t = Draft.make_text(["Path link array"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Point array
    _msg(16 * "-")
    _msg("Point array")
    poly_h = Draft.make_polygon(3, 250)

    point_1 = Draft.make_point(13000, 3000, 0)
    point_2 = Draft.make_point(13000, 3500, 0)
    point_3 = Draft.make_point(14000, 2500, 0)
    point_4 = Draft.make_point(14000, 3000, 0)

    add_list, delete_list = Draft.upgrade([point_1, point_2, point_3, point_4])
    compound = add_list[0]
    if App.GuiUp:
        compound.ViewObject.PointSize = 5

    Draft.makePointArray(poly_h, compound)
    t_xpos = 13000
    t_ypos = 2200
    _t = Draft.make_text(["Point array"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    # Clone and mirror
    _msg(16 * "-")
    _msg("Clone")
    wire_h = Draft.make_wire([
        Vector(15000, 2500, 0),
        Vector(15200, 3000, 0),
        Vector(15500, 2500, 0),
        Vector(15200, 2300, 0)
    ])

    Draft.clone(wire_h, Vector(0, 1000, 0))
    t_xpos = 15000
    t_ypos = 2100
    _t = Draft.make_text(["Clone"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    _msg(16 * "-")
    _msg("Mirror")
    wire_h = Draft.make_wire([
        Vector(17000, 2500, 0),
        Vector(16500, 4000, 0),
        Vector(16000, 2700, 0),
        Vector(16500, 2500, 0),
        Vector(16700, 2700, 0)
    ])

    Draft.mirror(wire_h, Vector(17100, 2000, 0), Vector(17100, 4000, 0))
    t_xpos = 17000
    t_ypos = 2200
    _t = Draft.make_text(["Mirror"], Vector(t_xpos, t_ypos, 0))
    _set_text(_t)

    doc.recompute()

    if App.GuiUp:
        Gui.runCommand("Std_ViewFitAll")

    # Export
    if not file_path:
        file_path = App.getUserAppDataDir()
    out_name = os.path.join(file_path, file_name + ".FCStd")
    doc.FileName = out_name
    if save:
        doc.save()
        _msg(16 * "-")
        _msg("Saved: {}".format(out_name))

    return doc
Example #16
0
def dim_symbol(symbol=None, invert=False):
    """Return the specified dimension symbol.

    Parameters
    ----------
    symbol: int, optional
        It defaults to `None`, in which it gets the value from the parameter
        database, `get_param("dimsymbol", 0)`.

        A numerical value defines different markers
         * 0, `SoSphere`
         * 1, `SoSeparator` with a `SoLineSet`, a circle (in fact a 24 sided polygon)
         * 2, `SoSeparator` with a `soCone`
         * 3, `SoSeparator` with a `SoFaceSet`
         * 4, `SoSeparator` with a `SoLineSet`, calling `dim_dash`
         * Otherwise, `SoSphere`

    invert: bool, optional
        It defaults to `False`.
        If it is `True` and `symbol=2`, the cone will be rotated
        -90 degrees around the Z axis, otherwise the rotation is positive,
        +90 degrees.

    Returns
    -------
    Coin.SoNode
        A `Coin.SoSphere`, or `Coin.SoSeparator` (circle, cone, face, line)
        that will be used as a dimension symbol.
    """
    if symbol is None:
        symbol = utils.get_param("dimsymbol", 0)

    if symbol == 0:
        # marker = coin.SoMarkerSet()
        # marker.markerIndex = 80

        # Returning a sphere means that the bounding box will
        # be 3-dimensional; a marker will always be planar seen from any
        # orientation but it currently doesn't work correctly
        marker = coin.SoSphere()
        return marker
    elif symbol == 1:
        marker = coin.SoSeparator()
        v = coin.SoVertexProperty()
        for i in range(25):
            ang = math.radians(i * 15)
            v.vertex.set1Value(i, (math.sin(ang), math.cos(ang), 0))
        p = coin.SoLineSet()
        p.vertexProperty = v
        marker.addChild(p)
        return marker
    elif symbol == 2:
        marker = coin.SoSeparator()
        t = coin.SoTransform()
        t.translation.setValue((0, -2, 0))
        t.center.setValue((0, 2, 0))
        if invert:
            t.rotation.setValue(coin.SbVec3f((0, 0, 1)), -math.pi / 2)
        else:
            t.rotation.setValue(coin.SbVec3f((0, 0, 1)), math.pi / 2)
        c = coin.SoCone()
        c.height.setValue(4)
        marker.addChild(t)
        marker.addChild(c)
        return marker
    elif symbol == 3:
        marker = coin.SoSeparator()
        # hints are required otherwise only the bottom of the face is colored
        h = coin.SoShapeHints()
        h.vertexOrdering = h.COUNTERCLOCKWISE
        c = coin.SoCoordinate3()
        c.point.setValues([(-1, -2, 0), (0, 2, 0), (1, 2, 0), (0, -2, 0)])
        f = coin.SoFaceSet()
        marker.addChild(h)
        marker.addChild(c)
        marker.addChild(f)
        return marker
    elif symbol == 4:
        return dim_dash((-1.5, -1.5, 0), (1.5, 1.5, 0))
    else:
        _wrn(
            translate("draft",
                      "Symbol not implemented. Using a default symbol."))
        return coin.SoSphere()
Example #17
0
def calculate_placement(globalRotation,
                        edge,
                        offset,
                        RefPt,
                        xlate,
                        align,
                        normal=None,
                        mode='Original',
                        overrideNormal=False):
    """Orient shape to a local coordinate system (tangent, normal, binormal).

    Orient shape at parameter offset, normally length.

    http://en.wikipedia.org/wiki/Euler_angles (previous version)
    http://en.wikipedia.org/wiki/Quaternions
    """
    # Start with a null Placement so the translation goes to the right place.
    # Then apply the global orientation.
    placement = App.Placement()
    placement.Rotation = globalRotation

    placement.move(RefPt + xlate)
    if not align:
        return placement

    nullv = App.Vector(0, 0, 0)
    defNormal = App.Vector(0.0, 0.0, 1.0)
    if normal:
        defNormal = normal

    try:
        t = edge.tangentAt(get_parameter_from_v0(edge, offset))
        t.normalize()
    except:
        _wrn(
            translate("draft",
                      "Cannot calculate path tangent. Copy not aligned."))
        return placement

    if mode in ('Original', 'Tangent'):
        if normal is None:
            n = defNormal
        else:
            n = normal
            n.normalize()

        try:
            b = t.cross(n)
            b.normalize()
        except Exception:
            # weird special case, tangent and normal parallel
            b = nullv
            _wrn(
                translate(
                    "draft",
                    "Tangent and normal are parallel. Copy not aligned."))
            return placement

        if overrideNormal:
            priority = "XZY"
            newRot = App.Rotation(t, b, n, priority)  # t/x, b/y, n/z
        else:
            # must follow X, try to follow Z, Y is what it is
            priority = "XZY"
            newRot = App.Rotation(t, n, b, priority)

    elif mode == 'Frenet':
        try:
            n = edge.normalAt(get_parameter_from_v0(edge, offset))
            n.normalize()
        except App.Base.FreeCADError:  # no/infinite normals here
            n = defNormal
            _msg(
                translate("draft",
                          "Cannot calculate path normal, using default."))

        try:
            b = t.cross(n)
            b.normalize()
        except Exception:
            b = nullv
            _wrn(
                translate("draft",
                          "Cannot calculate path binormal. Copy not aligned."))
            return placement

        priority = "XZY"
        newRot = App.Rotation(t, n, b, priority)  # t/x, n/y, b/z
    else:
        _msg(
            translate("draft", "AlignMode {} is not implemented").format(mode))
        return placement

    # Have valid tangent, normal, binormal
    newGRot = newRot.multiply(globalRotation)

    placement.Rotation = newGRot
    return placement
Example #18
0
def redraw_3d_view():
    """Force a redraw of 3D view or do nothing if it fails."""
    try:
        Gui.ActiveDocument.ActiveView.redraw()
    except AttributeError as err:
        _wrn(err)
Example #19
0
def load_texture(filename, size=None, gui=App.GuiUp):
    """Return a Coin.SoSFImage to use as a texture for a 2D plane.

    This function only works if the graphical interface is available
    as the visual properties that can be applied to a shape
    are attributes of the view provider (`obj.ViewObject`).

    Parameters
    ----------
    filename: str
        A path to a pixel image file (PNG) that can be used as a texture
        on the face of an object.

    size: tuple of two int, or a single int, optional
        It defaults to `None`.
        If a tuple is given, the two values define the width and height
        in pixels to which the loaded image will be scaled.
        If it is a single value, it is used for both dimensions.

        If it is `None`, the size will be determined from the `QImage`
        created from `filename`.

        CURRENTLY the input `size` parameter IS NOT USED.
        It always uses the `QImage` to determine this information.

    gui: bool, optional
        It defaults to the value of `App.GuiUp`, which is `True`
        when the interface exists, and `False` otherwise.

        This value can be set to `False` to simulate
        when the interface is not available.

    Returns
    -------
    coin.SoSFImage
        An image object with the appropriate size, number of components
        (grayscale, grayscale and transparency, color,
        color and transparency), and byte data.

        It returns `None` if the interface is not available,
        or if there is a problem creating the image.
    """
    if gui:
        # from pivy import coin
        # from PySide import QtGui, QtSvg
        try:
            p = QtGui.QImage(filename)

            if p.isNull():
                _wrn("load_texture: " + _tr("image is Null"))

                if not os.path.exists(filename):
                    raise FileNotFoundError(
                        -1,
                        _tr("filename does not exist "
                            "on the system or "
                            "on the resource file"), filename)

            # This is buggy so it was de-activated.
            #
            # TODO: allow SVGs to use resolutions
            # if size and (".svg" in filename.lower()):
            #    # this is a pattern, not a texture
            #    if isinstance(size, int):
            #        size = (size, size)
            #    svgr = QtSvg.QSvgRenderer(filename)
            #    p = QtGui.QImage(size[0], size[1],
            #                     QtGui.QImage.Format_ARGB32)
            #    pa = QtGui.QPainter()
            #    pa.begin(p)
            #    svgr.render(pa)
            #    pa.end()
            # else:
            #    p = QtGui.QImage(filename)
            size = coin.SbVec2s(p.width(), p.height())
            buffersize = p.byteCount()
            width = size[0]
            height = size[1]
            numcomponents = int(buffersize / (width * height))

            img = coin.SoSFImage()
            byteList = bytearray()

            # The SoSFImage needs to be filled with bytes.
            # The pixel information is converted into a Qt color, gray,
            # red, green, blue, or transparency (alpha),
            # depending on the input image.
            for y in range(height):
                # line = width*numcomponents*(height-(y));
                for x in range(width):
                    rgba = p.pixel(x, y)
                    if numcomponents <= 2:
                        byteList.append(QtGui.qGray(rgba))

                        if numcomponents == 2:
                            byteList.append(QtGui.qAlpha(rgba))

                    elif numcomponents <= 4:
                        byteList.append(QtGui.qRed(rgba))
                        byteList.append(QtGui.qGreen(rgba))
                        byteList.append(QtGui.qBlue(rgba))

                        if numcomponents == 4:
                            byteList.append(QtGui.qAlpha(rgba))
                    # line += numcomponents

            _bytes = bytes(byteList)
            img.setValue(size, numcomponents, _bytes)
        except FileNotFoundError as exc:
            _wrn("load_texture: {0}, {1}".format(exc.strerror, exc.filename))
            return None
        except Exception as exc:
            _wrn(str(exc))
            _wrn("load_texture: " + _tr("unable to load texture"))
            return None
        else:
            return img
    return None
Example #20
0
def _create_objects(doc=None,
                    font_file=None,
                    hatch_file=None,
                    hatch_name=None):
    """Create the objects of the test file."""
    if not doc:
        doc = App.activeDocument()
    if not doc:
        doc = App.newDocument()

    # Drafting ##############################################################

    # Line
    _msg(16 * "-")
    _msg("Line")
    Draft.make_line(Vector(0, 0, 0), Vector(500, 500, 0))
    _set_text(["Line"], Vector(0, -200, 0))

    # Wire
    _msg(16 * "-")
    _msg("Wire")
    Draft.make_wire(
        [Vector(1000, 0, 0),
         Vector(1500, 250, 0),
         Vector(1500, 500, 0)])
    _set_text(["Wire"], Vector(1000, -200, 0))

    # Fillet
    _msg(16 * "-")
    _msg("Fillet")
    line_1 = Draft.make_line(Vector(2000, 0, 0), Vector(2000, 500, 0))
    line_2 = Draft.make_line(Vector(2000, 500, 0), Vector(2500, 500, 0))
    if App.GuiUp:
        line_1.ViewObject.DrawStyle = "Dotted"
        line_2.ViewObject.DrawStyle = "Dotted"
    doc.recompute()
    Draft.make_fillet([line_1, line_2], 400)
    _set_text(["Fillet"], Vector(2000, -200, 0))

    # Circular arc
    _msg(16 * "-")
    _msg("Circular arc")
    arc = Draft.make_circle(250, startangle=90, endangle=270)
    arc.Placement.Base = Vector(3250, 250, 0)
    _set_text(["Circular arc"], Vector(3000, -200, 0))

    # Circular arc 3 points
    _msg(16 * "-")
    _msg("Circular arc 3 points")
    Draft.make_arc_3points(
        [Vector(4250, 0, 0),
         Vector(4000, 250, 0),
         Vector(4250, 500, 0)])
    _set_text(["Circular arc 3 points"], Vector(4000, -200, 0))

    # Circle
    _msg(16 * "-")
    _msg("Circle")
    circle = Draft.make_circle(250)
    circle.Placement.Base = Vector(5250, 250, 0)
    _set_text(["Circle"], Vector(5000, -200, 0))

    # Ellipse
    _msg(16 * "-")
    _msg("Ellipse")
    ellipse = Draft.make_ellipse(250, 150)
    ellipse.Placement.Base = Vector(6250, 150, 0)
    _set_text(["Ellipse"], Vector(6000, -200, 0))

    # Rectangle
    _msg(16 * "-")
    _msg("Rectangle")
    rectangle = Draft.make_rectangle(500, 300, 0)
    rectangle.Placement.Base = Vector(7000, 0, 0)
    _set_text(["Rectangle"], Vector(7000, -200, 0))

    # Polygon
    _msg(16 * "-")
    _msg("Polygon")
    polygon = Draft.make_polygon(5, 250)
    polygon.Placement.Base = Vector(8250, 250, 0)
    _set_text(["Polygon"], Vector(8000, -200, 0))

    # BSpline
    _msg(16 * "-")
    _msg("BSpline")
    Draft.make_bspline([
        Vector(9000, 0, 0),
        Vector(9100, 200, 0),
        Vector(9400, 300, 0),
        Vector(9500, 500, 0)
    ])
    _set_text(["BSpline"], Vector(9000, -200, 0))

    # Cubic bezier
    _msg(16 * "-")
    _msg("Cubic bezier")
    Draft.make_bezcurve([
        Vector(10000, 0, 0),
        Vector(10000, 500, 0),
        Vector(10500, 0, 0),
        Vector(10500, 500, 0)
    ],
                        degree=3)
    _set_text(["Cubic bezier"], Vector(10000, -200, 0))

    # N-degree bezier
    _msg(16 * "-")
    _msg("N-degree bezier")
    Draft.make_bezcurve([
        Vector(11000, 0, 0),
        Vector(11100, 400, 0),
        Vector(11250, 250, 0),
        Vector(11400, 100, 0),
        Vector(11500, 500, 0)
    ])
    _set_text(["N-degree bezier"], Vector(11000, -200, 0))

    # Point
    _msg(16 * "-")
    _msg("Point")
    point = Draft.make_point(12000, 0, 0)
    if App.GuiUp:
        point.ViewObject.PointSize = 10
    _set_text(["Point"], Vector(12000, -200, 0))

    # Facebinder
    _msg(16 * "-")
    _msg("Facebinder")
    box = doc.addObject("Part::Box", "Box")
    box.Length = 200
    box.Width = 500
    box.Height = 100
    box.Placement.Base = Vector(13000, 0, 0)
    if App.GuiUp:
        box.ViewObject.Visibility = False
    facebinder = Draft.make_facebinder([(box, ("Face1", "Face3", "Face6"))])
    facebinder.Extrusion = 10
    _set_text(["Facebinder"], Vector(13000, -200, 0))

    # Shapestring
    _msg(16 * "-")
    _msg("Shapestring")
    try:
        shape_string = Draft.make_shapestring("Testing", font_file, 100)
        shape_string.Placement.Base = Vector(14000, 0)
    except Exception:
        _wrn("Shapestring could not be created")
        _wrn("Possible cause: the font file may not exist")
        _wrn(font_file)
    _set_text(["Shapestring"], Vector(14000, -200, 0))

    # Hatch
    _msg(16 * "-")
    _msg("Hatch")
    rectangle = Draft.make_rectangle(500, 300, 0)
    rectangle.Placement.Base = Vector(15000, 0, 0)
    rectangle.MakeFace = True
    if App.GuiUp:
        rectangle.ViewObject.Visibility = False
    try:
        Draft.make_hatch(rectangle,
                         hatch_file,
                         hatch_name,
                         scale=10,
                         rotation=45)
    except Exception:
        _wrn("Hatch could not be created")
        _wrn("Possible cause: the hatch file may not exist")
        _wrn(hatch_file)
    _set_text(["Hatch"], Vector(15000, -200, 0))

    # Annotation ############################################################

    # Text
    _msg(16 * "-")
    _msg("Text")
    text = Draft.make_text(["Testing", "text"], Vector(0, 2100, 0))
    if App.GuiUp:
        text.ViewObject.FontSize = 100
    _set_text(["Text"], Vector(0, 1800, 0))

    # Linear dimension
    _msg(16 * "-")
    _msg("Linear dimension")
    dimension = Draft.make_linear_dimension(Vector(1500, 2000, 0),
                                            Vector(1500, 2400, 0),
                                            Vector(1000, 2200, 0))
    if App.GuiUp:
        dimension.ViewObject.ArrowSize = 15
        dimension.ViewObject.ExtLines = 0
        dimension.ViewObject.ExtOvershoot = 50
        dimension.ViewObject.DimOvershoot = 25
        dimension.ViewObject.FontSize = 50
        dimension.ViewObject.Decimals = 1
        dimension.ViewObject.ShowUnit = False

    line = Draft.make_wire([Vector(1500, 2600, 0), Vector(1500, 3000, 0)])
    doc.recompute()
    dimension = Draft.make_linear_dimension_obj(line, 1, 2,
                                                Vector(1000, 2800, 0))
    if App.GuiUp:
        dimension.ViewObject.ArrowSize = 15
        dimension.ViewObject.ArrowType = "Arrow"
        dimension.ViewObject.ExtLines = -50
        dimension.ViewObject.ExtOvershoot = 50
        dimension.ViewObject.DimOvershoot = 25
        dimension.ViewObject.FontSize = 50
        dimension.ViewObject.Decimals = 1
        dimension.ViewObject.ShowUnit = False

    _set_text(["Dimension"], Vector(1000, 1800, 0))

    # Radius and diameter dimension
    _msg(16 * "-")
    _msg("Radius and diameter dimension")
    circle = Draft.make_circle(200)
    circle.Placement.Base = Vector(2200, 2200, 0)
    circle.MakeFace = False
    doc.recompute()
    dimension = Draft.make_radial_dimension_obj(circle, 1, "radius",
                                                Vector(2300, 2300, 0))
    if App.GuiUp:
        dimension.ViewObject.ArrowSize = 15
        dimension.ViewObject.FontSize = 50
        dimension.ViewObject.Decimals = 1
        dimension.ViewObject.ShowUnit = False

    circle = Draft.make_circle(200)
    circle.Placement.Base = Vector(2200, 2800, 0)
    circle.MakeFace = False
    doc.recompute()
    dimension = Draft.make_radial_dimension_obj(circle, 1, "diameter",
                                                Vector(2300, 2900, 0))
    if App.GuiUp:
        dimension.ViewObject.ArrowSize = 15
        dimension.ViewObject.FontSize = 50
        dimension.ViewObject.Decimals = 1
        dimension.ViewObject.ShowUnit = False
    _set_text(["Radius dimension", "Diameter dimension"],
              Vector(2000, 1800, 0))

    # Angular dimension
    _msg(16 * "-")
    _msg("Angular dimension")
    Draft.make_line(Vector(3000, 2000, 0), Vector(3500, 2000, 0))
    Draft.make_line(Vector(3000, 2000, 0), Vector(3500, 2500, 0))
    dimension = Draft.make_angular_dimension(Vector(3000, 2000, 0), [0, 45],
                                             Vector(3250, 2250, 0))
    if App.GuiUp:
        dimension.ViewObject.ArrowSize = 15
        dimension.ViewObject.FontSize = 50
        dimension.ViewObject.Decimals = 1
    _set_text(["Angle dimension"], Vector(3000, 1800, 0))

    # Label
    _msg(16 * "-")
    _msg("Label")
    place = App.Placement(Vector(4250, 2250, 0), App.Rotation())
    label = Draft.make_label(target_point=Vector(4000, 2000, 0),
                             placement=place,
                             custom_text="Example label",
                             distance=-100)
    label.Text = "Testing"
    if App.GuiUp:
        label.ViewObject.ArrowSize = 15
        label.ViewObject.TextSize = 50
    doc.recompute()
    _set_text(["Label"], Vector(4000, 1800, 0))

    # Array #################################################################

    # Orthogonal array
    _msg(16 * "-")
    _msg("Orthogonal array")
    rectangle = Draft.make_rectangle(100, 50)
    rectangle.Placement.Base = Vector(0, 4000, 0)
    if App.GuiUp:
        rectangle.ViewObject.Visibility = False
    Draft.make_ortho_array(rectangle,
                           Vector(200, 0, 0),
                           Vector(0, 150, 0),
                           Vector(0, 0, 0),
                           3,
                           2,
                           1,
                           use_link=False)
    _set_text(["Orthogonal array"], Vector(0, 3800, 0))

    # Orthogonal link array
    _msg(16 * "-")
    _msg("Orthogonal link array")
    rectangle = Draft.make_rectangle(50, 50)
    rectangle.Placement.Base = Vector(1000, 4000, 0)
    if App.GuiUp:
        rectangle.ViewObject.Visibility = False
    Draft.make_ortho_array(rectangle,
                           Vector(200, 0, 0),
                           Vector(0, 150, 0),
                           Vector(0, 0, 0),
                           3,
                           2,
                           1,
                           use_link=True)
    _set_text(["Orthogonal link array"], Vector(1000, 3800, 0))

    # Polar array
    _msg(16 * "-")
    _msg("Polar array")
    wire = Draft.make_wire(
        [Vector(2000, 4050, 0),
         Vector(2000, 4000, 0),
         Vector(2100, 4000, 0)])
    if App.GuiUp:
        wire.ViewObject.Visibility = False
    Draft.make_polar_array(wire, 4, 90, Vector(2000, 4250, 0), use_link=False)
    _set_text(["Polar array"], Vector(2000, 3800, 0))

    # Polar link array
    _msg(16 * "-")
    _msg("Polar link array")
    wire = Draft.make_wire(
        [Vector(3000, 4050, 0),
         Vector(3000, 4000, 0),
         Vector(3050, 4000, 0)])
    if App.GuiUp:
        wire.ViewObject.Visibility = False
    Draft.make_polar_array(wire, 4, 90, Vector(3000, 4250, 0), use_link=True)
    _set_text(["Polar link array"], Vector(3000, 3800, 0))

    # Circular array
    _msg(16 * "-")
    _msg("Circular array")
    polygon = Draft.make_polygon(5, 30)
    polygon.Placement.Base = Vector(4250, 4250, 0)
    if App.GuiUp:
        polygon.ViewObject.Visibility = False
    Draft.make_circular_array(polygon,
                              110,
                              100,
                              3,
                              1,
                              Vector(0, 0, 1),
                              Vector(0, 0, 0),
                              use_link=False)
    _set_text(["Circular array"], Vector(4000, 3800, 0))

    # Circular link array
    _msg(16 * "-")
    _msg("Circular link array")
    polygon = Draft.make_polygon(6, 30)
    polygon.Placement.Base = Vector(5250, 4250, 0)
    if App.GuiUp:
        polygon.ViewObject.Visibility = False
    Draft.make_circular_array(polygon,
                              110,
                              100,
                              3,
                              1,
                              Vector(0, 0, 1),
                              Vector(0, 0, 0),
                              use_link=True)
    _set_text(["Circular link array"], Vector(5000, 3800, 0))

    # Path array
    _msg(16 * "-")
    _msg("Path array")
    polygon = Draft.make_polygon(3, 30)
    polygon.Placement.Base = Vector(6000, 4000, 0)
    if App.GuiUp:
        polygon.ViewObject.Visibility = False
    spline = Draft.make_bspline([
        Vector(6000, 4000, 0),
        Vector(6100, 4200, 0),
        Vector(6400, 4300, 0),
        Vector(6500, 4500, 0)
    ])
    Draft.make_path_array(polygon, spline, 5, use_link=False)
    _set_text(["Path array"], Vector(6000, 3800, 0))

    # Path link array
    _msg(16 * "-")
    _msg("Path link array")
    polygon = Draft.make_polygon(4, 30)
    polygon.Placement.Base = Vector(7000, 4000, 0)
    if App.GuiUp:
        polygon.ViewObject.Visibility = False
    spline = Draft.make_bspline([
        Vector(7000, 4000, 0),
        Vector(7100, 4200, 0),
        Vector(7400, 4300, 0),
        Vector(7500, 4500, 0)
    ])
    Draft.make_path_array(polygon, spline, 5, use_link=True)
    _set_text(["Path link array"], Vector(7000, 3800, 0))

    # Point array
    _msg(16 * "-")
    _msg("Point array")
    polygon = Draft.make_polygon(3, 30)
    polygon.Placement.Base = Vector(8000, 4000, 0)
    point_1 = Draft.make_point(8030, 4030, 0)
    point_2 = Draft.make_point(8030, 4250, 0)
    point_3 = Draft.make_point(8470, 4250, 0)
    point_4 = Draft.make_point(8470, 4470, 0)
    add_list, delete_list = Draft.upgrade([point_1, point_2, point_3, point_4])
    compound = add_list[0]
    if App.GuiUp:
        compound.ViewObject.PointSize = 5
    Draft.make_point_array(polygon, compound, use_link=False)
    _set_text(["Point array"], Vector(8000, 3800, 0))

    # Point link array
    _msg(16 * "-")
    _msg("Point link array")
    polygon = Draft.make_polygon(4, 30)
    polygon.Placement.Base = Vector(9000, 4000, 0)
    point_1 = Draft.make_point(9030, 4030, 0)
    point_2 = Draft.make_point(9030, 4250, 0)
    point_3 = Draft.make_point(9470, 4250, 0)
    point_4 = Draft.make_point(9470, 4470, 0)
    add_list, delete_list = Draft.upgrade([point_1, point_2, point_3, point_4])
    compound = add_list[0]
    if App.GuiUp:
        compound.ViewObject.PointSize = 5
    Draft.make_point_array(polygon, compound, use_link=True)
    _set_text(["Point link array"], Vector(9000, 3800, 0))

    # Miscellaneous #########################################################

    # Mirror
    _msg(16 * "-")
    _msg("Mirror")
    wire = Draft.make_wire(
        [Vector(0, 6000, 0),
         Vector(150, 6200, 0),
         Vector(500, 6000, 0)])
    Draft.mirror(wire, Vector(0, 6250, 0), Vector(500, 6250, 0))
    _set_text(["Mirror"], Vector(0, 5800, 0))

    # Clone
    _msg(16 * "-")
    _msg("Clone")
    wire = Draft.make_wire(
        [Vector(1000, 6000, 0),
         Vector(1150, 6200, 0),
         Vector(1500, 6000, 0)])
    Draft.make_clone(wire, Vector(0, 300, 0))
    _set_text(["Clone"], Vector(1000, 5800, 0))

    # Shape2DView
    _msg(16 * "-")
    _msg("Shape2DView")
    place = App.Placement(Vector(2000, 6000, 0),
                          App.Rotation(Vector(0, 0, 1), Vector(1, 2, 3)))
    box = doc.addObject("Part::Box", "Box")
    box.Length = 200
    box.Width = 500
    box.Height = 100
    box.Placement = place
    if App.GuiUp:
        box.ViewObject.Visibility = False
    Draft.make_shape2dview(box)
    _set_text(["Shape2DView"], Vector(2000, 5800, 0))

    # WorkingPlaneProxy
    _msg(16 * "-")
    _msg("WorkingPlaneProxy")
    place = App.Placement(Vector(3250, 6250, 0), App.Rotation())
    proxy = Draft.make_workingplaneproxy(place)
    if App.GuiUp:
        proxy.ViewObject.DisplaySize = 500
        proxy.ViewObject.ArrowSize = 50
    _set_text(["WorkingPlaneProxy"], Vector(3000, 5800, 0))

    # Layer
    _msg(16 * "-")
    _msg("Layer")
    layer = Draft.make_layer("Custom layer",
                             line_color=(0.33, 0.0, 0.49),
                             shape_color=(0.56, 0.89, 0.56),
                             line_width=4,
                             transparency=50)
    box = doc.addObject("Part::Box", "Box")
    box.Length = 200
    box.Width = 500
    box.Height = 100
    box.Placement.Base = Vector(4000, 6000, 0)
    sphere = doc.addObject("Part::Sphere", "Sphere")
    sphere.Radius = 100
    sphere.Placement.Base = Vector(4400, 6250, 0)
    layer.Proxy.addObject(layer, box)
    layer.Proxy.addObject(layer, sphere)
    _set_text(["Layer"], Vector(4000, 5800, 0))

    doc.recompute()