Draft: Introduced Hatch command + object

This commit is contained in:
Yorik van Havre
2021-09-06 15:27:52 +02:00
parent 74a3ca8f9f
commit 2bf67f0191
11 changed files with 664 additions and 1 deletions

View File

@@ -137,6 +137,7 @@ SET(Draft_make_functions
draftmake/make_text.py
draftmake/make_wire.py
draftmake/make_wpproxy.py
draftmake/make_hatch.py
draftmake/README.md
)
@@ -169,6 +170,7 @@ SET(Draft_objects
draftobjects/text.py
draftobjects/wire.py
draftobjects/wpproxy.py
draftobjects/hatch.py
draftobjects/README.md
)
@@ -194,6 +196,7 @@ SET(Draft_view_providers
draftviewproviders/view_text.py
draftviewproviders/view_wire.py
draftviewproviders/view_wpproxy.py
draftviewproviders/view_hatch.py
draftviewproviders/README.md
)
@@ -213,6 +216,7 @@ SET(Creator_tools
draftguitools/gui_points.py
draftguitools/gui_facebinders.py
draftguitools/gui_labels.py
draftguitools/gui_hatch.py
)
SET(Modifier_tools

View File

@@ -422,4 +422,9 @@ if App.GuiUp:
from draftviewproviders.view_text import (ViewProviderText,
ViewProviderDraftText)
from draftobjects.hatch import (Draft_Hatch_Object)
from draftmake.make_hatch import (make_hatch, makeHatch)
if App.GuiUp:
from draftviewproviders.view_hatch import (Draft_Hatch_ViewProvider)
## @}

View File

@@ -168,6 +168,7 @@ from draftguitools.gui_shapestrings import ShapeString
from draftguitools.gui_points import Point
from draftguitools.gui_facebinders import Draft_Facebinder
from draftguitools.gui_labels import Draft_Label
from draftguitools.gui_hatch import Draft_Hatch
# ---------------------------------------------------------------------------
# Modifier functions

View File

@@ -107,6 +107,7 @@
<file>icons/Snap_Special.svg</file>
<file>icons/Snap_WorkingPlane.svg</file>
<file>icons/Draft_NewLayer.svg</file>
<file>icons/Draft_Hatch.svg</file>
<file>patterns/aluminium.svg</file>
<file>patterns/brick01.svg</file>
<file>patterns/concrete.svg</file>
@@ -184,5 +185,6 @@
<file>ui/TaskShapeString.ui</file>
<file>ui/dialog_AnnotationStyleEditor.ui</file>
<file>ui/TaskPanel_SetStyle.ui</file>
<file>ui/dialogHatch.ui</file>
</qresource>
</RCC>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>227</width>
<height>142</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QComboBox" name="Pattern"/>
</item>
<item row="0" column="1">
<widget class="Gui::FileChooser" name="File">
<property name="filter">
<string>pattern files (*.pat)</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>PAT file:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Scale</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Pattern:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="Scale">
<property name="suffix">
<string/>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
</property>
<property name="value">
<double>1000.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Rotation:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="Rotation">
<property name="suffix">
<string>°</string>
</property>
<property name="maximum">
<double>359.990000000000009</double>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::FileChooser</class>
<extends>QWidget</extends>
<header>Gui/FileDialog.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,132 @@
#***************************************************************************
#* *
#* Copyright (c) 2021 Yorik van Havre <yorik@uncreated.net> *
#* *
#* 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. *
#* *
#* This program 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 this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
"""This module contains FreeCAD commands for the Draft workbench"""
import os
import FreeCAD
from draftutils.translate import translate, QT_TRANSLATE_NOOP
class Draft_Hatch:
def GetResources(self):
return {'Pixmap' : "Draft_Hatch",
'MenuText': QT_TRANSLATE_NOOP("Draft_Hatch", "Hatch"),
'Accel': "H, A",
'ToolTip' : QT_TRANSLATE_NOOP("Draft_Hatch", "Create hatches on selected faces")}
def Activated(self):
import FreeCADGui
if FreeCADGui.Selection.getSelection():
FreeCADGui.Control.showDialog(Draft_Hatch_TaskPanel(FreeCADGui.Selection.getSelection()[0]))
else:
FreeCAD.Console.PrintError(translate("Draft","You must choose a base object before using this command")+"\n")
class Draft_Hatch_TaskPanel:
def __init__(self,baseobj):
import FreeCADGui
from PySide import QtCore,QtGui
import Draft_rc
self.baseobj = baseobj
self.form = FreeCADGui.PySideUic.loadUi(":/ui/dialogHatch.ui")
self.form.setWindowIcon(QtGui.QIcon(":/icons/Draft_Hatch.svg"))
self.form.File.fileNameChanged.connect(self.onFileChanged)
self.p1 = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/TechDraw/PAT")
self.p2 = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
self.form.File.setFileName(self.p1.GetString("FilePattern",""))
pat = self.p1.GetString("NamePattern","")
if pat in [self.form.Pattern.itemText(i) for i in range(self.form.Pattern.count())]:
self.form.Pattern.setCurrentText(pat)
self.form.Scale.setValue(self.p2.GetFloat("HatchPatternScale",1000.0))
self.form.Rotation.setValue(self.p2.GetFloat("HatchPatternRotation",0.0))
def accept(self):
import FreeCADGui
self.p1.SetString("FilePattern",self.form.File.property("fileName"))
self.p1.SetString("NamePattern",self.form.Pattern.currentText())
self.p2.SetFloat("HatchPatternScale",self.form.Scale.value())
self.p2.SetFloat("HatchPatternRotation",self.form.Rotation.value())
if hasattr(self.baseobj,"File") and hasattr(self.baseobj,"Pattern"):
# modify existing hatch object
o = "FreeCAD.ActiveDocument.getObject(\""+self.baseobj.Name+"\")"
FreeCADGui.doCommand(o+".File=\""+self.form.File.property("fileName")+"\"")
FreeCADGui.doCommand(o+".Pattern=\""+self.form.Pattern.currentText()+"\"")
FreeCADGui.doCommand(o+".Scale="+str(self.form.Scale.value()))
FreeCADGui.doCommand(o+".Rotation="+str(self.form.Rotation.value()))
else:
# create new hatch object
FreeCAD.ActiveDocument.openTransaction("Create Hatch")
FreeCADGui.addModule("Draft")
cmd = "Draft.makeHatch("
cmd += "baseobject=FreeCAD.ActiveDocument.getObject(\""+self.baseobj.Name
cmd += "\"),filename=\""+self.form.File.property("fileName")
cmd += "\",pattern=\""+self.form.Pattern.currentText()
cmd += "\",scale="+str(self.form.Scale.value())
cmd += ",rotation="+str(self.form.Rotation.value())+")"
FreeCADGui.doCommand(cmd)
FreeCAD.ActiveDocument.commitTransaction()
FreeCADGui.doCommand("FreeCAD.ActiveDocument.recompute()")
self.reject()
def reject(self):
import FreeCADGui
FreeCADGui.Control.closeDialog()
FreeCAD.ActiveDocument.recompute()
def onFileChanged(self,filename):
pat = self.form.Pattern.currentText()
self.form.Pattern.clear()
patterns = self.getPatterns(filename)
self.form.Pattern.addItems(patterns)
if pat in patterns:
self.form.Pattern.setCurrentText(pat)
def getPatterns(self,filename):
"""returns a list of pattern names found in a PAT file"""
patterns = []
if os.path.exists(filename):
with open(filename) as patfile:
for line in patfile:
if line.startswith("*"):
patterns.append(line.split(",")[0][1:])
return patterns
if FreeCAD.GuiUp:
import FreeCADGui
FreeCADGui.addCommand("Draft_Hatch",Draft_Hatch())

View File

@@ -0,0 +1,48 @@
#***************************************************************************
#* *
#* Copyright (c) 2021 Yorik van Havre <yorik@uncreated.net> *
#* *
#* 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. *
#* *
#* This program 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 this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
"""This module contains FreeCAD commands for the Draft workbench"""
import FreeCAD
from draftobjects.hatch import Draft_Hatch_Object
from draftviewproviders.view_hatch import Draft_Hatch_ViewProvider
def makeHatch(baseobject,filename,pattern,scale,rotation):
"""makeHatch(baseobject,filename,pattern,scale,rotation): Creates and returns a hatch
object made by applying the given pattern of the given PAT file to the faces of the
given base object. Given scale and rotation factors are applied to the hatch object.
The result is a Part-based object created inthe active document."""
if not FreeCAD.ActiveDocument:
return
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Hatch")
Draft_Hatch_Object(obj)
obj.Base = baseobject
obj.File = filename
obj.Pattern = pattern
obj.Scale = scale
obj.Rotation = rotation
if FreeCAD.GuiUp:
Draft_Hatch_ViewProvider(obj.ViewObject)
make_hatch = makeHatch

View File

@@ -0,0 +1,133 @@
#***************************************************************************
#* *
#* Copyright (c) 2021 Yorik van Havre <yorik@uncreated.net> *
#* *
#* 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. *
#* *
#* This program 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 this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
"""This module contains FreeCAD commands for the Draft workbench"""
import os
import FreeCAD
from draftutils.translate import translate, QT_TRANSLATE_NOOP
class Draft_Hatch_Object:
def __init__(self,obj):
obj.Proxy = self
self.setProperties(obj)
def setProperties(self,obj):
pl = obj.PropertiesList
if not "Placement" in pl:
obj.addProperty("App::PropertyPlacement","Placement","Hatch",
QT_TRANSLATE_NOOP("App::Property","The placement of this object"))
if not "Shape" in pl:
obj.addProperty("Part::PropertyPartShape","Shape","Hatch",
QT_TRANSLATE_NOOP("App::Property","The shape of this object"))
if not "Base" in pl:
obj.addProperty("App::PropertyLink","Base","Hatch",
QT_TRANSLATE_NOOP("App::Property","The base object used by this object"))
if not "File" in pl:
obj.addProperty("App::PropertyFile","File","Hatch",
QT_TRANSLATE_NOOP("App::Property","The PAT file used by this object"))
if not "Pattern" in pl:
obj.addProperty("App::PropertyString","Pattern","Hatch",
QT_TRANSLATE_NOOP("App::Property","The pattern name used by this object"))
if not "Scale" in pl:
obj.addProperty("App::PropertyFloat","Scale","Hatch",
QT_TRANSLATE_NOOP("App::Property","The pattern scale used by this object"))
if not "Rotation" in pl:
obj.addProperty("App::PropertyAngle","Rotation","Hatch",
QT_TRANSLATE_NOOP("App::Property","The pattern rotation used by this object"))
if not "Translate" in pl:
obj.addProperty("App::PropertyBool","Translate","Hatch",
QT_TRANSLATE_NOOP("App::Property","If set to False, hatch is applied as is to the faces, without translation (this might give wrong results for non-XY faces)"))
obj.Translate = True
self.Type = "Hatch"
def onDocumentRestored(self,obj):
self.setProperties(obj)
def __getstate__(self):
return None
def __setstate__(self,state):
return None
def execute(self,obj):
import Part
import TechDraw
if not obj.Base:
return
if not obj.File:
return
if not obj.Pattern:
return
if not obj.Scale:
return
if not obj.Pattern in self.getPatterns(obj.File):
return
if not obj.Base.isDerivedFrom("Part::Feature"):
return
if not obj.Base.Shape.Faces:
return
pla = obj.Placement
shapes = []
for face in obj.Base.Shape.Faces:
face = face.copy()
if obj.Translate:
bpoint = face.CenterOfMass
norm = face.normalAt(0,0)
fpla = FreeCAD.Placement(bpoint,FreeCAD.Rotation(FreeCAD.Vector(0,0,1),norm))
face.Placement = face.Placement.multiply(fpla.inverse())
if obj.Rotation:
face.rotate(FreeCAD.Vector(),FreeCAD.Vector(0,0,1),obj.Rotation)
shape = TechDraw.makeGeomHatch(face,obj.Scale,obj.Pattern,obj.File)
if obj.Rotation:
shape.rotate(FreeCAD.Vector(),FreeCAD.Vector(0,0,1),-obj.Rotation)
if obj.Translate:
shape.Placement = shape.Placement.multiply(fpla)
shapes.append(shape)
if shapes:
obj.Shape = Part.makeCompound(shapes)
obj.Placement = pla
def getPatterns(self,filename):
"""returns a list of pattern names found in a PAT file"""
patterns = []
if os.path.exists(filename):
with open(filename) as patfile:
for line in patfile:
if line.startswith("*"):
patterns.append(line.split(",")[0][1:])
return patterns

View File

@@ -45,7 +45,7 @@ def get_draft_drawing_commands():
"Draft_Circle", "Draft_Ellipse", "Draft_Rectangle",
"Draft_Polygon", "Draft_BSpline", "Draft_BezierTools",
"Draft_Point", "Draft_Facebinder",
"Draft_ShapeString"]
"Draft_ShapeString","Draft_Hatch"]
def get_draft_annotation_commands():

