Skip to content

Commit

Permalink
Merge pull request #34 from davesrocketshop/dev2.6.1
Browse files Browse the repository at this point in the history
Dev2.6.1
  • Loading branch information
davesrocketshop authored Jul 31, 2022
2 parents 9ef1312 + 5e4bf5e commit 27a93fa
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 21 deletions.
6 changes: 6 additions & 0 deletions App/Constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def QT_TRANSLATE_NOOP(scope, text):
FEATURE_BODY_TUBE = "RocketBodyTube"
FEATURE_CENTERING_RING = "RocketCenteringRing"
FEATURE_FIN = "RocketFin"
FEATURE_FINCAN = "RocketFincan"
FEATURE_NOSE_CONE = "RocketNoseCone"
FEATURE_TRANSITION = "RocketTransition"
FEATURE_LAUNCH_LUG = "RocketLaunchLug"
Expand All @@ -45,6 +46,11 @@ def QT_TRANSLATE_NOOP(scope, text):
STYLE_HOLLOW = "hollow"
STYLE_CAPPED = "capped"

# Cap styles
STYLE_CAP_SOLID = "solid"
STYLE_CAP_BAR = "bar"
STYLE_CAP_CROSS = "cross"

# Part shapes
TYPE_CONE = "cone"
TYPE_BLUNTED_CONE = "blunted cone"
Expand Down
50 changes: 48 additions & 2 deletions App/NoseShapeHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from DraftTools import translate

from App.Constants import STYLE_CAPPED, STYLE_HOLLOW, STYLE_SOLID
from App.Constants import STYLE_CAP_BAR, STYLE_CAP_CROSS
from App.Constants import TYPE_BLUNTED_CONE, TYPE_BLUNTED_OGIVE, TYPE_SECANT_OGIVE

from App.Utilities import _err
Expand All @@ -45,6 +46,8 @@ def __init__(self, obj):
# Common parameters
self._type = str(obj.NoseType)
self._style = str(obj.NoseStyle)
self._capStyle = str(obj.CapStyle)
self._capBarWidth = float(obj.CapBarWidth)
self._thickness = float(obj.Thickness)

self._shoulder = bool(obj.Shoulder)
Expand Down Expand Up @@ -105,6 +108,31 @@ def isValidShape(self):
return False

return True

def _barCap(self):
return self._crossCap(barOnly = True)

def _crossCap(self, barOnly = False):
BASE_WIDTH = 5
base = 0.0 - BASE_WIDTH
length = self._thickness + BASE_WIDTH
if self._shoulder:
length += self._shoulderLength
base -= self._shoulderLength

point = FreeCAD.Vector(base, 0, 0)
direction = FreeCAD.Vector(1,0,0)

mask = Part.makeCylinder(self._shoulderRadius - self._shoulderThickness, length, point, direction)

point = FreeCAD.Vector(base + BASE_WIDTH, self._radius, -(self._capBarWidth / 2.0))
box = Part.makeBox(self._capBarWidth, 2.0 * self._radius, length - BASE_WIDTH, point, direction)
mask = mask.cut(box)
if not barOnly:
point = FreeCAD.Vector(base + BASE_WIDTH, (self._capBarWidth / 2.0), -self._radius)
box = Part.makeBox(2.0 * self._radius, self._capBarWidth, length - BASE_WIDTH, point, direction)
mask = mask.cut(box)
return mask

def draw(self):
if not self.isValidShape():
Expand Down Expand Up @@ -132,17 +160,35 @@ def draw(self):
_err(translate('Rocket', "Nose cone parameters produce an invalid shape"))
return

shape = None
if edges is not None:
try:
wire = Part.Wire(edges)
face = Part.Face(wire)
self._obj.Shape = face.revolve(FreeCAD.Vector(0, 0, 0),FreeCAD.Vector(1, 0, 0), 360)
self._obj.Placement = self._placement
shape = face.revolve(FreeCAD.Vector(0, 0, 0),FreeCAD.Vector(1, 0, 0), 360)
except Part.OCCError:
_err(translate('Rocket', "Nose cone parameters produce an invalid shape"))
return
else:
_err(translate('Rocket', "Nose cone parameters produce an invalid shape"))
return

