Draft: new Draft_OrthoArray command

It replaces the older `Draft_Array` command, and provides
a task panel to select the properties, similar to the
`Draft_PolarArray` and `Draft_CircularArray` commands.

It can also create `App::Links` directly from this task
panel, so it also replaces the `Draft_LinkArray`
introduced by the LinkMerge.
This commit is contained in:
vocx-fc
2020-02-02 14:04:22 -06:00
committed by Yorik van Havre
parent 2a857dcd81
commit 3d2fb0127e
10 changed files with 1041 additions and 1 deletions

View File

@@ -51,6 +51,7 @@ class ArchWorkbench(FreeCADGui.Workbench):
import DraftGui
from draftguitools import gui_circulararray
from draftguitools import gui_polararray
from draftguitools import gui_orthoarray
from draftguitools import gui_arrays
import Arch_rc
import Arch

View File

@@ -60,12 +60,14 @@ SET(Draft_utilities
SET(Draft_objects
draftobjects/__init__.py
draftobjects/circulararray.py
draftobjects/orthoarray.py
draftobjects/polararray.py
)
SET(Draft_view_providers
draftviewproviders/__init__.py
draftviewproviders/view_circulararray.py
draftviewproviders/view_orthoarray.py
draftviewproviders/view_polararray.py
)
@@ -73,6 +75,7 @@ SET(Draft_GUI_tools
draftguitools/__init__.py
draftguitools/gui_base.py
draftguitools/gui_circulararray.py
draftguitools/gui_orthoarray.py
draftguitools/gui_polararray.py
draftguitools/gui_arrays.py
)
@@ -80,6 +83,7 @@ SET(Draft_GUI_tools
SET(Draft_task_panels
drafttaskpanels/__init__.py
drafttaskpanels/task_circulararray.py
drafttaskpanels/task_orthoarray.py
drafttaskpanels/task_polararray.py
)

View File

@@ -82,6 +82,7 @@ class DraftWorkbench(FreeCADGui.Workbench):
import DraftFillet
from draftguitools import gui_circulararray
from draftguitools import gui_polararray
from draftguitools import gui_orthoarray
from draftguitools import gui_arrays
FreeCADGui.addLanguagePath(":/translations")
FreeCADGui.addIconPath(":/icons")

View File

@@ -152,6 +152,7 @@
<file>ui/preferences-oca.ui</file>
<file>ui/preferences-svg.ui</file>
<file>ui/TaskPanel_CircularArray.ui</file>
<file>ui/TaskPanel_OrthoArray.ui</file>
<file>ui/TaskPanel_PolarArray.ui</file>
<file>ui/TaskSelectPlane.ui</file>
<file>ui/TaskShapeString.ui</file>

View File

@@ -0,0 +1,441 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DraftOrthoArrayTaskPanel</class>
<widget class="QWidget" name="DraftOrthoArrayTaskPanel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>440</width>
<height>883</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>250</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Orthogonal array</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QGroupBox" name="main_group">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string/>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="6" column="0">
<widget class="QGroupBox" name="group_Z">
<property name="toolTip">
<string>Distance between the elements in the Z direction. Normally, only the Z value is necessary; the other two values can give an additional shift in their respective directions.</string>
</property>
<property name="title">
<string>Interval Z</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QGridLayout" name="grid_Z">
<item row="2" column="0">
<widget class="QLabel" name="label_Z_z">
<property name="text">
<string>Z</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_Z_y">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_Z_x">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::InputField" name="input_Z_x">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true"/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::InputField" name="input_Z_y">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true"/>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::InputField" name="input_Z_z">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true"/>
</property>
<property name="quantity" stdset="0">
<double>100.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="button_reset_Z">
<property name="toolTip">
<string>Reset the distances</string>
</property>
<property name="text">
<string>Reset Z</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="8" column="0">
<layout class="QVBoxLayout" name="vertical_layout">
<item>
<widget class="QCheckBox" name="checkbox_fuse">
<property name="toolTip">
<string>If checked, the resulting objects in the array will be fused if they touch each other</string>
</property>
<property name="text">
<string>Fuse</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkbox_link">
<property name="toolTip">
<string>If checked, the resulting objects in the array will be Links instead of simple copies</string>
</property>
<property name="text">
<string>Use Links</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="11" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="7" column="0">
<widget class="QGroupBox" name="group_copies">
<property name="toolTip">
<string>Number of elements in the array in the specified direction, including a copy of the original object. The number must be at least 1 in each direction.</string>
</property>
<property name="title">
<string>Number of elements</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<layout class="QGridLayout" name="grid_number">
<item row="0" column="0">
<widget class="QLabel" name="label_n_X">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_n_Z">
<property name="text">
<string>Z</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_n_Y">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinbox_n_X">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinbox_n_Y">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>2</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinbox_n_Z">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_icon">
<property name="text">
<string>(Placeholder for the icon)</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QGroupBox" name="group_X">
<property name="toolTip">
<string>Distance between the elements in the X direction. Normally, only the X value is necessary; the other two values can give an additional shift in their respective directions.</string>
</property>
<property name="title">
<string>Interval X</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="grid_X">
<item row="2" column="0">
<widget class="QLabel" name="label_X_z">
<property name="text">
<string>Z</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::InputField" name="input_X_x">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true"/>
</property>
<property name="quantity" stdset="0">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::InputField" name="input_X_y">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true"/>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::InputField" name="input_X_z">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true"/>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_X_x">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_X_y">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="button_reset_X">
<property name="toolTip">
<string>Reset the distances</string>
</property>
<property name="text">
<string>Reset X</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="5" column="0">
<widget class="QGroupBox" name="group_Y">
<property name="toolTip">
<string>Distance between the elements in the Y direction. Normally, only the Y value is necessary; the other two values can give an additional shift in their respective directions.</string>
</property>
<property name="title">
<string>Interval Y</string>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<layout class="QGridLayout" name="grid_Y">
<item row="0" column="0">
<widget class="QLabel" name="label_Y_x">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_Y_y">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_Y_z">
<property name="text">
<string>Z</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::InputField" name="input_Y_x">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true"/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::InputField" name="input_Y_y">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true"/>
</property>
<property name="quantity" stdset="0">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::InputField" name="input_Y_z">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="unit" stdset="0">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="button_reset_Y">
<property name="toolTip">
<string>Reset the distances</string>
</property>
<property name="text">
<string>Reset Y</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::InputField</class>
<extends>QLineEdit</extends>
<header>Gui/InputField.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>input_X_x</tabstop>
<tabstop>input_X_y</tabstop>
<tabstop>input_X_z</tabstop>
<tabstop>button_reset_X</tabstop>
<tabstop>checkbox_fuse</tabstop>
<tabstop>checkbox_link</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@@ -35,7 +35,7 @@ class ArrayGroupCommand:
def GetCommands(self):
"""Tuple of array commands."""
return tuple(["Draft_Array", "Draft_LinkArray",
return tuple(["Draft_OrthoArray",
"Draft_PolarArray", "Draft_CircularArray",
"Draft_PathArray", "Draft_PathLinkArray",
"Draft_PointArray"])

View File

@@ -0,0 +1,142 @@
"""Provide the Draft OrthoArray tool."""
## @package gui_orthoarray
# \ingroup DRAFT
# \brief Provide the Draft OrthoArray tool.
# ***************************************************************************
# * (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 *
# * *
# ***************************************************************************
import FreeCAD as App
import FreeCADGui as Gui
import Draft
import DraftGui
import Draft_rc
from . import gui_base
from drafttaskpanels import task_orthoarray
if App.GuiUp:
from PySide.QtCore import QT_TRANSLATE_NOOP
# import DraftTools
from draftutils.translate import translate
# from DraftGui import displayExternal
from pivy import coin
else:
def QT_TRANSLATE_NOOP(context, text):
return text
def translate(context, text):
return text
def _tr(text):
"""Translate the text with the context set."""
return translate("Draft", text)
# So the resource file doesn't trigger errors from code checkers (flake8)
True if Draft_rc.__name__ else False
class GuiCommandOrthoArray(gui_base.GuiCommandBase):
"""Gui command for the OrthoArray tool."""
def __init__(self):
super().__init__()
self.command_name = "OrthoArray"
# self.location = None
self.mouse_event = None
self.view = None
# self.callback_move = None
self.callback_click = None
self.ui = None
self.point = App.Vector()
def GetResources(self):
"""Set icon, menu and tooltip."""
_msg = ("Creates copies of a selected object, "
"and places the copies in an orthogonal pattern.\n"
"The properties of the array can be further modified after "
"the new object is created, including turning it into "
"a different type of array.")
d = {'Pixmap': 'Draft_Array',
'MenuText': QT_TRANSLATE_NOOP("Draft", "Array"),
'ToolTip': QT_TRANSLATE_NOOP("Draft", _msg)}
return d
def Activated(self):
"""Execute this when the command is called.
We add callbacks that connect the 3D view with
the widgets of the task panel.
"""
# self.location = coin.SoLocation2Event.getClassTypeId()
self.mouse_event = coin.SoMouseButtonEvent.getClassTypeId()
self.view = Draft.get3DView()
# self.callback_move = \
# self.view.addEventCallbackPivy(self.location, self.move)
self.callback_click = \
self.view.addEventCallbackPivy(self.mouse_event, self.click)
self.ui = task_orthoarray.TaskPanelOrthoArray()
# The calling class (this one) is saved in the object
# of the interface, to be able to call a function from within it.
self.ui.source_command = self
# Gui.Control.showDialog(self.ui)
DraftGui.todo.delay(Gui.Control.showDialog, self.ui)
def click(self, event_cb=None):
"""Run callback for when the mouse pointer clicks on the 3D view.
It should act as if the Enter key was pressed, or the OK button
was pressed in the task panel.
"""
if event_cb:
event = event_cb.getEvent()
if (event.getState() != coin.SoMouseButtonEvent.DOWN
or event.getButton() != coin.SoMouseButtonEvent.BUTTON1):
return
if self.ui and self.point:
# The accept function of the interface
# should call the completed function
# of the calling class (this one).
self.ui.accept()
def completed(self):
"""Run when the command is terminated.
We should remove the callbacks that were added to the 3D view
and then close the task panel.
"""
# self.view.removeEventCallbackPivy(self.location,
# self.callback_move)
self.view.removeEventCallbackPivy(self.mouse_event,
self.callback_click)
if Gui.Control.activeDialog():
Gui.Snapper.off()
Gui.Control.closeDialog()
super().finish()
if App.GuiUp:
Gui.addCommand('Draft_OrthoArray', GuiCommandOrthoArray())

View File

@@ -0,0 +1,60 @@
"""Provide the object code for Draft Array."""
## @package orthoarray
# \ingroup DRAFT
# \brief Provide the object code for Draft Array.
# ***************************************************************************
# * (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 *
# * *
# ***************************************************************************
import FreeCAD as App
import Draft
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=False):
"""Create an orthogonal array from the given object."""
obj = Draft.makeArray(obj,
arg1=v_x, arg2=v_y, arg3=v_z,
arg4=n_x, arg5=n_y, arg6=n_z,
useLink=use_link)
return obj
def make_ortho_array2(obj,
v_x=App.Vector(10, 0, 0),
v_y=App.Vector(0, 10, 0),
n_x=2,
n_y=2,
use_link=False):
"""Create a 2D orthogonal array from the given object."""
obj = Draft.makeArray(obj,
arg1=v_x, arg2=v_y,
arg3=n_x, arg4=n_y,
useLink=use_link)
return obj

View File

@@ -0,0 +1,347 @@
"""Provide the task panel for the Draft OrthoArray tool."""
## @package task_orthoarray
# \ingroup DRAFT
# \brief Provide the task panel for the Draft OrthoArray tool.
# ***************************************************************************
# * (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 *
# * *
# ***************************************************************************
import FreeCAD as App
import FreeCADGui as Gui
# import Draft
import Draft_rc
import DraftVecUtils
import PySide.QtGui as QtGui
from PySide.QtCore import QT_TRANSLATE_NOOP
# import DraftTools
from draftutils.translate import translate
# from DraftGui import displayExternal
_Quantity = App.Units.Quantity
def _Msg(text, end="\n"):
"""Print message with newline."""
App.Console.PrintMessage(text + end)
def _Wrn(text, end="\n"):
"""Print warning with newline."""
App.Console.PrintWarning(text + end)
def _tr(text):
"""Translate with the context set."""
return translate("Draft", text)
# So the resource file doesn't trigger errors from code checkers (flake8)
True if Draft_rc else False
class TaskPanelOrthoArray:
"""TaskPanel for the OrthoArray command.
The names of the widgets are defined in the `.ui` file.
In this class all those widgets are automatically created
under the name `self.form.<name>`
The `.ui` file may use special FreeCAD widgets such as
`Gui::InputField` (based on `QLineEdit`) and
`Gui::QuantitySpinBox` (based on `QAbstractSpinBox`).
See the Doxygen documentation of the corresponding files in `src/Gui/`,
for example, `InputField.h` and `QuantitySpinBox.h`.
"""
def __init__(self):
ui_file = ":/ui/TaskPanel_OrthoArray.ui"
self.form = Gui.PySideUic.loadUi(ui_file)
self.name = self.form.windowTitle()
icon_name = "Draft_Array"
svg = ":/icons/" + icon_name
pix = QtGui.QPixmap(svg)
icon = QtGui.QIcon.fromTheme(icon_name, QtGui.QIcon(svg))
self.form.setWindowIcon(icon)
self.form.label_icon.setPixmap(pix.scaled(32, 32))
start_x = _Quantity(100.0, App.Units.Length)
start_y = start_x
start_z = start_x
start_zero = _Quantity(0.0, App.Units.Length)
length_unit = start_x.getUserPreferred()[2]
self.form.input_X_x.setProperty('rawValue', start_x.Value)
self.form.input_X_x.setProperty('unit', length_unit)
self.form.input_X_y.setProperty('rawValue', start_zero.Value)
self.form.input_X_y.setProperty('unit', length_unit)
self.form.input_X_z.setProperty('rawValue', start_zero.Value)
self.form.input_X_z.setProperty('unit', length_unit)
self.form.input_Y_x.setProperty('rawValue', start_zero.Value)
self.form.input_Y_x.setProperty('unit', length_unit)
self.form.input_Y_y.setProperty('rawValue', start_y.Value)
self.form.input_Y_y.setProperty('unit', length_unit)
self.form.input_Y_z.setProperty('rawValue', start_zero.Value)
self.form.input_Y_z.setProperty('unit', length_unit)
self.form.input_Z_x.setProperty('rawValue', start_zero.Value)
self.form.input_Z_x.setProperty('unit', length_unit)
self.form.input_Z_y.setProperty('rawValue', start_zero.Value)
self.form.input_Z_y.setProperty('unit', length_unit)
self.form.input_Z_z.setProperty('rawValue', start_z.Value)
self.form.input_Z_z.setProperty('unit', length_unit)
self.v_X = App.Vector(100, 0, 0)
self.v_Y = App.Vector(0, 100, 0)
self.v_Z = App.Vector(0, 0, 100)
# Old style for Qt4, avoid!
# QtCore.QObject.connect(self.form.button_reset,
# QtCore.SIGNAL("clicked()"),
# self.reset_point)
# New style for Qt5
self.form.button_reset_X.clicked.connect(lambda: self.reset_v("X"))
self.form.button_reset_Y.clicked.connect(lambda: self.reset_v("Y"))
self.form.button_reset_Z.clicked.connect(lambda: self.reset_v("Z"))
self.n_X = 2
self.n_Y = 2
self.n_Z = 1
self.form.spinbox_n_X.setValue(self.n_X)
self.form.spinbox_n_Y.setValue(self.n_Y)
self.form.spinbox_n_Z.setValue(self.n_Z)
self.valid_input = False
# When the checkbox changes, change the fuse value
self.fuse = False
self.form.checkbox_fuse.stateChanged.connect(self.set_fuse)
self.use_link = False
self.form.checkbox_link.stateChanged.connect(self.set_link)
def accept(self):
"""Execute when clicking the OK button."""
selection = Gui.Selection.getSelection()
n_X = self.form.spinbox_n_X.value()
n_Y = self.form.spinbox_n_Y.value()
n_Z = self.form.spinbox_n_Z.value()
self.valid_input = self.validate_input(selection,
n_X,
n_Y,
n_Z)
if self.valid_input:
self.create_object(selection)
self.print_messages(selection)
self.finish()
def validate_input(self, selection, n_X, n_Y, n_Z):
"""Check that the input is valid."""
if not selection:
_Wrn(_tr("At least one element must be selected"))
return False
if n_X < 1 or n_Y < 1 or n_Z < 1:
_Wrn(_tr("Number of elements must be at least 1"))
return False
# Todo: each of the elements of the selection could be tested,
# not only the first one.
obj = selection[0]
if obj.isDerivedFrom("App::FeaturePython"):
_Wrn(_tr("Selection is not suitable for array"))
_Wrn(_tr("Object:") + " {0} ({1})".format(obj.Label, obj.TypeId))
return False
return True
def create_object(self, selection):
"""Create the actual object."""
self.v_X, self.v_Y, self.v_Z = self.set_intervals()
self.n_X, self.n_Y, self.n_Z = self.set_numbers()
if len(selection) == 1:
sel_obj = selection[0]
else:
# This can be changed so a compound of multiple
# selected objects is produced
sel_obj = selection[0]
self.fuse = self.form.checkbox_fuse.isChecked()
self.use_link = self.form.checkbox_link.isChecked()
# This creates the object immediately
# obj = Draft.makeArray(sel_obj,
# self.v_X, self.v_Y, self.v_Z,
# self.n_X, self.n_Y, self.n_Z)
# if obj:
# obj.Fuse = self.fuse
# Instead, we build the commands to execute through the parent
# of this class, the GuiCommand.
# This is needed to schedule geometry manipulation
# that would crash Coin3D if done in the event callback.
_cmd = "obj = Draft.makeArray("
_cmd += "FreeCAD.ActiveDocument." + sel_obj.Name + ", "
_cmd += "arg1=" + DraftVecUtils.toString(self.v_X) + ", "
_cmd += "arg2=" + DraftVecUtils.toString(self.v_Y) + ", "
_cmd += "arg3=" + DraftVecUtils.toString(self.v_Z) + ", "
_cmd += "arg4=" + str(self.n_X) + ", "
_cmd += "arg5=" + str(self.n_Y) + ", "
_cmd += "arg6=" + str(self.n_Z) + ", "
_cmd += "useLink=" + str(self.use_link)
_cmd += ")"
_cmd_list = ["FreeCADGui.addModule('Draft')",
_cmd,
"obj.Fuse = " + str(self.fuse),
"Draft.autogroup(obj)",
"FreeCAD.ActiveDocument.recompute()"]
self.source_command.commit("Ortho array", _cmd_list)
def set_numbers(self):
"""Assign the number of elements."""
self.n_X = self.form.spinbox_n_X.value()
self.n_Y = self.form.spinbox_n_Y.value()
self.n_Z = self.form.spinbox_n_Z.value()
return self.n_X, self.n_Y, self.n_Z
def set_intervals(self):
"""Assign the interval vectors."""
v_X_x_str = self.form.input_X_x.text()
v_X_y_str = self.form.input_X_y.text()
v_X_z_str = self.form.input_X_z.text()
self.v_X = App.Vector(_Quantity(v_X_x_str).Value,
_Quantity(v_X_y_str).Value,
_Quantity(v_X_z_str).Value)
v_Y_x_str = self.form.input_Y_x.text()
v_Y_y_str = self.form.input_Y_y.text()
v_Y_z_str = self.form.input_Y_z.text()
self.v_Y = App.Vector(_Quantity(v_Y_x_str).Value,
_Quantity(v_Y_y_str).Value,
_Quantity(v_Y_z_str).Value)
v_Z_x_str = self.form.input_X_x.text()
v_Z_y_str = self.form.input_X_y.text()
v_Z_z_str = self.form.input_X_z.text()
self.v_Z = App.Vector(_Quantity(v_Z_x_str).Value,
_Quantity(v_Z_y_str).Value,
_Quantity(v_Z_z_str).Value)
return self.v_X, self.v_Y, self.v_Z
def reset_v(self, interval):
"""Reset the interval to zero distance."""
if interval == "X":
self.form.input_X_x.setProperty('rawValue', 100)
self.form.input_X_y.setProperty('rawValue', 0)
self.form.input_X_z.setProperty('rawValue', 0)
_Msg(_tr("Interval X reset:")
+ " ({0}, {1}, {2})".format(self.v_X.x,
self.v_X.y,
self.v_X.z))
elif interval == "Y":
self.form.input_Y_x.setProperty('rawValue', 0)
self.form.input_Y_y.setProperty('rawValue', 100)
self.form.input_Y_z.setProperty('rawValue', 0)
_Msg(_tr("Interval Y reset:")
+ " ({0}, {1}, {2})".format(self.v_Y.x,
self.v_Y.y,
self.v_Y.z))
elif interval == "Z":
self.form.input_Z_x.setProperty('rawValue', 0)
self.form.input_Z_y.setProperty('rawValue', 0)
self.form.input_Z_z.setProperty('rawValue', 100)
_Msg(_tr("Interval Z reset:")
+ " ({0}, {1}, {2})".format(self.v_Z.x,
self.v_Z.y,
self.v_Z.z))
self.n_X, self.n_Y, self.n_Z = self.set_intervals()
def print_fuse_state(self):
"""Print the state translated."""
if self.fuse:
translated_state = QT_TRANSLATE_NOOP("Draft", "True")
else:
translated_state = QT_TRANSLATE_NOOP("Draft", "False")
_Msg(_tr("Fuse:") + " {}".format(translated_state))
def set_fuse(self):
"""Run callback when the fuse checkbox changes."""
self.fuse = self.form.checkbox_fuse.isChecked()
self.print_fuse_state()
def print_link_state(self):
"""Print the state translated."""
if self.use_link:
translated_state = QT_TRANSLATE_NOOP("Draft", "True")
else:
translated_state = QT_TRANSLATE_NOOP("Draft", "False")
_Msg(_tr("Use Link object:") + " {}".format(translated_state))
def set_link(self):
"""Run callback when the link checkbox changes."""
self.use_link = self.form.checkbox_link.isChecked()
self.print_link_state()
def print_messages(self, selection):
"""Print messages about the operation."""
if len(selection) == 1:
sel_obj = selection[0]
else:
# This can be changed so a compound of multiple
# selected objects is produced
sel_obj = selection[0]
_Msg("{}".format(16*"-"))
_Msg("{}".format(self.name))
_Msg(_tr("Object:") + " {}".format(sel_obj.Label))
_Msg(_tr("Number of X elements:") + " {}".format(self.n_X))
_Msg(_tr("Interval X:")
+ " ({0}, {1}, {2})".format(self.v_X.x,
self.v_X.y,
self.v_X.z))
_Msg(_tr("Number of Y elements:") + " {}".format(self.n_Y))
_Msg(_tr("Interval Y:")
+ " ({0}, {1}, {2})".format(self.v_Y.x,
self.v_Y.y,
self.v_Y.z))
_Msg(_tr("Number of Z elements:") + " {}".format(self.n_Z))
_Msg(_tr("Interval Z:")
+ " ({0}, {1}, {2})".format(self.v_Z.x,
self.v_Z.y,
self.v_Z.z))
self.print_fuse_state()
self.print_link_state()
def reject(self):
"""Run when clicking the Cancel button."""
_Msg(_tr("Aborted:") + " {}".format(self.name))
self.finish()
def finish(self):
"""Run at the end after OK or Cancel."""
# App.ActiveDocument.commitTransaction()
Gui.ActiveDocument.resetEdit()
# Runs the parent command to complete the call
self.source_command.completed()

View File

@@ -0,0 +1,43 @@
"""Provide the view provider code for Draft Array."""
## @package view_orthoarray
# \ingroup DRAFT
# \brief Provide the view provider code for Draft Array.
# ***************************************************************************
# * (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 *
# * *
# ***************************************************************************
import Draft
import Draft_rc
ViewProviderDraftArray = Draft._ViewProviderDraftArray
# So the resource file doesn't trigger errors from code checkers (flake8)
True if Draft_rc else False
class ViewProviderOrthoArray(ViewProviderDraftArray):
def __init__(self, vobj):
super().__init__(self, vobj)
def getIcon(self):
return ":/icons/Draft_Array"