Rebar Addon for FreeCAD
Stirrup.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 # ***************************************************************************
3 # * *
4 # * Copyright (c) 2017 - Amritpal Singh <amrit3701@gmail.com> *
5 # * *
6 # * This program is free software; you can redistribute it and/or modify *
7 # * it under the terms of the GNU Lesser General Public License (LGPL) *
8 # * as published by the Free Software Foundation; either version 2 of *
9 # * the License, or (at your option) any later version. *
10 # * for detail see the LICENCE text file. *
11 # * *
12 # * This program is distributed in the hope that it will be useful, *
13 # * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 # * GNU Library General Public License for more details. *
16 # * *
17 # * You should have received a copy of the GNU Library General Public *
18 # * License along with this program; if not, write to the Free Software *
19 # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
20 # * USA *
21 # * *
22 # ***************************************************************************
23 
24 __title__ = "StirrupRebar"
25 __author__ = "Amritpal Singh"
26 __url__ = "https://www.freecadweb.org"
27 
28 from PySide import QtCore, QtGui
29 from Rebarfunc import *
30 from PySide.QtCore import QT_TRANSLATE_NOOP
31 from RebarDistribution import runRebarDistribution, removeRebarDistribution
32 from PopUpImage import showPopUpImageDialog
33 import FreeCAD
34 import FreeCADGui
35 import ArchCommands
36 import os
37 import sys
38 import math
39 
40 def getpointsOfStirrup(FacePRM, l_cover, r_cover, t_cover, b_cover, bentAngle, bentFactor, diameter, rounding, facenormal):
41  """ getpointsOfStirrup(FacePRM, LeftCover, RightCover, TopCover, BottomCover, BentAngle, BentFactor, Diameter, Rounding, FaceNormal):
42  Return the coordinates points of the Stirrup in the form of array."""
43  angle = 180 - bentAngle
44  tangent_part_length = extendedTangentPartLength(rounding, diameter, angle)
45  tangent_length = extendedTangentLength(rounding, diameter, angle)
46  if round(facenormal[0]) in {1,-1}:
47  x1 = FacePRM[1][0]
48  y1 = FacePRM[1][1] - FacePRM[0][0] / 2 + l_cover
49  z1 = FacePRM[1][2] + FacePRM[0][1] / 2 - t_cover + tangent_part_length
50  y2 = FacePRM[1][1] - FacePRM[0][0] / 2 + l_cover
51  z2 = FacePRM[1][2] - FacePRM[0][1] / 2 + b_cover
52  y3 = FacePRM[1][1] + FacePRM[0][0] / 2 - r_cover
53  z3 = FacePRM[1][2] - FacePRM[0][1] / 2 + b_cover
54  y4 = FacePRM[1][1] + FacePRM[0][0] / 2 - r_cover
55  z4 = FacePRM[1][2] + FacePRM[0][1] / 2 - t_cover
56  y5 = FacePRM[1][1] - FacePRM[0][0] / 2 + l_cover - tangent_part_length
57  z5 = FacePRM[1][2] + FacePRM[0][1] / 2 - t_cover
58  side_length = abs(y5 - y4) - tangent_part_length
59  normal_dis = (diameter * (side_length + tangent_part_length)) / side_length
60  x2 = x1 - normal_dis / 4
61  x3 = x2 - normal_dis / 4
62  x4 = x3 - normal_dis / 4
63  x5 = x4 - normal_dis / 4
64  x0 = x1 + normal_dis / 4
65  y0 = y1 + (tangent_length + bentFactor * diameter) * math.sin(math.radians(angle))
66  z0 = z1 - (tangent_length + bentFactor * diameter) * math.cos(math.radians(angle))
67  x6 = x5 - normal_dis / 4
68  y6 = y5 + (tangent_length + bentFactor * diameter) * math.sin(math.radians(90 - angle))
69  z6 = z5 - (tangent_length + bentFactor * diameter) * math.cos(math.radians(90 - angle))
70  elif round(facenormal[1]) in {1,-1}:
71  x1 = FacePRM[1][0] - FacePRM[0][0] / 2 + l_cover
72  y1 = FacePRM[1][1]
73  z1 = FacePRM[1][2] + FacePRM[0][1] / 2 - t_cover + tangent_part_length
74  x2 = FacePRM[1][0] - FacePRM[0][0] / 2 + l_cover
75  z2 = FacePRM[1][2] - FacePRM[0][1] / 2 + b_cover
76  x3 = FacePRM[1][0] + FacePRM[0][0] / 2 - r_cover
77  z3 = FacePRM[1][2] - FacePRM[0][1] / 2 + b_cover
78  x4 = FacePRM[1][0] + FacePRM[0][0] / 2 - r_cover
79  z4 = FacePRM[1][2] + FacePRM[0][1] / 2 - t_cover
80  x5 = FacePRM[1][0] - FacePRM[0][0] / 2 + l_cover - tangent_part_length
81  z5 = FacePRM[1][2] + FacePRM[0][1] / 2 - t_cover
82  side_length = abs(x5 - x4) - tangent_part_length
83  normal_dis = (diameter * (side_length + tangent_part_length)) / side_length
84  y2 = y1 - normal_dis / 4
85  y3 = y2 - normal_dis / 4
86  y4 = y3 - normal_dis / 4
87  y5 = y4 - normal_dis / 4
88  y0 = y1 + normal_dis / 4
89  x0 = x1 + (tangent_length + bentFactor * diameter) * math.sin(math.radians(angle))
90  z0 = z1 - (tangent_length + bentFactor * diameter) * math.cos(math.radians(angle))
91  x6 = x5 + (tangent_length + bentFactor * diameter) * math.sin(math.radians(90 - angle))
92  y6 = y5 - normal_dis / 4
93  z6 = z5 - (tangent_length + bentFactor * diameter) * math.cos(math.radians(90 - angle))
94  elif round(facenormal[2]) in {1,-1}:
95  x1 = FacePRM[1][0] - FacePRM[0][0] / 2 + l_cover
96  y1 = FacePRM[1][1] + FacePRM[0][1] / 2 - t_cover + tangent_part_length
97  z1 = FacePRM[1][2]
98  x2 = FacePRM[1][0] - FacePRM[0][0] / 2 + l_cover
99  y2 = FacePRM[1][1] - FacePRM[0][1] / 2 + b_cover
100  x3 = FacePRM[1][0] + FacePRM[0][0] / 2 - r_cover
101  y3 = FacePRM[1][1] - FacePRM[0][1] / 2 + b_cover
102  x4 = FacePRM[1][0] + FacePRM[0][0] / 2 - r_cover
103  y4 = FacePRM[1][1] + FacePRM[0][1] / 2 - t_cover
104  x5 = FacePRM[1][0] - FacePRM[0][0] / 2 + l_cover - tangent_part_length
105  y5 = FacePRM[1][1] + FacePRM[0][1] / 2 - t_cover
106  side_length = abs(x5 - x4) - tangent_part_length
107  normal_dis = (diameter * (side_length + tangent_part_length)) / side_length
108  z2 = z1 - normal_dis / 4
109  z3 = z2 - normal_dis / 4
110  z4 = z3 - normal_dis / 4
111  z5 = z4 - normal_dis / 4
112  z0 = z1 + normal_dis / 4
113  x0 = x1 + (tangent_length + bentFactor * diameter) * math.sin(math.radians(angle))
114  y0 = y1 - (tangent_length + bentFactor * diameter) * math.cos(math.radians(angle))
115  x6 = x5 + (tangent_length + bentFactor * diameter) * math.sin(math.radians(90 - angle))
116  y6 = y5 - (tangent_length + bentFactor * diameter) * math.cos(math.radians(90 - angle))
117  z6 = z5 - normal_dis / 4
118  return [FreeCAD.Vector(x0, y0, z0), FreeCAD.Vector(x1, y1, z1),\
119  FreeCAD.Vector(x2, y2, z2), FreeCAD.Vector(x3, y3, z3),\
120  FreeCAD.Vector(x4, y4, z4), FreeCAD.Vector(x5, y5, z5),\
121  FreeCAD.Vector(x6, y6, z6)]
122 
124  def __init__(self, Rebar = None):
125  self.CustomSpacing = None
126  if not Rebar:
127  selected_obj = FreeCADGui.Selection.getSelectionEx()[0]
128  self.SelectedObj = selected_obj.Object
129  self.FaceName = selected_obj.SubElementNames[0]
130  else:
131  self.FaceName = Rebar.Base.Support[0][1][0]
132  self.SelectedObj = Rebar.Base.Support[0][0]
133  self.form = FreeCADGui.PySideUic.loadUi(os.path.splitext(__file__)[0] + ".ui")
134  self.form.setWindowTitle(QtGui.QApplication.translate("RebarAddon", "Stirrup Rebar", None))
135  self.form.bentAngle.addItems(["135", "90"])
136  self.form.amount_radio.clicked.connect(self.amount_radio_clicked)
137  self.form.spacing_radio.clicked.connect(self.spacing_radio_clicked)
138  self.form.image.setPixmap(QtGui.QPixmap(os.path.split(os.path.abspath(__file__))[0]+"/icons/Stirrup.svg"))
139  self.form.customSpacing.clicked.connect(lambda: runRebarDistribution(self))
140  self.form.removeCustomSpacing.clicked.connect(lambda: removeRebarDistribution(self))
141  self.form.PickSelectedFace.clicked.connect(lambda: getSelectedFace(self))
142  self.form.toolButton.setIcon(self.form.toolButton.style().standardIcon(QtGui.QStyle.SP_DialogHelpButton))
143  self.form.toolButton.clicked.connect(lambda: showPopUpImageDialog(os.path.split(os.path.abspath(__file__))[0] + "/icons/StirrupDetailed.svg"))
144  self.Rebar = Rebar
145 
147  return int(QtGui.QDialogButtonBox.Ok) | int(QtGui.QDialogButtonBox.Apply) | int(QtGui.QDialogButtonBox.Cancel)
148 
149  def clicked(self, button):
150  if button == int(QtGui.QDialogButtonBox.Apply):
151  self.accept(button)
152 
153  def accept(self, signal = None):
154  l_cover = self.form.l_sideCover.text()
155  l_cover = FreeCAD.Units.Quantity(l_cover).Value
156  r_cover = self.form.r_sideCover.text()
157  r_cover = FreeCAD.Units.Quantity(r_cover).Value
158  t_cover = self.form.t_sideCover.text()
159  t_cover = FreeCAD.Units.Quantity(t_cover).Value
160  b_cover = self.form.b_sideCover.text()
161  b_cover = FreeCAD.Units.Quantity(b_cover).Value
162  f_cover = self.form.frontCover.text()
163  f_cover = FreeCAD.Units.Quantity(f_cover).Value
164  diameter = self.form.diameter.text()
165  diameter = FreeCAD.Units.Quantity(diameter).Value
166  bentAngle = int(self.form.bentAngle.currentText())
167  bentFactor = self.form.bentFactor.value()
168  rounding = self.form.rounding.value()
169  amount_check = self.form.amount_radio.isChecked()
170  spacing_check = self.form.spacing_radio.isChecked()
171  if not self.Rebar:
172  if amount_check:
173  amount = self.form.amount.value()
174  rebar = makeStirrup(l_cover, r_cover, t_cover, b_cover, f_cover, bentAngle, bentFactor, diameter,\
175  rounding, True, amount, self.SelectedObj, self.FaceName)
176  elif spacing_check:
177  spacing = self.form.spacing.text()
178  spacing = FreeCAD.Units.Quantity(spacing).Value
179  rebar = makeStirrup(l_cover, r_cover, t_cover, b_cover, f_cover, bentAngle, bentFactor, diameter,\
180  rounding, False, spacing, self.SelectedObj, self.FaceName)
181  else:
182  if amount_check:
183  amount = self.form.amount.value()
184  rebar = editStirrup(self.Rebar, l_cover, r_cover, t_cover, b_cover, f_cover, bentAngle, bentFactor,\
185  diameter, rounding, True, amount, self.SelectedObj, self.FaceName)
186  elif spacing_check:
187  spacing = self.form.spacing.text()
188  spacing = FreeCAD.Units.Quantity(spacing).Value
189  rebar = editStirrup(self.Rebar, l_cover, r_cover, t_cover, b_cover, f_cover, bentAngle, bentFactor,\
190  diameter, rounding, False, spacing, self.SelectedObj, self.FaceName)
191  if self.CustomSpacing:
192  rebar.CustomSpacing = self.CustomSpacing
193  FreeCAD.ActiveDocument.recompute()
194  self.Rebar = rebar
195  if signal == int(QtGui.QDialogButtonBox.Apply):
196  pass
197  else:
198  FreeCADGui.Control.closeDialog(self)
199 
201  self.form.spacing.setEnabled(False)
202  self.form.amount.setEnabled(True)
203 
205  self.form.amount.setEnabled(False)
206  self.form.spacing.setEnabled(True)
207 
208 
209 def makeStirrup(l_cover, r_cover, t_cover, b_cover, f_cover, bentAngle, bentFactor, diameter, rounding,\
210  amount_spacing_check, amount_spacing_value, structure = None, facename = None):
211  """ makeStirrup(LeftCover, RightCover, TopCover, BottomCover, FrontCover, BentAngle,
212  BentFactor, Diameter, Rounding, AmountSpacingCheck, AmountSpacingValue, Structure, Facename):
213  Adds the Stirrup reinforcement bar to the selected structural object."""
214  if not structure and not facename:
215  selected_obj = FreeCADGui.Selection.getSelectionEx()[0]
216  structure = selected_obj.Object
217  facename = selected_obj.SubElementNames[0]
218  face = structure.Shape.Faces[getFaceNumber(facename) - 1]
219  #StructurePRM = getTrueParametersOfStructure(structure)
220  FacePRM = getParametersOfFace(structure, facename, False)
221  FaceNormal = face.normalAt(0,0)
222  #FaceNormal = face.Placement.Rotation.inverted().multVec(FaceNormal)
223  if not FacePRM:
224  FreeCAD.Console.PrintError("Cannot identified shape or from which base object sturctural element is derived\n")
225  return
226  # Calculate the coordinate values of Stirrup
227  points = getpointsOfStirrup(FacePRM, l_cover, r_cover, t_cover, b_cover, bentAngle, bentFactor, diameter, rounding, FaceNormal)
228  import Draft
229  line = Draft.makeWire(points, closed = False, face = True, support = None)
230  import Arch
231  line.Support = [(structure, facename)]
232  if amount_spacing_check:
233  rebar = Arch.makeRebar(structure, line, diameter, amount_spacing_value, f_cover)
234  else:
235  size = (ArchCommands.projectToVector(structure.Shape.copy(), face.normalAt(0, 0))).Length
236  rebar = Arch.makeRebar(structure, line, diameter,\
237  int((size - diameter) / amount_spacing_value), f_cover)
238  rebar.Direction = FaceNormal.negative()
239  rebar.Rounding = rounding
240  # Adds properties to the rebar object
241  rebar.ViewObject.addProperty("App::PropertyString", "RebarShape", "RebarDialog",\
242  QT_TRANSLATE_NOOP("App::Property","Shape of rebar")).RebarShape = "Stirrup"
243  rebar.ViewObject.setEditorMode("RebarShape", 2)
244  rebar.addProperty("App::PropertyDistance", "LeftCover", "RebarDialog",\
245  QT_TRANSLATE_NOOP("App::Property", "Left Side cover of rebar")).LeftCover = l_cover
246  rebar.setEditorMode("LeftCover", 2)
247  rebar.addProperty("App::PropertyDistance", "RightCover", "RebarDialog",\
248  QT_TRANSLATE_NOOP("App::Property", "Right Side cover of rebar")).RightCover = r_cover
249  rebar.setEditorMode("RightCover", 2)
250  rebar.addProperty("App::PropertyDistance", "TopCover", "RebarDialog",\
251  QT_TRANSLATE_NOOP("App::Property", "Top Side cover of rebar")).TopCover = t_cover
252  rebar.setEditorMode("TopCover", 2)
253  rebar.addProperty("App::PropertyDistance", "BottomCover", "RebarDialog",\
254  QT_TRANSLATE_NOOP("App::Property", "Bottom Side cover of rebar")).BottomCover = b_cover
255  rebar.setEditorMode("BottomCover", 2)
256  rebar.addProperty("App::PropertyDistance", "FrontCover", "RebarDialog",\
257  QT_TRANSLATE_NOOP("App::Property", "Top cover of rebar")).FrontCover = f_cover
258  rebar.setEditorMode("FrontCover", 2)
259  rebar.addProperty("App::PropertyInteger", "BentAngle", "RebarDialog",\
260  QT_TRANSLATE_NOOP("App::Property", "Bent angle between at the end of rebar")).BentAngle = bentAngle
261  rebar.setEditorMode("BentAngle", 2)
262  rebar.addProperty("App::PropertyInteger", "BentFactor", "RebarDialog",\
263  QT_TRANSLATE_NOOP("App::Property", "Bent Length is the equal to BentFactor * Diameter")).BentFactor = bentFactor
264  rebar.setEditorMode("BentFactor", 2)
265  rebar.addProperty("App::PropertyBool", "AmountCheck", "RebarDialog",\
266  QT_TRANSLATE_NOOP("App::Property", "Amount radio button is checked")).AmountCheck
267  rebar.setEditorMode("AmountCheck", 2)
268  rebar.addProperty("App::PropertyDistance", "TrueSpacing", "RebarDialog",\
269  QT_TRANSLATE_NOOP("App::Property", "Spacing between of rebars")).TrueSpacing = amount_spacing_value
270  rebar.setEditorMode("TrueSpacing", 2)
271  if amount_spacing_check:
272  rebar.AmountCheck = True
273  else:
274  rebar.AmountCheck = False
275  rebar.TrueSpacing = amount_spacing_value
276  rebar.Label = "Stirrup"
277  FreeCAD.ActiveDocument.recompute()
278  return rebar
279 
280 def editStirrup(Rebar, l_cover, r_cover, t_cover, b_cover, f_cover, bentAngle, bentFactor, diameter, rounding,\
281  amount_spacing_check, amount_spacing_value, structure = None, facename = None):
282  sketch = Rebar.Base
283  if structure and facename:
284  sketch.Support = [(structure, facename)]
285  # Check if sketch support is empty.
286  if not sketch.Support:
287  showWarning("You have checked remove external geometry of base sketchs when needed.\nTo unchecked Edit->Preferences->Arch.")
288  return
289  # Assigned values
290  facename = sketch.Support[0][1][0]
291  structure = sketch.Support[0][0]
292  face = structure.Shape.Faces[getFaceNumber(facename) - 1]
293  #StructurePRM = getTrueParametersOfStructure(structure)
294  # Get parameters of the face where sketch of rebar is drawn
295  FacePRM = getParametersOfFace(structure, facename, False)
296  FaceNormal = face.normalAt(0, 0)
297  #FaceNormal = face.Placement.Rotation.inverted().multVec(FaceNormal)
298  # Calculate the coordinates value of Stirrup rebar
299  points = getpointsOfStirrup(FacePRM, l_cover, r_cover, t_cover, b_cover, bentAngle, bentFactor, diameter, rounding, FaceNormal)
300  Rebar.Base.Points = points
301  FreeCAD.ActiveDocument.recompute()
302  Rebar.Direction = FaceNormal.negative()
303  Rebar.OffsetStart = f_cover
304  Rebar.OffsetEnd = f_cover
305  Rebar.BentAngle = bentAngle
306  Rebar.BentFactor = bentFactor
307  Rebar.Rounding = rounding
308  Rebar.Diameter = diameter
309  if amount_spacing_check:
310  Rebar.Amount = amount_spacing_value
311  FreeCAD.ActiveDocument.recompute()
312  Rebar.AmountCheck = True
313  else:
314  size = (ArchCommands.projectToVector(structure.Shape.copy(), face.normalAt(0, 0))).Length
315  Rebar.Amount = int((size - diameter) / amount_spacing_value)
316  FreeCAD.ActiveDocument.recompute()
317  Rebar.AmountCheck = False
318  Rebar.FrontCover = f_cover
319  Rebar.LeftCover = l_cover
320  Rebar.RightCover = r_cover
321  Rebar.TopCover = t_cover
322  Rebar.BottomCover = b_cover
323  Rebar.TrueSpacing = amount_spacing_value
324  FreeCAD.ActiveDocument.recompute()
325  return Rebar
326 
327 def editDialog(vobj):
328  FreeCADGui.Control.closeDialog()
329  obj = _StirrupTaskPanel(vobj.Object)
330  obj.form.frontCover.setText(str(vobj.Object.FrontCover))
331  obj.form.l_sideCover.setText(str(vobj.Object.LeftCover))
332  obj.form.r_sideCover.setText(str(vobj.Object.RightCover))
333  obj.form.t_sideCover.setText(str(vobj.Object.TopCover))
334  obj.form.b_sideCover.setText(str(vobj.Object.BottomCover))
335  obj.form.diameter.setText(str(vobj.Object.Diameter))
336  obj.form.bentAngle.setCurrentIndex(obj.form.bentAngle.findText(str(vobj.Object.BentAngle)))
337  obj.form.bentFactor.setValue(vobj.Object.BentFactor)
338  obj.form.rounding.setValue(vobj.Object.Rounding)
339  if vobj.Object.AmountCheck:
340  obj.form.amount.setValue(vobj.Object.Amount)
341  else:
342  obj.form.amount_radio.setChecked(False)
343  obj.form.spacing_radio.setChecked(True)
344  obj.form.amount.setDisabled(True)
345  obj.form.spacing.setEnabled(True)
346  obj.form.spacing.setText(str(vobj.Object.TrueSpacing))
347  #obj.form.PickSelectedFace.setVisible(False)
348  FreeCADGui.Control.showDialog(obj)
349 
351  selected_obj = check_selected_face()
352  if selected_obj:
353  FreeCADGui.Control.showDialog(_StirrupTaskPanel())
def editDialog(vobj)
Definition: Stirrup.py:327
def accept(self, signal=None)
Definition: Stirrup.py:153
def check_selected_face()
Definition: Rebarfunc.py:255
def extendedTangentLength(rounding, diameter, angle)
Definition: Rebarfunc.py:243
def __init__(self, Rebar=None)
Definition: Stirrup.py:124
def getSelectedFace(self)
Definition: Rebarfunc.py:278
def getFaceNumber(s)
Definition: Rebarfunc.py:72
def runRebarDistribution(self)
def CommandStirrup()
Definition: Stirrup.py:350
def showPopUpImageDialog(img)
Definition: PopUpImage.py:43
def removeRebarDistribution(self)
def showWarning(message)
Definition: Rebarfunc.py:293
def editStirrup(Rebar, l_cover, r_cover, t_cover, b_cover, f_cover, bentAngle, bentFactor, diameter, rounding, amount_spacing_check, amount_spacing_value, structure=None, facename=None)
Definition: Stirrup.py:281
def getParametersOfFace(structure, facename, sketch=True)
Definition: Rebarfunc.py:126
def amount_radio_clicked(self)
Definition: Stirrup.py:200
def clicked(self, button)
Definition: Stirrup.py:149
def makeStirrup(l_cover, r_cover, t_cover, b_cover, f_cover, bentAngle, bentFactor, diameter, rounding, amount_spacing_check, amount_spacing_value, structure=None, facename=None)
Definition: Stirrup.py:210
def getpointsOfStirrup(FacePRM, l_cover, r_cover, t_cover, b_cover, bentAngle, bentFactor, diameter, rounding, facenormal)
Definition: Stirrup.py:40
def extendedTangentPartLength(rounding, diameter, angle)
Definition: Rebarfunc.py:235
def spacing_radio_clicked(self)
Definition: Stirrup.py:204
def getStandardButtons(self)
Definition: Stirrup.py:146