try:
if self._style == STYLE_CAPPED:
mask = None
if self._capStyle == STYLE_CAP_BAR:
mask = self._barCap()
elif self._capStyle == STYLE_CAP_CROSS:
mask = self._crossCap()

if mask is not None:
shape = shape.cut(mask)
except Part.OCCError:
_err(translate('Rocket', "Nose cone cap style produces an invalid shape"))
return

self._obj.Shape = shape
self._obj.Placement = self._placement

def toShape(self, shapeObject):
if hasattr(shapeObject, 'toShape'):
Expand Down
4 changes: 2 additions & 2 deletions App/ShapeFin.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,15 @@ def __init__(self, obj):
# These are only exposed for fin cans
if not hasattr(obj,"FinSet"):
obj.addProperty('App::PropertyBool', 'FinSet', 'Fin', translate('App::Property', 'True when describing a set of fins')).FinSet = False
obj.setEditorMode('FinSet', PROP_TRANSIENT | PROP_HIDDEN) # hide
obj.setEditorMode('FinSet', PROP_HIDDEN) # hide
if not hasattr(obj,"FinCount"):
obj.addProperty('App::PropertyInteger', 'FinCount', 'Fin', translate('App::Property', 'Number of fins in a radial pattern')).FinCount = 3
if not hasattr(obj,"FinSpacing"):
obj.addProperty('App::PropertyAngle', 'FinSpacing', 'Fin', translate('App::Property', 'Angle between consecutive fins')).FinSpacing = 120

# Hidden properties used for calculation
if not hasattr(obj,"ParentRadius"):
obj.addProperty('App::PropertyLength', 'ParentRadius', 'Fin', translate('App::Property', 'Parent radius')).ParentRadius = 20.0
obj.addProperty('App::PropertyLength', 'ParentRadius', 'Fin', 'Parent radius').ParentRadius = 20.0 # No translation required for a hidden parameter
obj.setEditorMode('ParentRadius', PROP_TRANSIENT | PROP_HIDDEN) # hide

if not hasattr(obj, "Profile"):
Expand Down
2 changes: 1 addition & 1 deletion App/ShapeFinCan.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def __init__(self, obj):
if not hasattr(obj,"LugAutoThickness"):
obj.addProperty('App::PropertyBool', 'LugAutoThickness', 'Fin', translate('App::Property', 'Launch lug thickness is the same as the fin can')).LugAutoThickness = True
if not hasattr(obj,"LugLength"):
obj.addProperty('App::PropertyLength', 'LugLength', 'Fin', translate('App::Property', 'Length of the launch')).LugLength = 60.0
obj.addProperty('App::PropertyLength', 'LugLength', 'Fin', translate('App::Property', 'Length of the launch lug')).LugLength = 60.0
if not hasattr(obj,"LugAutoLength"):
obj.addProperty('App::PropertyBool', 'LugAutoLength', 'Fin', translate('App::Property', 'Automatically adjust the length of the launch lug')).LugAutoLength = True
if not hasattr(obj,"LugFilletRadius"):
Expand Down
10 changes: 10 additions & 0 deletions App/ShapeNoseCone.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

from App.Constants import TYPE_CONE, TYPE_BLUNTED_CONE, TYPE_SPHERICAL, TYPE_ELLIPTICAL, TYPE_HAACK, TYPE_OGIVE, TYPE_BLUNTED_OGIVE, TYPE_SECANT_OGIVE, TYPE_VON_KARMAN, TYPE_PARABOLA, TYPE_PARABOLIC, TYPE_POWER
from App.Constants import STYLE_CAPPED, STYLE_HOLLOW, STYLE_SOLID
from App.Constants import STYLE_CAP_SOLID, STYLE_CAP_BAR, STYLE_CAP_CROSS

from App.Utilities import _wrn

