Draft: move make_label function to its own module
Also perform several improvements such as PEP8 cleanup, writing complete docstrings, type checking the input arguments, and deprecating the older call. Update `Draft.py`, the Gui Command, the unit test, and test script as well.
This commit is contained in:
@@ -113,6 +113,7 @@ SET(Draft_make_functions
|
||||
draftmake/make_ellipse.py
|
||||
draftmake/make_facebinder.py
|
||||
draftmake/make_fillet.py
|
||||
draftmake/make_label.py
|
||||
draftmake/make_line.py
|
||||
draftmake/make_orthoarray.py
|
||||
draftmake/make_patharray.py
|
||||
|
||||
@@ -398,17 +398,16 @@ if gui:
|
||||
_ViewProviderAngularDimension = ViewProviderAngularDimension
|
||||
|
||||
|
||||
from draftobjects.label import make_label
|
||||
from draftobjects.label import Label
|
||||
from draftobjects.label import (Label,
|
||||
DraftLabel)
|
||||
|
||||
makeLabel = make_label
|
||||
DraftLabel = Label
|
||||
from draftmake.make_label import (make_label,
|
||||
makeLabel)
|
||||
|
||||
if gui:
|
||||
from draftviewproviders.view_label import ViewProviderLabel
|
||||
ViewProviderDraftLabel = ViewProviderLabel
|
||||
|
||||
|
||||
from draftobjects.text import (Text,
|
||||
DraftText)
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import draftguitools.gui_base_original as gui_base_original
|
||||
import draftguitools.gui_tool_utils as gui_tool_utils
|
||||
import draftguitools.gui_trackers as trackers
|
||||
import draftutils.utils as utils
|
||||
|
||||
from draftutils.messages import _msg
|
||||
from draftutils.translate import translate
|
||||
|
||||
@@ -56,7 +57,19 @@ class Label(gui_base_original.Creator):
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
_tip = ("Creates a label, "
|
||||
"optionally attached to a selected object or element.")
|
||||
"optionally attached to a selected object or subelement.\n"
|
||||
"\n"
|
||||
"First select a vertex, an edge, or a face of an object, "
|
||||
"then call this command,\n"
|
||||
"and then set the position of the leader line "
|
||||
"and the textual label.\n"
|
||||
"The label will be able to display information "
|
||||
"about this object, and about the selected subelement,\n"
|
||||
"if any.\n"
|
||||
"\n"
|
||||
"If many objects or many subelements are selected, "
|
||||
"only the first one in each case\n"
|
||||
"will be used to provide information to the label.")
|
||||
|
||||
return {'Pixmap': 'Draft_Label',
|
||||
'Accel': "D, L",
|
||||
@@ -107,6 +120,7 @@ class Label(gui_base_original.Creator):
|
||||
h = App.Vector(1, 0, 0)
|
||||
n = App.Vector(0, 0, 1)
|
||||
r = App.Rotation()
|
||||
|
||||
if abs(DraftVecUtils.angle(v, h, n)) <= math.pi/4:
|
||||
direction = "Horizontal"
|
||||
dist = -dist
|
||||
@@ -117,38 +131,45 @@ class Label(gui_base_original.Creator):
|
||||
else:
|
||||
direction = "Vertical"
|
||||
dist = -dist
|
||||
tp = "targetpoint=FreeCAD." + str(targetpoint) + ", "
|
||||
|
||||
tp = DraftVecUtils.toString(targetpoint)
|
||||
sel = ""
|
||||
if self.sel:
|
||||
if self.sel.SubElementNames:
|
||||
sub = "'" + self.sel.SubElementNames[0] + "'"
|
||||
else:
|
||||
sub = "()"
|
||||
sel = "target="
|
||||
sel += "("
|
||||
sub = "[]"
|
||||
sel = "["
|
||||
sel += "FreeCAD.ActiveDocument." + self.sel.Object.Name + ", "
|
||||
sel += sub
|
||||
sel += "),"
|
||||
pl = "placement=FreeCAD.Placement"
|
||||
sel += "]"
|
||||
|
||||
pl = "FreeCAD.Placement"
|
||||
pl += "("
|
||||
pl += "FreeCAD." + str(basepoint) + ", "
|
||||
pl += DraftVecUtils.toString(basepoint) + ", "
|
||||
pl += "FreeCAD.Rotation" + str(r.Q)
|
||||
pl += ")"
|
||||
App.ActiveDocument.openTransaction("Create Label")
|
||||
|
||||
Gui.addModule("Draft")
|
||||
_cmd = "Draft.makeLabel"
|
||||
_cmd = "Draft.make_label"
|
||||
_cmd += "("
|
||||
_cmd += tp
|
||||
_cmd += sel
|
||||
_cmd += "direction='" + direction + "', "
|
||||
_cmd += "distance=" + str(dist) + ", "
|
||||
_cmd += "labeltype='" + self.labeltype + "', "
|
||||
_cmd += pl
|
||||
_cmd += "target_point=" + tp + ", "
|
||||
_cmd += "placement=" + pl + ", "
|
||||
if sel:
|
||||
_cmd += "target=" + sel + ", "
|
||||
_cmd += "label_type=" + "'" + self.labeltype + "'" + ", "
|
||||
# _cmd += "custom_text=" + "'Label'" + ", "
|
||||
_cmd += "direction=" + "'" + direction + "'" + ", "
|
||||
_cmd += "distance=" + str(dist)
|
||||
_cmd += ")"
|
||||
Gui.doCommand("l = " + _cmd)
|
||||
Gui.doCommand("Draft.autogroup(l)")
|
||||
App.ActiveDocument.recompute()
|
||||
App.ActiveDocument.commitTransaction()
|
||||
|
||||
# Commit the creation instructions through the parent class,
|
||||
# the Creator class
|
||||
_cmd_list = ['_label_ = ' + _cmd,
|
||||
'Draft.autogroup(_label_)',
|
||||
'FreeCAD.ActiveDocument.recompute()']
|
||||
self.commit(translate("draft", "Create Label"),
|
||||
_cmd_list)
|
||||
self.finish()
|
||||
|
||||
def action(self, arg):
|
||||
|
||||
336
src/Mod/Draft/draftmake/make_label.py
Normal file
336
src/Mod/Draft/draftmake/make_label.py
Normal file
@@ -0,0 +1,336 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
|
||||
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
|
||||
# * Copyright (c) 2020 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * FreeCAD is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with FreeCAD; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Provides the make function to create Draft Label objects."""
|
||||
## @package make_label
|
||||
# \ingroup DRAFT
|
||||
# \brief Provides the make function to create Draft Label objects.
|
||||
|
||||
import FreeCAD as App
|
||||
import draftutils.gui_utils as gui_utils
|
||||
import draftutils.utils as utils
|
||||
|
||||
from draftutils.messages import _msg, _wrn, _err
|
||||
from draftutils.translate import _tr
|
||||
from draftobjects.label import Label
|
||||
|
||||
if App.GuiUp:
|
||||
from draftviewproviders.view_label import ViewProviderLabel
|
||||
|
||||
|
||||
def make_label(target_point=App.Vector(0, 0, 0),
|
||||
placement=App.Vector(30, 30, 0),
|
||||
target=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: list, optional
|
||||
It defaults to `None`.
|
||||
The list should be a `LinkSubList`, that is, it should contain
|
||||
two elements; the first element should be an object which will be used
|
||||
to provide information to the label; the second element should be
|
||||
a string indicating a subelement name, either `'VertexN'`, `'EdgeN'`,
|
||||
or `'FaceN'` which exists within the first element.
|
||||
In this case `'N'` is a number that starts with `1`
|
||||
and goes up to the maximum number of vertices, edges, or faces.
|
||||
::
|
||||
target = [Part::Feature, 'Edge1']
|
||||
|
||||
The target may not need a subelement, in which case the second
|
||||
element of the list may be empty.
|
||||
::
|
||||
target = [Part::Feature, ]
|
||||
|
||||
This `LinkSubList` can be obtained from the `Gui::Selection`
|
||||
module.
|
||||
::
|
||||
sel_object = Gui.Selection.getSelectionEx()[0]
|
||||
object = sel_object.Object
|
||||
subelement = sel_object.SubElementNames[0]
|
||||
target = [object, subelement]
|
||||
|
||||
label_type: str, optional
|
||||
It defaults to `'Custom'`.
|
||||
It can be `'Custom'`, `'Name'`, `'Label'`, `'Position'`,
|
||||
`'Length'`, `'Area'`, `'Volume'`, `'Tag'`, or `'Material'`.
|
||||
It indicates the type of information that will be shown in the label.
|
||||
|
||||
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, optional
|
||||
It defaults to `'Label'`.
|
||||
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(_tr("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(_tr("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(_tr("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)
|
||||
|
||||
_msg("target: {}".format(target))
|
||||
if target:
|
||||
try:
|
||||
utils.type_check([(target, (tuple, list))],
|
||||
name=_name)
|
||||
except TypeError:
|
||||
_err(_tr("Wrong input: must be a LinkSubList of two elements. "
|
||||
"For example, [object, 'Edge1']"))
|
||||
return None
|
||||
|
||||
target = list(target)
|
||||
if len(target) == 1:
|
||||
target.append([])
|
||||
|
||||
_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(_tr("Wrong input: must be a string, "
|
||||
"'Custom', 'Name', 'Label', 'Position', "
|
||||
"'Length', 'Area', 'Volume', 'Tag', or 'Material'."))
|
||||
return None
|
||||
|
||||
if label_type not in ("Custom", "Name", "Label", "Position",
|
||||
"Length", "Area", "Volume", "Tag", "Material"):
|
||||
_err(_tr("Wrong input: must be a string, "
|
||||
"'Custom', 'Name', 'Label', 'Position', "
|
||||
"'Length', 'Area', 'Volume', 'Tag', or 'Material'."))
|
||||
return None
|
||||
|
||||
_msg("custom_text: {}".format(custom_text))
|
||||
if not custom_text:
|
||||
custom_text = "Label"
|
||||
try:
|
||||
utils.type_check([(custom_text, str)], name=_name)
|
||||
except TypeError:
|
||||
_err(_tr("Wrong input: must be a string."))
|
||||
return None
|
||||
|
||||
_msg("direction: {}".format(direction))
|
||||
if not direction:
|
||||
direction = "Horizontal"
|
||||
try:
|
||||
utils.type_check([(direction, str)], name=_name)
|
||||
except TypeError:
|
||||
_err(_tr("Wrong input: must be a string, "
|
||||
"'Horizontal', 'Vertical', or 'Custom'."))
|
||||
return None
|
||||
|
||||
if direction not in ("Horizontal", "Vertical", "Custom"):
|
||||
_err(_tr("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(_tr("Wrong input: must be a number."))
|
||||
return None
|
||||
|
||||
if points:
|
||||
_msg("points: {}".format(points))
|
||||
|
||||
_err_msg = _tr("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(new_obj)
|
||||
|
||||
new_obj.TargetPoint = target_point
|
||||
new_obj.Placement = placement
|
||||
if target:
|
||||
new_obj.Target = target
|
||||
|
||||
new_obj.LabelType = label_type
|
||||
new_obj.CustomText = custom_text
|
||||
|
||||
new_obj.StraightDirection = direction
|
||||
new_obj.StraightDistance = distance
|
||||
if points:
|
||||
if direction != "Custom":
|
||||
_wrn(_tr("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
|
||||
|
||||
|
||||
def makeLabel(targetpoint=None, target=None, direction=None,
|
||||
distance=None, labeltype=None, placement=None):
|
||||
"""Create a Label. DEPRECATED. Use 'make_label'."""
|
||||
utils.use_instead("make_label")
|
||||
|
||||
return make_label(target_point=targetpoint,
|
||||
placement=placement,
|
||||
target=target,
|
||||
label_type=labeltype,
|
||||
direction=direction,
|
||||
distance=distance)
|
||||
@@ -29,95 +29,25 @@
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the object code for Draft Label.
|
||||
|
||||
import FreeCAD as App
|
||||
import math
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import DraftGeomUtils
|
||||
import draftutils.gui_utils as gui_utils
|
||||
import draftutils.utils as utils
|
||||
|
||||
import FreeCAD as App
|
||||
|
||||
from draftobjects.draft_annotation import DraftAnnotation
|
||||
|
||||
if App.GuiUp:
|
||||
from draftviewproviders.view_label import ViewProviderLabel
|
||||
|
||||
|
||||
|
||||
def make_label(targetpoint=None, target=None, direction=None,
|
||||
distance=None, labeltype=None, placement=None):
|
||||
"""
|
||||
make_label(targetpoint, target, direction, distance, labeltype, placement)
|
||||
|
||||
Function to create a Draft Label annotation object
|
||||
|
||||
Parameters
|
||||
----------
|
||||
targetpoint : App::Vector
|
||||
To be completed
|
||||
|
||||
target : LinkSub
|
||||
To be completed
|
||||
|
||||
direction : String
|
||||
Straight direction of the label
|
||||
["Horizontal","Vertical","Custom"]
|
||||
|
||||
distance : Quantity
|
||||
Length of the straight segment of label leader line
|
||||
|
||||
labeltype : String
|
||||
Label type in
|
||||
["Custom","Name","Label","Position",
|
||||
"Length","Area","Volume","Tag","Material"]
|
||||
|
||||
placement : Base::Placement
|
||||
To be completed
|
||||
|
||||
Returns
|
||||
-------
|
||||
obj : App::DocumentObject
|
||||
Newly created label object
|
||||
"""
|
||||
obj = App.ActiveDocument.addObject("App::FeaturePython",
|
||||
"dLabel")
|
||||
Label(obj)
|
||||
if App.GuiUp:
|
||||
ViewProviderLabel(obj.ViewObject)
|
||||
if targetpoint:
|
||||
obj.TargetPoint = targetpoint
|
||||
if target:
|
||||
obj.Target = target
|
||||
if direction:
|
||||
obj.StraightDirection = direction
|
||||
if distance:
|
||||
obj.StraightDistance = distance
|
||||
if labeltype:
|
||||
obj.LabelType = labeltype
|
||||
if placement:
|
||||
obj.Placement = placement
|
||||
|
||||
if App.GuiUp:
|
||||
gui_utils.format_object(obj)
|
||||
gui_utils.select(obj)
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
class Label(DraftAnnotation):
|
||||
"""The Draft Label object"""
|
||||
|
||||
def __init__(self, obj):
|
||||
|
||||
super(Label, self).__init__(obj, "Label")
|
||||
|
||||
self.init_properties(obj)
|
||||
|
||||
obj.Proxy = self
|
||||
|
||||
|
||||
def init_properties(self, obj):
|
||||
"""Add properties to the object and set them"""
|
||||
|
||||
_tip = QT_TRANSLATE_NOOP("App::Property",
|
||||
"The placement of this object")
|
||||
obj.addProperty("App::PropertyPlacement", "Placement", "Base", _tip)
|
||||
@@ -213,3 +143,7 @@ class Label(DraftAnnotation):
|
||||
'''Do something when a property has changed'''
|
||||
|
||||
return
|
||||
|
||||
|
||||
# Alias for compatibility with v0.18 and earlier
|
||||
DraftLabel = Label
|
||||
|
||||
@@ -354,9 +354,10 @@ def _create_objects(doc=None,
|
||||
_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 = 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
|
||||
|
||||
@@ -321,7 +321,7 @@ class DraftCreation(unittest.TestCase):
|
||||
_msg(" target_point={0}, "
|
||||
"distance={1}".format(target_point, distance))
|
||||
_msg(" placement={}".format(placement))
|
||||
obj = Draft.make_label(targetpoint=target_point,
|
||||
obj = Draft.make_label(target_point=target_point,
|
||||
distance=distance,
|
||||
placement=placement)
|
||||
self.doc.recompute()
|
||||
|
||||
Reference in New Issue
Block a user