Added trim option to GZ curves tool
This commit is contained in:
parent
bdd5e0bc99
commit
6bc60de9bd
|
@ -439,9 +439,9 @@ def KBT(ship, draft, trim, roll=0.0):
|
|||
@param draft Draft.
|
||||
@param trim Trim in degrees.
|
||||
@param roll Roll angle in degrees.
|
||||
@return [KBTx, KBTy]: \n
|
||||
KBTy : TRansversal KB y coordinate \n
|
||||
KBTz : TRansversal KB z coordinate
|
||||
@return [KBTy, KBTz]: \n
|
||||
KBTy : Transversal KB y coordinate \n
|
||||
KBTz : Transversal KB z coordinate
|
||||
"""
|
||||
angle = math.radians(trim)
|
||||
rAngle = math.radians(roll)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
import math
|
||||
# FreeCAD modules
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
|
@ -37,7 +38,6 @@ class TaskPanel:
|
|||
self.ui = Paths.modulePath() + "/tankGZ/TaskPanel.ui"
|
||||
self.ship = None
|
||||
self.tanks = {}
|
||||
self.trim = 0.0
|
||||
|
||||
def accept(self):
|
||||
if not self.ship:
|
||||
|
@ -71,11 +71,13 @@ class TaskPanel:
|
|||
pass
|
||||
|
||||
def setupUi(self):
|
||||
mw = self.getMainWindow()
|
||||
form = mw.findChild(QtGui.QWidget, "TaskPanel")
|
||||
form.tanks = form.findChild(QtGui.QListWidget, "Tanks")
|
||||
form.disp = form.findChild(QtGui.QLabel, "DisplacementLabel")
|
||||
form.draft = form.findChild(QtGui.QLabel, "DraftLabel")
|
||||
mw = self.getMainWindow()
|
||||
form = mw.findChild(QtGui.QWidget, "TaskPanel")
|
||||
form.tanks = form.findChild(QtGui.QListWidget, "Tanks")
|
||||
form.disp = form.findChild(QtGui.QLabel, "DisplacementLabel")
|
||||
form.draft = form.findChild(QtGui.QLabel, "DraftLabel")
|
||||
form.trim = form.findChild(QtGui.QDoubleSpinBox, "Trim")
|
||||
form.autoTrim = form.findChild(QtGui.QPushButton, "TrimAutoCompute")
|
||||
self.form = form
|
||||
# Initial values
|
||||
if self.initValues():
|
||||
|
@ -84,6 +86,8 @@ class TaskPanel:
|
|||
self.onTanksSelection()
|
||||
# Connect Signals and Slots
|
||||
QtCore.QObject.connect(form.tanks,QtCore.SIGNAL("itemSelectionChanged()"),self.onTanksSelection)
|
||||
QtCore.QObject.connect(form.trim,QtCore.SIGNAL("valueChanged(double)"),self.onTrim)
|
||||
QtCore.QObject.connect(form.autoTrim,QtCore.SIGNAL("pressed()"),self.onAutoTrim)
|
||||
return False
|
||||
|
||||
def getMainWindow(self):
|
||||
|
@ -166,6 +170,10 @@ class TaskPanel:
|
|||
self.form.setWindowTitle(Translator.translate("GZ curve computation"))
|
||||
self.form.findChild(QtGui.QGroupBox, "LoadConditionGroup").setTitle(Translator.translate("Loading condition."))
|
||||
self.form.findChild(QtGui.QGroupBox, "AnglesGroup").setTitle(Translator.translate("Roll angles."))
|
||||
self.form.findChild(QtGui.QLabel, "TrimLabel").setText(Translator.translate("Trim") + " [deg]")
|
||||
self.form.findChild(QtGui.QLabel, "StartAngleLabel").setText(Translator.translate("Start") + " [deg]")
|
||||
self.form.findChild(QtGui.QLabel, "EndAngleLabel").setText(Translator.translate("Start") + " [deg]")
|
||||
self.form.findChild(QtGui.QLabel, "NAngleLabel").setText(Translator.translate("Number of points"))
|
||||
|
||||
def onTanksSelection(self):
|
||||
""" Called when tanks are selected or deselected.
|
||||
|
@ -174,8 +182,59 @@ class TaskPanel:
|
|||
disp = self.computeDisplacement()
|
||||
self.form.disp.setText(Translator.translate("Displacement") + ' = %g [kg]' % (disp[0]))
|
||||
# Set draft label
|
||||
draft = self.computeDraft(disp[0])
|
||||
self.form.draft.setText(Translator.translate("Draft") + ' = %g [m]' % (draft))
|
||||
draft = self.computeDraft(disp[0], self.form.trim.value())
|
||||
self.form.draft.setText(Translator.translate("Draft") + ' = %g [m]' % (draft[0]))
|
||||
|
||||
def onTrim(self, trim):
|
||||
""" Called when trim angle value is changed.
|
||||
@param trim Selected trim angle.
|
||||
"""
|
||||
self.onTanksSelection()
|
||||
|
||||
def onAutoTrim(self):
|
||||
""" Called when trim angle must be auto computed.
|
||||
"""
|
||||
# Start at null trim angle
|
||||
trim = 0.0
|
||||
# Get center of gravity
|
||||
disp = self.computeDisplacement(trim)
|
||||
G = [disp[1], disp[2], disp[3]]
|
||||
disp = disp[0]
|
||||
# Get bouyancy center
|
||||
draft = self.computeDraft(disp)
|
||||
xcb = draft[1]
|
||||
draft = draft[0]
|
||||
KBT = Hydrostatics.KBT(self.ship, draft, trim)
|
||||
B = [xcb, KBT[0], KBT[1]]
|
||||
# Get stability initial condition
|
||||
BG = [G[0]-B[0], G[1]-B[1], G[2]-B[2]]
|
||||
x = BG[0]*math.cos(math.radians(trim)) - BG[2]*math.sin(math.radians(trim))
|
||||
y = BG[1]
|
||||
z = BG[0]*math.sin(math.radians(trim)) + BG[2]*math.cos(math.radians(trim))
|
||||
var = math.degrees(math.atan2(x,z))
|
||||
# Iterate looking stability point
|
||||
dVar = math.copysign(0.0033, var)
|
||||
while True:
|
||||
if (dVar*math.copysign(dVar, var) < 0.0):
|
||||
break
|
||||
trim = trim - math.copysign(dVar, var)
|
||||
# Get center of gravity
|
||||
disp = self.computeDisplacement(trim)
|
||||
G = [disp[1], disp[2], disp[3]]
|
||||
disp = disp[0]
|
||||
# Get bouyancy center
|
||||
draft = self.computeDraft(disp, trim)
|
||||
xcb = draft[1]
|
||||
draft = draft[0]
|
||||
KBT = Hydrostatics.KBT(self.ship, draft, trim)
|
||||
B = [xcb, KBT[0], KBT[1]]
|
||||
# Get stability initial condition
|
||||
BG = [G[0]-B[0], G[1]-B[1], G[2]-B[2]]
|
||||
x = BG[0]*math.cos(math.radians(trim)) - BG[2]*math.sin(math.radians(trim))
|
||||
y = BG[1]
|
||||
z = BG[0]*math.sin(math.radians(trim)) + BG[2]*math.cos(math.radians(trim))
|
||||
var = math.degrees(math.atan2(x,z))
|
||||
self.form.trim.setValue(trim)
|
||||
|
||||
def getTanks(self):
|
||||
""" Get the selected tanks objects list.
|
||||
|
@ -186,14 +245,15 @@ class TaskPanel:
|
|||
for item in items:
|
||||
tag = str(item.text())
|
||||
name = self.tanks[tag]
|
||||
t = App.ActiveDocument.getObject('Tank')
|
||||
t = App.ActiveDocument.getObject(name)
|
||||
if not t:
|
||||
continue
|
||||
tanks.append(t)
|
||||
return tanks
|
||||
|
||||
def computeDisplacement(self):
|
||||
def computeDisplacement(self, trim=0.0):
|
||||
""" Computes ship displacement.
|
||||
@param trim Trim angle [degrees].
|
||||
@return Ship displacement and center of gravity. None if errors detected.
|
||||
"""
|
||||
if not self.ship:
|
||||
|
@ -209,33 +269,39 @@ class TaskPanel:
|
|||
# Get selected tanks weights
|
||||
tanks = self.getTanks()
|
||||
for t in tanks:
|
||||
w = tankWeight(t)
|
||||
w = tankWeight(t, App.Base.Vector(0.0,-trim,0.0))
|
||||
# Unrotate center of gravity
|
||||
x = w[1]*math.cos(math.radians(-trim)) - w[3]*math.sin(math.radians(-trim))
|
||||
y = w[2]
|
||||
z = w[1]*math.sin(math.radians(-trim)) + w[3]*math.cos(math.radians(-trim))
|
||||
W[0] = W[0] + w[0]
|
||||
W[1] = W[1] + w[0]*w[1]
|
||||
W[2] = W[2] + w[0]*w[2]
|
||||
W[3] = W[3] + w[0]*w[3]
|
||||
W[1] = W[1] + w[0]*x
|
||||
W[2] = W[2] + w[0]*y
|
||||
W[3] = W[3] + w[0]*z
|
||||
return [W[0], W[1]/W[0], W[2]/W[0], W[3]/W[0]]
|
||||
|
||||
def computeDraft(self, disp):
|
||||
def computeDraft(self, disp, trim=0.0):
|
||||
""" Computes ship draft.
|
||||
@param disp Ship displacement.
|
||||
@return Ship draft. None if errors detected.
|
||||
@note 0 trim will be assumed.
|
||||
@param trim Trim angle [degrees].
|
||||
@return Ship draft, and longitudinal bouyance center position. None if errors detected.
|
||||
"""
|
||||
if not self.ship:
|
||||
return None
|
||||
# Initial condition
|
||||
trim = 0.0
|
||||
dens = 1025
|
||||
bbox = self.ship.Shape.BoundBox
|
||||
draft = bbox.ZMin
|
||||
dx = bbox.XMax - bbox.XMin
|
||||
dy = bbox.YMax - bbox.YMin
|
||||
w = 0.0
|
||||
xcb = 0.0
|
||||
while(abs(disp - w)/disp > 0.01):
|
||||
draft = draft + (disp - w) / (dens*dx*dy)
|
||||
w = 1000.0*Hydrostatics.Displacement(self.ship, draft, trim)[1]
|
||||
return draft
|
||||
ww = Hydrostatics.Displacement(self.ship, draft, trim)
|
||||
w = 1000.0*ww[1]
|
||||
xcb = ww[2]
|
||||
return [draft,xcb]
|
||||
|
||||
def createTask():
|
||||
panel = TaskPanel()
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>256</width>
|
||||
<height>368</height>
|
||||
<height>408</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>256</width>
|
||||
<height>368</height>
|
||||
<height>408</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -25,7 +25,7 @@
|
|||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
<verstretch>6</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeIncrement">
|
||||
|
@ -43,7 +43,7 @@
|
|||
<x>0</x>
|
||||
<y>20</y>
|
||||
<width>231</width>
|
||||
<height>151</height>
|
||||
<height>231</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
|
@ -71,6 +71,55 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="TrimLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>3</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trim [deg]</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="Trim">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>3</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-45.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>45.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="TrimAutoCompute">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
@ -78,9 +127,9 @@
|
|||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="AnglesGroup">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
<verstretch>3</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
|
@ -92,7 +141,7 @@
|
|||
<x>0</x>
|
||||
<y>20</y>
|
||||
<width>231</width>
|
||||
<height>141</height>
|
||||
<height>101</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
|
@ -121,13 +170,28 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox"/>
|
||||
<widget class="QDoubleSpinBox" name="StartAngle">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>90.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_2"/>
|
||||
<widget class="QDoubleSpinBox" name="EndAngle">
|
||||
<property name="maximum">
|
||||
<double>90.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="spinBox"/>
|
||||
<widget class="QSpinBox" name="NAngle">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
Loading…
Reference in New Issue
Block a user