Expand Down Expand Up @@ -92,6 +93,8 @@ class ShapeNoseCone(ShapeComponent):
def __init__(self, obj):
super().__init__(obj)

if not hasattr(obj, 'CapBarWidth'):
obj.addProperty('App::PropertyLength', 'CapBarWidth', 'NoseCone', translate('App::Property', 'Width of the nose cap bar')).CapBarWidth = 3.0
if not hasattr(obj, 'Length'):
obj.addProperty('App::PropertyLength', 'Length', 'NoseCone', translate('App::Property', 'Length of the nose not including any shoulder')).Length = 60.0
if not hasattr(obj, 'BluntedDiameter'):
Expand Down Expand Up @@ -138,6 +141,13 @@ def __init__(self, obj):
STYLE_CAPPED]
obj.NoseStyle = STYLE_SOLID

if not hasattr(obj, 'CapStyle'):
obj.addProperty('App::PropertyEnumeration', 'CapStyle', 'NoseCone', translate('App::Property', 'Nose cone cap style'))
obj.CapStyle = [STYLE_CAP_SOLID,
STYLE_CAP_BAR,
STYLE_CAP_CROSS]
obj.CapStyle = STYLE_CAP_SOLID

if not hasattr(obj, 'Shape'):
obj.addProperty('Part::PropertyPartShape', 'Shape', 'NoseCone', translate('App::Property', 'Shape of the nose cone'))

Expand Down
14 changes: 7 additions & 7 deletions Ui/TaskPanelFin.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@ def onTipLength2(self, value):
def onHeight(self, value):
try:
self._obj.Height = FreeCAD.Units.Quantity(value).Value
self._sweepAngleFromLength(self._finForm.sweepLengthInput.property("quantity").Value)
self._sweepAngleFromLength(self._obj.SweepLength)
self.redraw()
except ValueError:
pass
Expand All @@ -720,28 +720,28 @@ def _sweepLengthFromAngle(self, value):
_err("Sweep angle must be greater than -90 and less than +90")
return
theta = math.radians(-1.0 * (theta + 90.0))
length = self._finForm.heightInput.property("quantity").Value / math.tan(theta)
self._finForm.sweepLengthInput.setText("%f" % length)
length = _toFloat(self._obj.Height) / math.tan(theta)
self._obj.SweepLength = length
self._finForm.sweepLengthInput.setText(self._obj.SweepLength.UserString)

def _sweepAngleFromLength(self, value):
length = _toFloat(value)
theta = 90.0 - math.degrees(math.atan2(self._finForm.heightInput.property("quantity").Value, length))
self._finForm.sweepAngleInput.setText("%f" % theta)
theta = 90.0 - math.degrees(math.atan2(_toFloat(self._obj.Height), length))
self._obj.SweepAngle = theta
self._finForm.sweepAngleInput.setText(self._obj.SweepAngle.UserString)

def onSweepLength(self, value):
try:
self._obj.SweepLength = FreeCAD.Units.Quantity(value).Value
self._sweepAngleFromLength(value)
self._sweepAngleFromLength(self._obj.SweepLength)
self.redraw()
except ValueError:
pass

def onSweepAngle(self, value):
try:
self._obj.SweepAngle = FreeCAD.Units.Quantity(value).Value
self._sweepLengthFromAngle(value)
self._sweepLengthFromAngle(self._obj.SweepAngle)
self.redraw()
except ValueError:
pass
Expand Down
14 changes: 7 additions & 7 deletions Ui/TaskPanelFinCan.py
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,7 @@ def onTipLength2(self, value):
def onHeight(self, value):
try:
self._obj.Height = FreeCAD.Units.Quantity(value).Value
self._sweepAngleFromLength(self._finForm.sweepLengthInput.property("quantity").Value)
self._sweepAngleFromLength(self._obj.SweepLength)
self.redraw()
except ValueError:
pass
Expand All @@ -1004,28 +1004,28 @@ def _sweepLengthFromAngle(self, value):
_err("Sweep angle must be greater than -90 and less than +90")
return
theta = math.radians(-1.0 * (theta + 90.0))
length = self._finForm.heightInput.property("quantity").Value / math.tan(theta)
self._finForm.sweepLengthInput.setText("%f" % length)
length = _toFloat(self._obj.Height) / math.tan(theta)
self._obj.SweepLength = length
self._finForm.sweepLengthInput.setText(self._obj.SweepLength.UserString)