View File

@@ -0,0 +1,70 @@
#***************************************************************************
#* *
#* Copyright (c) 2021 Yorik van Havre <yorik@uncreated.net> *
#* *
#* 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. *
#* *
#* This program 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 this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
"""This module contains FreeCAD commands for the Draft workbench"""
import os
import FreeCAD
from draftguitools.gui_hatch import Draft_Hatch_TaskPanel
class Draft_Hatch_ViewProvider:
def __init__(self,vobj):
vobj.Proxy = self
def getIcon(self):
return ":/icons/Draft_Hatch.svg"
def __getstate__(self):
return None
def __setstate__(self,state):
return None
def setEdit(self,vobj,mode):
import FreeCADGui
taskd = Draft_Hatch_TaskPanel(vobj.Object)
taskd.form.File.setFileName(vobj.Object.File)
taskd.form.Pattern.setCurrentText(vobj.Object.Pattern)
taskd.form.Scale.setValue(vobj.Object.Scale)
taskd.form.Rotation.setValue(vobj.Object.Rotation)
FreeCADGui.Control.showDialog(taskd)
return True
def unsetEdit(self,vobj,mode):
import FreeCADGui
FreeCADGui.Control.closeDialog()
return True
def doubleClicked(self,vobj):
self.setEdit(vobj,None)