Added all the Hydrostatics to the console interface
This commit is contained in:
parent
c65dbe1db1
commit
0a4a8191a2
|
@ -30,4 +30,5 @@ __doc__="The Ships module provide a set of tools to make some specific Naval" \
|
|||
" Architecture computations"
|
||||
|
||||
from shipCreateShip.Tools import createShip
|
||||
from shipHydrostatics.Tools import areas
|
||||
from shipHydrostatics.Tools import areas, displacement, wettedArea, moment,
|
||||
floatingArea, BMT, mainFrameCoeff
|
|
@ -89,9 +89,9 @@ class Plot(object):
|
|||
addInfo = ("$XCB = {0} \\; \\mathrm{{m}}$\n"
|
||||
"$Area_{{max}} = {1} \\; \\mathrm{{m}}^2$\n"
|
||||
"$\\bigtriangleup = {2} \\; \\mathrm{{tons}}$".format(
|
||||
xcb,
|
||||
xcb.getValueAs("m").Value,
|
||||
maxArea,
|
||||
disp))
|
||||
disp.getValueAs("kg").Value / 1000.0))
|
||||
ax.text(0.0,
|
||||
0.01 * maxArea,
|
||||
addInfo,
|
||||
|
|
|
@ -55,11 +55,11 @@ class Preview(object):
|
|||
point = Base.Vector(x, y, 0.0)
|
||||
plane = Part.makePlane(L, B, point, Base.Vector(0, 0, 1))
|
||||
plane.rotate(Base.Vector(0, 0, 0), Base.Vector(0, 1, 0), trim)
|
||||
plane.translate(Base.Vector(0, 0, draft * Units.Metre.Value))
|
||||
plane.translate(Base.Vector(0, 0, draft))
|
||||
Part.show(plane)
|
||||
objs = FreeCAD.ActiveDocument.Objects
|
||||
self.obj = objs[len(objs) - 1]
|
||||
self.obj.Label = 'FreeSurface'
|
||||
self.obj.Label = 'FreeSurfaceHelper'
|
||||
guiObj = FreeCADGui.ActiveDocument.getObject(self.obj.Name)
|
||||
guiObj.ShapeColor = (0.4, 0.8, 0.85)
|
||||
guiObj.Transparency = 50
|
||||
|
@ -69,4 +69,4 @@ class Preview(object):
|
|||
if not self.obj:
|
||||
return
|
||||
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
|
||||
self.obj = None
|
||||
self.obj = None
|
|
@ -55,12 +55,11 @@ class TaskPanel:
|
|||
trim = Units.parseQuantity(Locale.fromString(form.trim.text()))
|
||||
num = form.num.value()
|
||||
|
||||
data = Hydrostatics.displacement(self.ship,
|
||||
draft.getValueAs("m").Value,
|
||||
0.0,
|
||||
trim.getValueAs("deg").Value)
|
||||
disp = data[0]
|
||||
xcb = data[1].x
|
||||
disp, B, _ = Hydrostatics.displacement(self.ship,
|
||||
draft,
|
||||
Units.parseQuantity("0 deg"),
|
||||
trim)
|
||||
xcb = Units.Quantity(B.x, Units.Length)
|
||||
data = Hydrostatics.areas(self.ship,
|
||||
num,
|
||||
draft=draft,
|
||||
|
@ -245,24 +244,11 @@ class TaskPanel:
|
|||
None,
|
||||
QtGui.QApplication.UnicodeUTF8))
|
||||
|
||||
def clampLength(self, widget, val_min, val_max, val):
|
||||
if val >= val_min and val <= val_max:
|
||||
def clampValue(self, widget, val_min, val_max, val):
|
||||
if val_min <= val <= val_max:
|
||||
return val
|
||||
input_format = USys.getLengthFormat()
|
||||
val = min(val_max, max(val_min, val))
|
||||
qty = Units.Quantity('{} m'.format(val))
|
||||
widget.setText(Locale.toString(input_format.format(
|
||||
qty.getValueAs(USys.getLengthUnits()).Value)))
|
||||
return val
|
||||
|
||||
def clampAngle(self, widget, val_min, val_max, val):
|
||||
if val >= val_min and val <= val_max:
|
||||
return val
|
||||
input_format = USys.getAngleFormat()
|
||||
val = min(val_max, max(val_min, val))
|
||||
qty = Units.Quantity('{} deg'.format(val))
|
||||
widget.setText(Locale.toString(input_format.format(
|
||||
qty.getValueAs(USys.getLengthUnits()).Value)))
|
||||
widget.setText(val.UserString)
|
||||
return val
|
||||
|
||||
def onData(self, value):
|
||||
|
@ -279,32 +265,24 @@ class TaskPanel:
|
|||
|
||||
# Get the values (or fix them in bad setting case)
|
||||
try:
|
||||
draft = Units.Quantity(Locale.fromString(
|
||||
form.draft.text())).getValueAs('m').Value
|
||||
draft = Units.parseQuantity(Locale.fromString(form.draft.text()))
|
||||
except:
|
||||
draft = self.ship.Draft.getValueAs(USys.getLengthUnits()).Value
|
||||
input_format = USys.getLengthFormat()
|
||||
qty = Units.Quantity('{} m'.format(draft))
|
||||
widget.setText(Locale.toString(input_format.format(
|
||||
qty.getValueAs(USys.getLengthUnits()).Value)))
|
||||
draft = self.ship.Draft
|
||||
form.draft.setText(draft.UserString)
|
||||
try:
|
||||
trim = Units.Quantity(Locale.fromString(
|
||||
form.trim.text())).getValueAs('deg').Value
|
||||
trim = Units.parseQuantity(Locale.fromString(form.trim.text()))
|
||||
except:
|
||||
trim = 0.0
|
||||
input_format = USys.getAngleFormat()
|
||||
qty = Units.Quantity('{} deg'.format(trim))
|
||||
widget.setText(Locale.toString(input_format.format(
|
||||
qty.getValueAs(USys.getLengthUnits()).Value)))
|
||||
trim = Units.parseQuantity("0 deg")
|
||||
form.trim.setText(trim.UserString)
|
||||
|
||||
bbox = self.ship.Shape.BoundBox
|
||||
draft_min = bbox.ZMin / Units.Metre.Value
|
||||
draft_max = bbox.ZMax / Units.Metre.Value
|
||||
draft = self.clampLength(form.draft, draft_min, draft_max, draft)
|
||||
draft_min = Units.Quantity(bbox.ZMin, Units.Length)
|
||||
draft_max = Units.Quantity(bbox.ZMax, Units.Length)
|
||||
draft = self.clampValue(form.draft, draft_min, draft_max, draft)
|
||||
|
||||
trim_min = -180.0
|
||||
trim_max = 180.0
|
||||
trim = self.clampAngle(form.trim, trim_min, trim_max, trim)
|
||||
trim_min = Units.parseQuantity("-180 deg")
|
||||
trim_max = Units.parseQuantity("180 deg")
|
||||
trim = self.clampValue(form.trim, trim_min, trim_max, trim)
|
||||
|
||||
self.onUpdate()
|
||||
self.preview.update(draft, trim, self.ship)
|
||||
|
@ -319,40 +297,39 @@ class TaskPanel:
|
|||
form.trim = self.widget(QtGui.QLineEdit, "Trim")
|
||||
form.output = self.widget(QtGui.QTextEdit, "OutputData")
|
||||
|
||||
draft = Units.Quantity(Locale.fromString(
|
||||
form.draft.text())).getValueAs('m').Value
|
||||
trim = Units.Quantity(Locale.fromString(
|
||||
form.trim.text())).getValueAs('deg').Value
|
||||
draft = Units.parseQuantity(Locale.fromString(form.draft.text()))
|
||||
trim = Units.parseQuantity(Locale.fromString(form.trim.text()))
|
||||
|
||||
# Calculate the drafts at each perpendicular
|
||||
angle = math.radians(trim)
|
||||
angle = trim.getValueAs("rad").Value
|
||||
L = self.ship.Length.getValueAs('m').Value
|
||||
B = self.ship.Breadth.getValueAs('m').Value
|
||||
draftAP = draft + 0.5 * L * math.tan(angle)
|
||||
draftAP = draft + 0.5 * self.ship.Length * math.tan(angle)
|
||||
if draftAP < 0.0:
|
||||
draftAP = 0.0
|
||||
draftFP = draft - 0.5 * L * math.tan(angle)
|
||||
draftFP = draft - 0.5 * self.ship.Length * math.tan(angle)
|
||||
if draftFP < 0.0:
|
||||
draftFP = 0.0
|
||||
# Calculate the involved hydrostatics
|
||||
data = Hydrostatics.displacement(self.ship,
|
||||
draft,
|
||||
0.0,
|
||||
trim)
|
||||
disp, B, _ = Hydrostatics.displacement(self.ship,
|
||||
draft,
|
||||
Units.parseQuantity("0 deg"),
|
||||
trim)
|
||||
xcb = Units.Quantity(B.x, Units.Length)
|
||||
# Setup the html string
|
||||
string = 'L = {0} [m]<BR>'.format(L)
|
||||
string = string + 'B = {0} [m]<BR>'.format(B)
|
||||
string = string + 'T = {0} [m]<HR>'.format(draft)
|
||||
string = string + 'Trim = {0} [degrees]<BR>'.format(trim)
|
||||
string = string + 'T<sub>AP</sub> = {0} [m]<BR>'.format(draftAP)
|
||||
string = string + 'T<sub>FP</sub> = {0} [m]<HR>'.format(draftFP)
|
||||
string = u'L = {0}<BR>'.format(self.ship.Length.UserString)
|
||||
string += u'B = {0}<BR>'.format(self.ship.Breadth.UserString)
|
||||
string += u'T = {0}<HR>'.format(draft.UserString)
|
||||
string += u'Trim = {0}<BR>'.format(trim.UserString)
|
||||
string += u'T<sub>AP</sub> = {0}<BR>'.format(draftAP.UserString)
|
||||
string += u'T<sub>FP</sub> = {0}<HR>'.format(draftFP.UserString)
|
||||
dispText = QtGui.QApplication.translate(
|
||||
"ship_areas",
|
||||
'Displacement',
|
||||
None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
string = string + dispText + ' = {0} [ton]<BR>'.format(data[0])
|
||||
string = string + 'XCB = {0} [m]'.format(data[1].x)
|
||||
string += dispText + u' = {0}<BR>'.format(disp.UserString)
|
||||
string += u'XCB = {0}'.format(xcb.UserString)
|
||||
form.output.setHtml(string)
|
||||
|
||||
def save(self):
|
||||
|
@ -363,10 +340,8 @@ class TaskPanel:
|
|||
form.trim = self.widget(QtGui.QLineEdit, "Trim")
|
||||
form.num = self.widget(QtGui.QSpinBox, "Num")
|
||||
|
||||
draft = Units.Quantity(Locale.fromString(
|
||||
form.draft.text())).getValueAs('m').Value
|
||||
trim = Units.Quantity(Locale.fromString(
|
||||
form.trim.text())).getValueAs('deg').Value
|
||||
draft = Units.parseQuantity(Locale.fromString(form.draft.text()))
|
||||
trim = Units.parseQuantity(Locale.fromString(form.trim.text()))
|
||||
num = form.num.value()
|
||||
|
||||
props = self.ship.PropertiesList
|
||||
|
@ -385,7 +360,7 @@ class TaskPanel:
|
|||
"AreaCurveDraft",
|
||||
"Ship",
|
||||
tooltip)
|
||||
self.ship.AreaCurveDraft = '{} m'.format(draft)
|
||||
self.ship.AreaCurveDraft = draft
|
||||
try:
|
||||
props.index("AreaCurveTrim")
|
||||
except ValueError:
|
||||
|
@ -401,7 +376,7 @@ class TaskPanel:
|
|||
"AreaCurveTrim",
|
||||
"Ship",
|
||||
tooltip)
|
||||
self.ship.AreaCurveTrim = '{} deg'.format(trim)
|
||||
self.ship.AreaCurveTrim = trim
|
||||
try:
|
||||
props.index("AreaCurveNum")
|
||||
except ValueError:
|
||||
|
@ -426,4 +401,4 @@ def createTask():
|
|||
if panel.setupUi():
|
||||
Gui.Control.closeDialog(panel)
|
||||
return None
|
||||
return panel
|
||||
return panel
|
|
@ -121,8 +121,12 @@ def solve_point(W, COG, TW, VOLS, ship, tanks, roll, var_trim=True):
|
|||
|
||||
for i in range(MAX_EQUILIBRIUM_ITERS):
|
||||
# Get the displacement, and the bouyance application point
|
||||
disp, B, Cb = Hydrostatics.displacement(ship, draft, roll, trim)
|
||||
disp *= 1000.0 * G
|
||||
disp, B, _ = Hydrostatics.displacement(ship,
|
||||
draft * Units.Metre,
|
||||
roll * Units.Degree,
|
||||
trim * Units.Degree)
|
||||
disp = disp.getValueAs("kg").Value * G
|
||||
B.multiply(1.0 / Units.Metre.Value)
|
||||
# Add the tanks effect on the center of gravity
|
||||
cog = Vector(COG.x * W, COG.y * W, COG.z * W)
|
||||
for i,t in enumerate(tanks):
|
||||
|
|
|
@ -84,11 +84,11 @@ class Plot(object):
|
|||
t1cm = []
|
||||
xcb = []
|
||||
for i in range(len(self.points)):
|
||||
disp.append(self.points[i].disp)
|
||||
draft.append(self.points[i].draft)
|
||||
warea.append(self.points[i].wet)
|
||||
t1cm.append(self.points[i].mom)
|
||||
xcb.append(self.points[i].xcb)
|
||||
disp.append(self.points[i].disp.getValueAs("kg").Value / 1000.0)
|
||||
draft.append(self.points[i].draft.getValueAs("m").Value)
|
||||
warea.append(self.points[i].wet.getValueAs("m^2").Value)
|
||||
t1cm.append(self.points[i].mom.getValueAs("kg*m").Value / 1000.0)
|
||||
xcb.append(self.points[i].xcb.getValueAs("m").Value)
|
||||
|
||||
axes = Plot.axesList()
|
||||
for ax in axes:
|
||||
|
@ -166,11 +166,11 @@ class Plot(object):
|
|||
kbt = []
|
||||
bmt = []
|
||||
for i in range(len(self.points)):
|
||||
disp.append(self.points[i].disp)
|
||||
draft.append(self.points[i].draft)
|
||||
farea.append(self.points[i].farea)
|
||||
kbt.append(self.points[i].KBt)
|
||||
bmt.append(self.points[i].BMt)
|
||||
disp.append(self.points[i].disp.getValueAs("kg").Value / 1000.0)
|
||||
draft.append(self.points[i].draft.getValueAs("m").Value)
|
||||
farea.append(self.points[i].farea.getValueAs("m^2").Value)
|
||||
kbt.append(self.points[i].KBt.getValueAs("m").Value)
|
||||
bmt.append(self.points[i].BMt.getValueAs("m").Value)
|
||||
|
||||
axes = Plot.axesList()
|
||||
for ax in axes:
|
||||
|
@ -248,8 +248,8 @@ class Plot(object):
|
|||
cf = []
|
||||
cm = []
|
||||
for i in range(len(self.points)):
|
||||
disp.append(self.points[i].disp)
|
||||
draft.append(self.points[i].draft)
|
||||
disp.append(self.points[i].disp.getValueAs("kg").Value / 1000.0)
|
||||
draft.append(self.points[i].draft.getValueAs("m").Value)
|
||||
cb.append(self.points[i].Cb)
|
||||
cf.append(self.points[i].Cf)
|
||||
cm.append(self.points[i].Cm)
|
||||
|
@ -322,17 +322,28 @@ class Plot(object):
|
|||
# Print the data
|
||||
for i in range(len(self.points)):
|
||||
point = self.points[i]
|
||||
s.set("A{}".format(i + 2), str(point.disp))
|
||||
s.set("B{}".format(i + 2), str(point.draft))
|
||||
s.set("C{}".format(i + 2), str(point.wet))
|
||||
s.set("D{}".format(i + 2), str(point.mom))
|
||||
s.set("E{}".format(i + 2), str(point.farea))
|
||||
s.set("F{}".format(i + 2), str(point.xcb))
|
||||
s.set("G{}".format(i + 2), str(point.KBt))
|
||||
s.set("H{}".format(i + 2), str(point.BMt))
|
||||
s.set("I{}".format(i + 2), str(point.Cb))
|
||||
s.set("J{}".format(i + 2), str(point.Cf))
|
||||
s.set("K{}".format(i + 2), str(point.Cm))
|
||||
s.set("A{}".format(i + 2),
|
||||
str(point.disp.getValueAs("kg").Value / 1000.0))
|
||||
s.set("B{}".format(i + 2),
|
||||
str(point.draft.getValueAs("m").Value))
|
||||
s.set("C{}".format(i + 2),
|
||||
str(point.wet.getValueAs("m^2").Value))
|
||||
s.set("D{}".format(i + 2),
|
||||
str(point.mom.getValueAs("kg*m").Value / 1000.0))
|
||||
s.set("E{}".format(i + 2),
|
||||
str(point.farea.getValueAs("m^2").Value))
|
||||
s.set("F{}".format(i + 2),
|
||||
str(point.xcb.getValueAs("m").Value))
|
||||
s.set("G{}".format(i + 2),
|
||||
str(point.KBt.getValueAs("m").Value))
|
||||
s.set("H{}".format(i + 2),
|
||||
str(point.BMt.getValueAs("m").Value))
|
||||
s.set("I{}".format(i + 2),
|
||||
str(point.Cb))
|
||||
s.set("J{}".format(i + 2),
|
||||
str(point.Cf))
|
||||
s.set("K{}".format(i + 2),
|
||||
str(point.Cm))
|
||||
|
||||
# Recompute
|
||||
FreeCAD.activeDocument().recompute()
|
|
@ -57,12 +57,9 @@ class TaskPanel:
|
|||
form.maxDraft = self.widget(QtGui.QLineEdit, "MaxDraft")
|
||||
form.nDraft = self.widget(QtGui.QSpinBox, "NDraft")
|
||||
|
||||
trim = Units.Quantity(Locale.fromString(
|
||||
form.trim.text())).getValueAs('deg').Value
|
||||
min_draft = Units.Quantity(Locale.fromString(
|
||||
form.minDraft.text())).getValueAs('m').Value
|
||||
max_draft = Units.Quantity(Locale.fromString(
|
||||
form.maxDraft.text())).getValueAs('m').Value
|
||||
trim = Units.parseQuantity(Locale.fromString(form.trim.text()))
|
||||
min_draft = Units.parseQuantity(Locale.fromString(form.minDraft.text()))
|
||||
max_draft = Units.parseQuantity(Locale.fromString(form.maxDraft.text()))
|
||||
n_draft = form.nDraft.value()
|
||||
|
||||
draft = min_draft
|
||||
|
@ -72,7 +69,6 @@ class TaskPanel:
|
|||
draft = draft + dDraft
|
||||
drafts.append(draft)
|
||||
|
||||
# Compute data
|
||||
# Get external faces
|
||||
self.loop = QtCore.QEventLoop()
|
||||
self.timer = QtCore.QTimer()
|
||||
|
@ -94,6 +90,7 @@ class TaskPanel:
|
|||
App.Console.PrintError(msg + '\n')
|
||||
return False
|
||||
faces = Part.makeShell(faces)
|
||||
|
||||
# Get the hydrostatics
|
||||
msg = QtGui.QApplication.translate(
|
||||
"ship_console",
|
||||
|
|
|
@ -34,7 +34,7 @@ from shipUtils import Math
|
|||
import shipUtils.Units as USys
|
||||
|
||||
|
||||
DENS = 1.025 # [tons/m3], salt water
|
||||
DENS = Units.parseQuantity("1025 kg/m^3") # Salt water
|
||||
COMMON_BOOLEAN_ITERATIONS = 10
|
||||
|
||||
|
||||
|
@ -49,9 +49,11 @@ def placeShipShape(shape, draft, roll, trim):
|
|||
roll -- Roll angle
|
||||
trim -- Trim angle
|
||||
|
||||
Returned value:
|
||||
The same transformed input shape. Just for debugging purposes, you can
|
||||
discard it.
|
||||
Returned values:
|
||||
shape -- The same transformed input shape. Just for debugging purposes, you
|
||||
can discard it.
|
||||
base_z -- The new base z coordinate (after applying the roll angle). Useful
|
||||
if you want to revert back the transformation
|
||||
"""
|
||||
# Roll the ship. In order to can deal with large roll angles, we are
|
||||
# proceeding as follows:
|
||||
|
@ -66,16 +68,21 @@ def placeShipShape(shape, draft, roll, trim):
|
|||
shape.translate(Vector(draft * math.sin(math.radians(trim)), 0.0, 0.0))
|
||||
shape.translate(Vector(0.0, 0.0, -draft))
|
||||
|
||||
return shape
|
||||
return shape, base_z
|
||||
|
||||
|
||||
def getUnderwaterSide(shape):
|
||||
def getUnderwaterSide(shape, force=True):
|
||||
"""Get the underwater shape, simply cropping the provided shape by the z=0
|
||||
free surface plane.
|
||||
|
||||
Position arguments:
|
||||
shape -- Solid shape to be cropped
|
||||
|
||||
Keyword arguments:
|
||||
force -- True if in case the common boolean operation fails, i.e. returns
|
||||
no solids, the tool should retry it slightly moving the free surface. False
|
||||
otherwise. (True by default)
|
||||
|
||||
Returned value:
|
||||
Cropped shape. It is not modifying the input shape
|
||||
"""
|
||||
|
@ -109,7 +116,7 @@ def getUnderwaterSide(shape):
|
|||
"UnderwaterSideHelper")
|
||||
common.Shapes = [orig, box]
|
||||
App.ActiveDocument.recompute()
|
||||
if len(common.Shape.Solids) == 0:
|
||||
if force and len(common.Shape.Solids) == 0:
|
||||
# The common operation is failing, let's try moving a bit the free
|
||||
# surface
|
||||
msg = QtGui.QApplication.translate(
|
||||
|
@ -139,7 +146,7 @@ def getUnderwaterSide(shape):
|
|||
def areas(ship, n, draft=None,
|
||||
roll=Units.parseQuantity("0 deg"),
|
||||
trim=Units.parseQuantity("0 deg")):
|
||||
""" Compute the ship transversal areas
|
||||
"""Compute the ship transversal areas
|
||||
|
||||
Position arguments:
|
||||
ship -- Ship object (see createShip)
|
||||
|
@ -161,11 +168,8 @@ def areas(ship, n, draft=None,
|
|||
if draft is None:
|
||||
draft = ship.Draft
|
||||
|
||||
# Manipulate a copy of the ship shape
|
||||
shape = getUnderwaterSide(placeShipShape(ship.Shape.copy(),
|
||||
draft,
|
||||
roll,
|
||||
trim))
|
||||
shape, _ = placeShipShape(ship.Shape.copy(), draft, roll, trim)
|
||||
shape = getUnderwaterSide(shape)
|
||||
|
||||
# Sections distance computation
|
||||
bbox = shape.BoundBox
|
||||
|
@ -191,6 +195,12 @@ def areas(ship, n, draft=None,
|
|||
try:
|
||||
f = Part.Face(shape.slice(Vector(1,0,0), x))
|
||||
except Part.OCCError:
|
||||
msg = QtGui.QApplication.translate(
|
||||
"ship_console",
|
||||
"Part.OCCError: Transversal area computation failed",
|
||||
None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
App.Console.PrintError(msg + '\n')
|
||||
areas.append((Units.Quantity(x, Units.Length),
|
||||
Units.Quantity(0.0, Units.Area)))
|
||||
continue
|
||||
|
@ -204,397 +214,328 @@ def areas(ship, n, draft=None,
|
|||
return areas
|
||||
|
||||
|
||||
def displacement(ship, draft, roll=0.0, trim=0.0, yaw=0.0):
|
||||
""" Compute the ship displacement.
|
||||
@param ship Ship instance.
|
||||
@param draft Ship draft.
|
||||
@param roll Ship roll angle.
|
||||
@param trim Ship trim angle.
|
||||
@param yaw Ship yaw angle. Ussually you don't want to use this
|
||||
value.
|
||||
@return [disp, B, Cb], \n
|
||||
- disp = Ship displacement [ton].
|
||||
- B = Bouyance center [m].
|
||||
- Cb = Block coefficient.
|
||||
@note Bouyance center will returned as a FreeCAD.Vector instance.
|
||||
@note Returned Bouyance center is in the non modified ship coordinates
|
||||
def displacement(ship, draft=None,
|
||||
roll=Units.parseQuantity("0 deg"),
|
||||
trim=Units.parseQuantity("0 deg")):
|
||||
"""Compute the ship displacement
|
||||
|
||||
Position arguments:
|
||||
ship -- Ship object (see createShip)
|
||||
|
||||
Keyword arguments:
|
||||
draft -- Ship draft (Design ship draft by default)
|
||||
roll -- Roll angle (0 degrees by default)
|
||||
trim -- Trim angle (0 degrees by default)
|
||||
|
||||
Returned values:
|
||||
disp -- The ship displacement (a density of the water of 1025 kg/m^3 is
|
||||
assumed)
|
||||
B -- Bouyance application point, i.e. Center of mass of the underwater side
|
||||
Cb -- Block coefficient
|
||||
|
||||
The Bouyance center is refered to the original ship position.
|
||||
"""
|
||||
# We will take a duplicate of ship shape in order to conviniently
|
||||
# manipulate it
|
||||
shape = ship.Shape.copy()
|
||||
_draft = draft * Units.Metre.Value
|
||||
# Roll the ship. In order to can deal with large roll angles, we are
|
||||
# proceeding as follows:
|
||||
# 1.- Applying the roll with respect the base line
|
||||
# 2.- Recentering the ship in the y direction
|
||||
# 3.- Readjusting the base line
|
||||
shape.rotate(Vector(0.0, 0.0, 0.0), Vector(1.0, 0.0, 0.0), roll)
|
||||
base_z = shape.BoundBox.ZMin
|
||||
shape.translate(Vector(0.0,
|
||||
_draft * math.sin(math.radians(roll)),
|
||||
-base_z))
|
||||
# Trim and yaw the ship. In this case we only need to correct the x
|
||||
# direction
|
||||
shape.rotate(Vector(0.0, 0.0, 0.0), Vector(0.0, -1.0, 0.0), trim)
|
||||
shape.translate(Vector(_draft * math.sin(math.radians(trim)), 0.0, 0.0))
|
||||
shape.rotate(Vector(0.0, 0.0, 0.0), Vector(0.0, 0.0, 1.0), yaw)
|
||||
shape.translate(Vector(0.0, 0.0, -_draft))
|
||||
Part.show(shape)
|
||||
ship_shape = App.ActiveDocument.Objects[-1]
|
||||
if draft is None:
|
||||
draft = ship.Draft
|
||||
|
||||
bbox = shape.BoundBox
|
||||
xmin = bbox.XMin
|
||||
xmax = bbox.XMax
|
||||
ymin = bbox.YMin
|
||||
ymax = bbox.YMax
|
||||
zmin = bbox.ZMin
|
||||
zmax = bbox.ZMax
|
||||
# Create the "sea" box to intersect the ship
|
||||
L = xmax - xmin
|
||||
B = ymax - ymin
|
||||
H = zmax - zmin
|
||||
|
||||
box = App.ActiveDocument.addObject("Part::Box","Box")
|
||||
length_format = USys.getLengthFormat()
|
||||
box.Placement = Placement(Vector(xmin - L, ymin - B, zmin - H),
|
||||
Rotation(App.Vector(0,0,1),0))
|
||||
box.Length = length_format.format(3.0 * L)
|
||||
box.Width = length_format.format(3.0 * B)
|
||||
box.Height = length_format.format(- zmin + H)
|
||||
|
||||
App.ActiveDocument.recompute()
|
||||
common = App.activeDocument().addObject("Part::MultiCommon",
|
||||
"DisplacementHelper")
|
||||
common.Shapes = [ship_shape, box]
|
||||
App.ActiveDocument.recompute()
|
||||
if len(common.Shape.Solids) == 0:
|
||||
# The common operation is failing, let's try moving a bit the free
|
||||
# surface
|
||||
msg = QtGui.QApplication.translate(
|
||||
"ship_console",
|
||||
"Boolean operation failed. The tool is retrying that slightly"
|
||||
" moving the free surface position",
|
||||
None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
App.Console.PrintWarning(msg + '\n')
|
||||
random_bounds = 0.01 * H
|
||||
i = 0
|
||||
while len(common.Shape.Solids) == 0 and i < COMMON_BOOLEAN_ITERATIONS:
|
||||
i += 1
|
||||
box.Height = length_format.format(
|
||||
- zmin + H + random.uniform(-random_bounds, random_bounds))
|
||||
App.ActiveDocument.recompute()
|
||||
shape, base_z = placeShipShape(ship.Shape.copy(), draft, roll, trim)
|
||||
shape = getUnderwaterSide(shape)
|
||||
|
||||
vol = 0.0
|
||||
cog = Vector()
|
||||
if len(common.Shape.Solids) > 0:
|
||||
for solid in common.Shape.Solids:
|
||||
vol += solid.Volume / Units.Metre.Value**3
|
||||
if len(shape.Solids) > 0:
|
||||
for solid in shape.Solids:
|
||||
vol += solid.Volume
|
||||
sCoG = solid.CenterOfMass
|
||||
cog.x = cog.x + sCoG.x * solid.Volume / Units.Metre.Value**4
|
||||
cog.y = cog.y + sCoG.y * solid.Volume / Units.Metre.Value**4
|
||||
cog.z = cog.z + sCoG.z * solid.Volume / Units.Metre.Value**4
|
||||
cog.x = cog.x + sCoG.x * solid.Volume
|
||||
cog.y = cog.y + sCoG.y * solid.Volume
|
||||
cog.z = cog.z + sCoG.z * solid.Volume
|
||||
cog.x = cog.x / vol
|
||||
cog.y = cog.y / vol
|
||||
cog.z = cog.z / vol
|
||||
Vol = L * B * abs(bbox.ZMin) / Units.Metre.Value**3
|
||||
|
||||
App.ActiveDocument.removeObject(common.Name)
|
||||
App.ActiveDocument.removeObject(ship_shape.Name)
|
||||
App.ActiveDocument.removeObject(box.Name)
|
||||
App.ActiveDocument.recompute()
|
||||
bbox = shape.BoundBox
|
||||
Vol = (bbox.XMax - bbox.XMin) * (bbox.YMax - bbox.YMin) * abs(bbox.ZMin)
|
||||
|
||||
# Undo the transformations
|
||||
# Undo the transformations on the bouyance point
|
||||
B = Part.Point(Vector(cog.x, cog.y, cog.z))
|
||||
m = Matrix()
|
||||
m.move(Vector(0.0, 0.0, draft))
|
||||
m.rotateZ(-math.radians(yaw))
|
||||
m.move(Vector(-draft * math.sin(math.radians(trim)), 0.0, 0.0))
|
||||
m.rotateY(math.radians(trim))
|
||||
m.move(Vector(0.0,
|
||||
-draft * math.sin(math.radians(roll)),
|
||||
base_z / Units.Metre.Value))
|
||||
base_z))
|
||||
m.rotateX(-math.radians(roll))
|
||||
B.transform(m)
|
||||
|
||||
# Return the computed data
|
||||
return [DENS*vol, Vector(B.X, B.Y, B.Z), vol/Vol]
|
||||
|
||||
|
||||
def wettedArea(shape, draft, trim):
|
||||
""" Calculate wetted ship area.
|
||||
@param shape Ship external faces instance.
|
||||
@param draft Draft.
|
||||
@param trim Trim in degrees.
|
||||
@return Wetted ship area.
|
||||
"""
|
||||
area = 0.0
|
||||
nObjects = 0
|
||||
|
||||
shape = shape.copy()
|
||||
_draft = draft * Units.Metre.Value
|
||||
shape.rotate(Vector(0.0, 0.0, 0.0), Vector(0.0, -1.0, 0.0), trim)
|
||||
shape.translate(Vector(0.0, 0.0, -_draft))
|
||||
|
||||
bbox = shape.BoundBox
|
||||
xmin = bbox.XMin
|
||||
xmax = bbox.XMax
|
||||
ymin = bbox.YMin
|
||||
ymax = bbox.YMax
|
||||
|
||||
# Create the "sea" box
|
||||
L = xmax - xmin
|
||||
B = ymax - ymin
|
||||
p = Vector(xmin - L, ymin - B, bbox.ZMin - 1.0)
|
||||
try:
|
||||
box = Part.makeBox(3.0 * L, 3.0 * B, - bbox.ZMin + 1.0, p)
|
||||
except Part.OCCError:
|
||||
return 0.0
|
||||
|
||||
for f in shape.Faces:
|
||||
try:
|
||||
common = box.common(f)
|
||||
except Part.OCCError:
|
||||
continue
|
||||
area = area + common.Area
|
||||
return area / Units.Metre.Value**2
|
||||
cb = vol / Vol
|
||||
except ZeroDivisionError:
|
||||
msg = QtGui.QApplication.translate(
|
||||
"ship_console",
|
||||
"ZeroDivisionError: Null volume found during the displacement"
|
||||
" computation!",
|
||||
None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
App.Console.PrintError(msg + '\n')
|
||||
cb = 0.0
|
||||
|
||||
|
||||
def moment(ship, draft, trim, disp, xcb):
|
||||
""" Calculate triming 1cm ship moment.
|
||||
@param ship Selected ship instance
|
||||
@param draft Draft.
|
||||
@param trim Trim in degrees.
|
||||
@param disp Displacement at selected draft and trim.
|
||||
@param xcb Bouyance center at selected draft and trim.
|
||||
@return Moment to trim ship 1cm (ton m).
|
||||
@note Moment is positive when produce positive trim.
|
||||
# Return the computed data
|
||||
return (DENS * Units.Quantity(vol, Units.Volume),
|
||||
Vector(B.X, B.Y, B.Z),
|
||||
cb)
|
||||
|
||||
|
||||
def wettedArea(shape, draft, roll=Units.parseQuantity("0 deg"),
|
||||
trim=Units.parseQuantity("0 deg")):
|
||||
"""Compute the ship wetted area
|
||||
|
||||
Position arguments:
|
||||
shape -- External faces of the ship hull
|
||||
draft -- Ship draft
|
||||
|
||||
Keyword arguments:
|
||||
roll -- Roll angle (0 degrees by default)
|
||||
trim -- Trim angle (0 degrees by default)
|
||||
|
||||
Returned value:
|
||||
The wetted area, i.e. The underwater side area
|
||||
"""
|
||||
shape, _ = placeShipShape(shape.copy(), draft, roll, trim)
|
||||
shape = getUnderwaterSide(shape, force=False)
|
||||
|
||||
area = 0.0
|
||||
for f in shape.Faces:
|
||||
area = area + f.Area
|
||||
return Units.Quantity(area, Units.Area)
|
||||
|
||||
|
||||
def moment(ship, draft=None,
|
||||
roll=Units.parseQuantity("0 deg"),
|
||||
trim=Units.parseQuantity("0 deg")):
|
||||
"""Compute the moment required to trim the ship 1cm
|
||||
|
||||
Position arguments:
|
||||
ship -- Ship object (see createShip)
|
||||
|
||||
Keyword arguments:
|
||||
draft -- Ship draft (Design ship draft by default)
|
||||
roll -- Roll angle (0 degrees by default)
|
||||
trim -- Trim angle (0 degrees by default)
|
||||
|
||||
Returned value:
|
||||
Moment required to trim the ship 1cm. Such moment is positive if it cause a
|
||||
positive trim angle. The moment is expressed as a mass by a distance, not as
|
||||
a force by a distance
|
||||
"""
|
||||
disp_orig, B_orig, _ = displacement(ship, draft, roll, trim)
|
||||
xcb_orig = Units.Quantity(B_orig.x, Units.Length)
|
||||
|
||||
factor = 10.0
|
||||
angle = factor * math.degrees(math.atan2(
|
||||
0.01,
|
||||
0.5 * ship.Length.getValueAs('m').Value))
|
||||
newTrim = trim + angle
|
||||
data = displacement(ship, draft, 0.0, newTrim, 0.0)
|
||||
mom0 = -disp * xcb
|
||||
mom1 = -data[0] * data[1].x
|
||||
x = 0.5 * ship.Length.getValueAs('cm').Value
|
||||
y = 1.0
|
||||
angle = math.atan2(y, x) * Units.Radian
|
||||
trim_new = trim + factor * angle
|
||||
disp_new, B_new, _ = displacement(ship, draft, roll, trim_new)
|
||||
xcb_new = Units.Quantity(B_new.x, Units.Length)
|
||||
|
||||
mom0 = -disp_orig * xcb_orig
|
||||
mom1 = -disp_new * xcb_new
|
||||
return (mom1 - mom0) / factor
|
||||
|
||||
|
||||
def FloatingArea(ship, draft, trim):
|
||||
""" Calculate ship floating area.
|
||||
@param ship Selected ship instance
|
||||
@param draft Draft.
|
||||
@param trim Trim in degrees.
|
||||
@return Ship floating area, and floating coefficient.
|
||||
"""
|
||||
area = 0.0
|
||||
cf = 0.0
|
||||
maxX = 0.0
|
||||
minX = 0.0
|
||||
maxY = 0.0
|
||||
minY = 0.0
|
||||
def floatingArea(ship, draft=None,
|
||||
roll=Units.parseQuantity("0 deg"),
|
||||
trim=Units.parseQuantity("0 deg")):
|
||||
"""Compute the ship floating area
|
||||
|
||||
shape = ship.Shape.copy()
|
||||
_draft = draft * Units.Metre.Value
|
||||
shape.rotate(Vector(0.0, 0.0, 0.0), Vector(0.0, -1.0, 0.0), trim)
|
||||
shape.translate(Vector(0.0, 0.0, -_draft))
|
||||
Position arguments:
|
||||
ship -- Ship object (see createShip)
|
||||
|
||||
Keyword arguments:
|
||||
draft -- Ship draft (Design ship draft by default)
|
||||
roll -- Roll angle (0 degrees by default)
|
||||
trim -- Trim angle (0 degrees by default)
|
||||
|
||||
Returned values:
|
||||
area -- Ship floating area
|
||||
cf -- Floating area coefficient
|
||||
"""
|
||||
if draft is None:
|
||||
draft = ship.Draft
|
||||
|
||||
# We wanna intersect the whole ship with the free surface, so in this case
|
||||
# we must not use the underwater side (or the tool will fail)
|
||||
shape, _ = placeShipShape(ship.Shape.copy(), draft, roll, trim)
|
||||
|
||||
try:
|
||||
f = Part.Face(shape.slice(Vector(0,0,1), 0.0))
|
||||
area = Units.Quantity(f.Area, Units.Area)
|
||||
except Part.OCCError:
|
||||
msg = QtGui.QApplication.translate(
|
||||
"ship_console",
|
||||
"Part.OCCError: Floating area cannot be computed",
|
||||
None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
App.Console.PrintError(msg + '\n')
|
||||
area = Units.Quantity(0.0, Units.Area)
|
||||
|
||||
bbox = shape.BoundBox
|
||||
xmin = bbox.XMin
|
||||
xmax = bbox.XMax
|
||||
ymin = bbox.YMin
|
||||
ymax = bbox.YMax
|
||||
|
||||
# Create the "sea" box
|
||||
L = xmax - xmin
|
||||
B = ymax - ymin
|
||||
p = Vector(xmin - L, ymin - B, bbox.ZMin - 1.0)
|
||||
Area = (bbox.XMax - bbox.XMin) * (bbox.YMax - bbox.YMin)
|
||||
try:
|
||||
box = Part.makeBox(3.0 * L, 3.0 * B, - bbox.ZMin + 1.0, p)
|
||||
except Part.OCCError:
|
||||
return [area, cf]
|
||||
cf = area.Value / Area
|
||||
except ZeroDivisionError:
|
||||
msg = QtGui.QApplication.translate(
|
||||
"ship_console",
|
||||
"ZeroDivisionError: Null area found during the floating area"
|
||||
" computation!",
|
||||
None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
App.Console.PrintError(msg + '\n')
|
||||
cf = 0.0
|
||||
|
||||
maxX = bbox.XMin / Units.Metre.Value
|
||||
minX = bbox.XMax / Units.Metre.Value
|
||||
maxY = bbox.YMin / Units.Metre.Value
|
||||
minY = bbox.YMax / Units.Metre.Value
|
||||
for s in shape.Solids:
|
||||
try:
|
||||
common = box.common(s)
|
||||
except Part.OCCError:
|
||||
continue
|
||||
if common.Volume == 0.0:
|
||||
continue
|
||||
# Recompute the object adding it to the scene. OpenCASCADE must be
|
||||
# performing an internal tesellation doing that
|
||||
try:
|
||||
Part.show(common)
|
||||
except (TypeError,Part.OCCError):
|
||||
continue
|
||||
# Divide the solid by faces and filter the well placed ones
|
||||
faces = common.Faces
|
||||
for f in faces:
|
||||
faceBounds = f.BoundBox
|
||||
# Orientation filter
|
||||
if faceBounds.ZMax - faceBounds.ZMin > 0.00001:
|
||||
continue
|
||||
# Position filter
|
||||
if abs(faceBounds.ZMax) > 0.00001:
|
||||
continue
|
||||
|
||||
area = area + f.Area / Units.Metre.Value**2
|
||||
maxX = max(maxX, faceBounds.XMax / Units.Metre.Value)
|
||||
minX = min(minX, faceBounds.XMin / Units.Metre.Value)
|
||||
maxY = max(maxY, faceBounds.YMax / Units.Metre.Value)
|
||||
minY = min(minY, faceBounds.YMin / Units.Metre.Value)
|
||||
App.ActiveDocument.removeObject(App.ActiveDocument.Objects[-1].Name)
|
||||
|
||||
dx = maxX - minX
|
||||
dy = maxY - minY
|
||||
if dx*dy > 0.0:
|
||||
cf = area / (dx * dy)
|
||||
return [area, cf]
|
||||
return area, cf
|
||||
|
||||
|
||||
def BMT(ship, draft, trim=0.0):
|
||||
""" Calculate ship Bouyance center transversal distance.
|
||||
@param ship Ship instance.
|
||||
@param draft Ship draft.
|
||||
@param trim Ship trim angle.
|
||||
@return BM Bouyance to metacenter height [m].
|
||||
def BMT(ship, draft=None, trim=Units.parseQuantity("0 deg")):
|
||||
"""Calculate "ship Bouyance center" - "transversal metacenter" radius
|
||||
|
||||
Position arguments:
|
||||
ship -- Ship object (see createShip)
|
||||
|
||||
Keyword arguments:
|
||||
draft -- Ship draft (Design ship draft by default)
|
||||
trim -- Trim angle (0 degrees by default)
|
||||
|
||||
Returned value:
|
||||
BMT radius
|
||||
"""
|
||||
if draft is None:
|
||||
draft = ship.Draft
|
||||
|
||||
roll = Units.parseQuantity("0 deg")
|
||||
_, B0, _ = displacement(ship, draft, roll, trim)
|
||||
|
||||
|
||||
nRoll = 2
|
||||
maxRoll = 7.0
|
||||
B0 = displacement(ship, draft, 0.0, trim, 0.0)[1]
|
||||
maxRoll = Units.parseQuantity("7 deg")
|
||||
|
||||
BM = 0.0
|
||||
for i in range(nRoll):
|
||||
roll = (maxRoll / nRoll)*(i + 1)
|
||||
B1 = displacement(ship, draft, roll, trim, 0.0)[1]
|
||||
roll = (maxRoll / nRoll) * (i + 1)
|
||||
_, B1, _ = displacement(ship, draft, roll, trim)
|
||||
# * M
|
||||
# / \
|
||||
# / \ BM ==|> BM = (BB/2) / sin(alpha/2)
|
||||
# / \
|
||||
# *-------*
|
||||
# BB
|
||||
BB = [B1.y - B0.y, B1.z - B0.z]
|
||||
BB = math.sqrt(BB[0] * BB[0] + BB[1] * BB[1])
|
||||
# nRoll is acting as the weight function
|
||||
BM = BM + 0.5 * BB / math.sin(math.radians(0.5 * roll)) / nRoll
|
||||
return BM
|
||||
BB = B1 - B0
|
||||
BB.x = 0.0
|
||||
# nRoll is actually representing the weight function
|
||||
BM += 0.5 * BB.Length / math.sin(math.radians(0.5 * roll)) / nRoll
|
||||
return Units.Quantity(BM, Units.Length)
|
||||
|
||||
|
||||
def mainFrameCoeff(ship, draft):
|
||||
""" Calculate main frame coefficient.
|
||||
@param ship Selected ship instance
|
||||
@param draft Draft.
|
||||
@return Main frame coefficient
|
||||
def mainFrameCoeff(ship, draft=None):
|
||||
"""Compute the main frame coefficient
|
||||
|
||||
Position arguments:
|
||||
ship -- Ship object (see createShip)
|
||||
|
||||
Keyword arguments:
|
||||
draft -- Ship draft (Design ship draft by default)
|
||||
|
||||
Returned value:
|
||||
Ship main frame area coefficient
|
||||
"""
|
||||
cm = 0.0
|
||||
maxY = 0.0
|
||||
minY = 0.0
|
||||
if draft is None:
|
||||
draft = ship.Draft
|
||||
|
||||
shape = ship.Shape.copy()
|
||||
shape.translate(Vector(0.0, 0.0, -draft * Units.Metre.Value))
|
||||
x = 0.0
|
||||
area = 0.0
|
||||
shape, _ = placeShipShape(ship.Shape.copy(), draft,
|
||||
Units.parseQuantity("0 deg"),
|
||||
Units.parseQuantity("0 deg"))
|
||||
shape = getUnderwaterSide(shape)
|
||||
|
||||
try:
|
||||
f = Part.Face(shape.slice(Vector(1,0,0), 0.0))
|
||||
area = f.Area
|
||||
except Part.OCCError:
|
||||
msg = QtGui.QApplication.translate(
|
||||
"ship_console",
|
||||
"Part.OCCError: Main frame area cannot be computed",
|
||||
None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
App.Console.PrintError(msg + '\n')
|
||||
area = 0.0
|
||||
|
||||
bbox = shape.BoundBox
|
||||
xmin = bbox.XMin
|
||||
xmax = bbox.XMax
|
||||
ymin = bbox.YMin
|
||||
ymax = bbox.YMax
|
||||
Area = (bbox.YMax - bbox.YMin) * (bbox.ZMax - bbox.ZMin)
|
||||
|
||||
# Create the "sea" box
|
||||
L = xmax - xmin
|
||||
B = ymax - ymin
|
||||
p = Vector(xmin - L, ymin - B, bbox.ZMin - 1.0)
|
||||
try:
|
||||
box = Part.makeBox(1.5 * L, 3.0 * B, - bbox.ZMin + 1.0, p)
|
||||
except Part.OCCError:
|
||||
return cm
|
||||
cm = area / Area
|
||||
except ZeroDivisionError:
|
||||
msg = QtGui.QApplication.translate(
|
||||
"ship_console",
|
||||
"ZeroDivisionError: Null area found during the main frame area"
|
||||
" coefficient computation!",
|
||||
None,
|
||||
QtGui.QApplication.UnicodeUTF8)
|
||||
App.Console.PrintError(msg + '\n')
|
||||
cm = 0.0
|
||||
|
||||
maxY = bbox.YMin / Units.Metre.Value
|
||||
minY = bbox.YMax / Units.Metre.Value
|
||||
for s in shape.Solids:
|
||||
try:
|
||||
common = box.common(s)
|
||||
except Part.OCCError:
|
||||
continue
|
||||
if common.Volume == 0.0:
|
||||
continue
|
||||
# Recompute the object adding it to the scene. OpenCASCADE must be
|
||||
# performing an internal tesellation doing that
|
||||
try:
|
||||
Part.show(common)
|
||||
except (TypeError,Part.OCCError):
|
||||
continue
|
||||
# Divide the solid by faces and filter the well placed ones
|
||||
faces = common.Faces
|
||||
for f in faces:
|
||||
faceBounds = f.BoundBox
|
||||
# Orientation filter
|
||||
if faceBounds.XMax - faceBounds.XMin > 0.00001:
|
||||
continue
|
||||
# Position filter
|
||||
if abs(faceBounds.XMax - x) > 0.00001:
|
||||
continue
|
||||
|
||||
area = area + f.Area / Units.Metre.Value**2
|
||||
maxY = max(maxY, faceBounds.YMax / Units.Metre.Value)
|
||||
minY = min(minY, faceBounds.YMin / Units.Metre.Value)
|
||||
App.ActiveDocument.removeObject(App.ActiveDocument.Objects[-1].Name)
|
||||
|
||||
dy = maxY - minY
|
||||
if dy * draft > 0.0:
|
||||
cm = area / (dy * draft)
|
||||
return cm
|
||||
|
||||
|
||||
class Point:
|
||||
""" Hydrostatics point, that conatins: \n
|
||||
draft Ship draft [m]. \n
|
||||
trim Ship trim [deg]. \n
|
||||
disp Ship displacement [ton]. \n
|
||||
xcb Bouyance center X coordinate [m].
|
||||
wet Wetted ship area [m2].
|
||||
mom Triming 1cm ship moment [ton m].
|
||||
farea Floating area [m2].
|
||||
KBt Transversal KB height [m].
|
||||
BMt Transversal BM height [m].
|
||||
Cb Block coefficient.
|
||||
Cf Floating coefficient.
|
||||
Cm Main frame coefficient.
|
||||
@note Moment is positive when produce positive trim.
|
||||
"""Hydrostatics point, that contains the following members:
|
||||
|
||||
draft -- Ship draft
|
||||
trim -- Ship trim
|
||||
disp -- Ship displacement
|
||||
xcb -- Bouyance center X coordinate
|
||||
wet -- Wetted ship area
|
||||
mom -- Triming 1cm ship moment
|
||||
farea -- Floating area
|
||||
KBt -- Transversal KB height
|
||||
BMt -- Transversal BM height
|
||||
Cb -- Block coefficient.
|
||||
Cf -- Floating coefficient.
|
||||
Cm -- Main frame coefficient.
|
||||
|
||||
The moment to trim the ship 1 cm is positive when is resulting in a positive
|
||||
trim angle.
|
||||
"""
|
||||
def __init__(self, ship, faces, draft, trim):
|
||||
""" Use all hydrostatics tools to define a hydrostatics
|
||||
point.
|
||||
@param ship Selected ship instance
|
||||
@param faces Ship external faces
|
||||
@param draft Draft.
|
||||
@param trim Trim in degrees.
|
||||
"""Compute all the hydrostatics.
|
||||
|
||||
Position argument:
|
||||
ship -- Ship instance
|
||||
faces -- Ship external faces
|
||||
draft -- Ship draft
|
||||
trim -- Trim angle
|
||||
"""
|
||||
# Hydrostatics computation
|
||||
dispData = displacement(ship, draft, 0.0, trim, 0.0)
|
||||
disp, B, cb = displacement(ship, draft=draft, trim=trim)
|
||||
if not faces:
|
||||
wet = 0.0
|
||||
else:
|
||||
wet = wettedArea(faces, draft, trim)
|
||||
mom = moment(ship, draft, trim, dispData[0], dispData[1].x)
|
||||
farea = FloatingArea(ship, draft, trim)
|
||||
bm = BMT(ship, draft, trim)
|
||||
cm = mainFrameCoeff(ship, draft)
|
||||
wet = wettedArea(faces, draft=draft, trim=trim)
|
||||
mom = moment(ship, draft=draft, trim=trim)
|
||||
farea, cf = floatingArea(ship, draft=draft, trim=trim)
|
||||
bm = BMT(ship, draft=draft, trim=trim)
|
||||
cm = mainFrameCoeff(ship, draft=draft)
|
||||
# Store final data
|
||||
self.draft = draft
|
||||
self.trim = trim
|
||||
self.disp = dispData[0]
|
||||
self.xcb = dispData[1].x
|
||||
self.disp = disp
|
||||
self.xcb = Units.Quantity(B.x, Units.Length)
|
||||
self.wet = wet
|
||||
self.farea = farea[0]
|
||||
self.farea = farea
|
||||
self.mom = mom
|
||||
self.KBt = dispData[1].z
|
||||
self.KBt = Units.Quantity(B.z, Units.Length)
|
||||
self.BMt = bm
|
||||
self.Cb = dispData[2]
|
||||
self.Cf = farea[1]
|
||||
self.Cm = cm
|
||||
self.Cb = cb
|
||||
self.Cf = cf
|
||||
self.Cm = cm
|
Loading…
Reference in New Issue
Block a user