def _sweepAngleFromLength(self, value):
length = _toFloat(value)
theta = 90.0 - math.degrees(math.atan2(self._finForm.heightInput.property("quantity").Value, length))
self._finForm.sweepAngleInput.setText("%f" % theta)
theta = 90.0 - math.degrees(math.atan2(_toFloat(self._obj.Height), length))
self._obj.SweepAngle = theta
self._finForm.sweepAngleInput.setText(self._obj.SweepAngle.UserString)

def onSweepLength(self, value):
try:
self._obj.SweepLength = FreeCAD.Units.Quantity(value).Value
self._sweepAngleFromLength(value)
self._sweepAngleFromLength(self._obj.SweepLength)
self.redraw()
except ValueError:
pass

def onSweepAngle(self, value):
try:
self._obj.SweepAngle = FreeCAD.Units.Quantity(value).Value
self._sweepLengthFromAngle(value)
self._sweepLengthFromAngle(self._obj.SweepAngle)
self.redraw()
except ValueError:
pass
Expand Down
66 changes: 66 additions & 0 deletions Ui/TaskPanelNoseCone.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from Ui.TaskPanelDatabase import TaskPanelDatabase
from App.Constants import TYPE_CONE, TYPE_BLUNTED_CONE, TYPE_SPHERICAL, TYPE_ELLIPTICAL, TYPE_HAACK, TYPE_OGIVE, TYPE_BLUNTED_OGIVE, TYPE_SECANT_OGIVE, TYPE_VON_KARMAN, TYPE_PARABOLA, TYPE_PARABOLIC, TYPE_POWER
from App.Constants import STYLE_CAPPED, STYLE_HOLLOW, STYLE_SOLID
from App.Constants import STYLE_CAP_SOLID, STYLE_CAP_BAR, STYLE_CAP_CROSS
from App.Constants import COMPONENT_TYPE_NOSECONE

from App.Utilities import _toFloat, _valueWithUnits
Expand Down Expand Up @@ -135,6 +136,36 @@ def setTabGeneral(self):
self.ogiveDiameterInput.unit = 'mm'
self.ogiveDiameterInput.setMinimumWidth(100)

# Nose cap styles
self.noseCapGroup = QtGui.QGroupBox(translate('Rocket', "Nose Cap"), self)

self.noseCapStyleLabel = QtGui.QLabel(translate('Rocket', "Cap style"), self)

self.noseCapStyles = (STYLE_CAP_SOLID,
STYLE_CAP_BAR,
STYLE_CAP_CROSS)
self.noseCapStylesCombo = QtGui.QComboBox(self)
self.noseCapStylesCombo.addItems(self.noseCapStyles)

self.noseCapBarWidthLabel = QtGui.QLabel(translate('Rocket', "Bar Width"), self)

self.noseCapBarWidthInput = ui.createWidget("Gui::InputField")
self.noseCapBarWidthInput.unit = 'mm'
self.noseCapBarWidthInput.setMinimumWidth(100)

# Nose cap group
row = 0
grid = QGridLayout()

grid.addWidget(self.noseCapStyleLabel, row, 0)
grid.addWidget(self.noseCapStylesCombo, row, 1)
row += 1

grid.addWidget(self.noseCapBarWidthLabel, row, 0)
grid.addWidget(self.noseCapBarWidthInput, row, 1)

self.noseCapGroup.setLayout(grid)

layout = QGridLayout()
row = 0

Expand All @@ -146,6 +177,9 @@ def setTabGeneral(self):
layout.addWidget(self.noseStylesCombo, row, 1)
row += 1

layout.addWidget(self.noseCapGroup, row, 0, 1, 2)
row += 1

layout.addWidget(self.lengthLabel, row, 0)
layout.addWidget(self.lengthInput, row, 1)
row += 1
Expand Down Expand Up @@ -239,6 +273,8 @@ def __init__(self,obj,mode):

self._noseForm.noseConeTypesCombo.currentTextChanged.connect(self.onNoseType)
self._noseForm.noseStylesCombo.currentTextChanged.connect(self.onNoseStyle)
self._noseForm.noseCapStylesCombo.currentTextChanged.connect(self.onNoseCapStyle)
self._noseForm.noseCapBarWidthInput.textEdited.connect(self.onBarWidthChanged)

self._noseForm.lengthInput.textEdited.connect(self.onLengthChanged)
self._noseForm.bluntedInput.textEdited.connect(self.onBluntedChanged)
Expand All @@ -264,6 +300,8 @@ def transferTo(self):
"Transfer from the dialog to the object"
self._obj.NoseType = str(self._noseForm.noseConeTypesCombo.currentText())
self._obj.NoseStyle = str(self._noseForm.noseStylesCombo.currentText())
self._obj.CapStyle = str(self._noseForm.noseCapStylesCombo.currentText())
self._obj.CapBarWidth = self._noseForm.noseCapBarWidthInput.text()
self._obj.Length = self._noseForm.lengthInput.text()
self._obj.BluntedDiameter = self._noseForm.bluntedInput.text()
self._obj.Diameter = self._noseForm.diameterInput.text()
Expand All @@ -279,6 +317,8 @@ def transferFrom(self):
"Transfer from the object to the dialog"
self._noseForm.noseConeTypesCombo.setCurrentText(self._obj.NoseType)
self._noseForm.noseStylesCombo.setCurrentText(self._obj.NoseStyle)
self._noseForm.noseCapStylesCombo.setCurrentText(self._obj.CapStyle)
self._noseForm.noseCapBarWidthInput.setText(self._obj.CapBarWidth.UserString)
self._noseForm.lengthInput.setText(self._obj.Length.UserString)
self._noseForm.bluntedInput.setText(self._obj.BluntedDiameter.UserString)
self._noseForm.diameterInput.setText(self._obj.Diameter.UserString)
Expand Down Expand Up @@ -358,12 +398,38 @@ def _setStyleState(self):
else:
self._noseForm.thicknessInput.setEnabled(False)
self._noseForm.shoulderThicknessInput.setEnabled(False)

if value == STYLE_CAPPED:
self._noseForm.noseCapGroup.setEnabled(True)
self._setCapStyleState()
else:
self._noseForm.noseCapGroup.setEnabled(False)

def onNoseStyle(self, value):
self._obj.NoseStyle = value
self._setStyleState()

self._obj.Proxy.execute(self._obj)

def _setCapStyleState(self):
value = self._obj.CapStyle
if value == STYLE_CAP_SOLID:
self._noseForm.noseCapBarWidthInput.setEnabled(False)
else:
self._noseForm.noseCapBarWidthInput.setEnabled(True)

def onNoseCapStyle(self, value):
self._obj.CapStyle = value
self._setCapStyleState()

self._obj.Proxy.execute(self._obj)

def onBarWidthChanged(self, value):
try:
self._obj.CapBarWidth = FreeCAD.Units.Quantity(value).Value
self._obj.Proxy.execute(self._obj)
except ValueError:
pass

def onLengthChanged(self, value):
try:
Expand Down
4 changes: 2 additions & 2 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<package format="1" xmlns="https://wiki.freecad.org/Package_Metadata">
<name>Rocket</name>
<description>A workbench for designing model rockets.</description>
<version>2.5.1</version>
<date>2022-07-15</date>
<version>2.6.1</version>
<date>2022-07-31</date>
<maintainer email="[email protected]">David Carter</maintainer>
<license file="LICENSE">LGPLv2.1</license>
<url type="repository" branch="master">https://github.com/davesrocketshop/Rocket</url>
Expand Down

0 comments on commit 27a93fa

Please sign in to comment.