Added the possibility of computing the transversal areas from the console interface

This commit is contained in:
Jose Luis Cercos Pita 2016-01-21 19:57:55 +01:00
parent 55c63f414d
commit e1aa844e95
3 changed files with 118 additions and 39 deletions

View File

@ -29,4 +29,5 @@ __url__ = "http://www.freecadweb.org"
__doc__="The Ships module provide a set of tools to make some specific Naval" \
" Architecture computations"
from shipCreateShip.Tools import createShip
from shipCreateShip.Tools import createShip
from shipHydrostatics.Tools import areas

View File

@ -51,28 +51,25 @@ class TaskPanel:
form.draft = self.widget(QtGui.QLineEdit, "Draft")
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()
data = Hydrostatics.displacement(self.ship,
draft,
draft.getValueAs("m").Value,
0.0,
trim)
trim.getValueAs("deg").Value)
disp = data[0]
xcb = data[1].x
data = Hydrostatics.areas(self.ship,
draft,
0.0,
trim,
0.0,
num)
num,
draft=draft,
trim=trim)
x = []
y = []
for i in range(0, len(data)):
x.append(data[i][0])
y.append(data[i][1])
x.append(data[i][0].getValueAs("m").Value)
y.append(data[i][1].getValueAs("m^2").Value)
PlotAux.Plot(x, y, disp, xcb, self.ship)
self.preview.clean()
return True

View File

@ -38,24 +38,102 @@ DENS = 1.025 # [tons/m3], salt water
COMMON_BOOLEAN_ITERATIONS = 10
def areas(ship, draft, roll=0.0, trim=0.0, yaw=0.0, n=30):
""" Compute the ship transversal areas.
@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.
@param n Number of sections to perform.
@return Transversal areas (every area value is composed by x
coordinate and computed area)
def getUnderwaterSide(shape):
""" Get the underwater shape, simply cropping the provided shape by the z=0
free surface plane.
Position arguments:
shape -- Solid shape to be cropped
Returned value:
Cropped shape. It is not modifying the input shape
"""
# Convert the shape into an active object
Part.show(shape)
orig = App.ActiveDocument.Objects[-1]
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",
"UnderwaterSideHelper")
common.Shapes = [orig, 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 when trying to get the underwater side."
" The tool is retrying such operation 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()
out = common.Shape
App.ActiveDocument.removeObject(common.Name)
App.ActiveDocument.removeObject(orig.Name)
App.ActiveDocument.removeObject(box.Name)
App.ActiveDocument.recompute()
return out
def areas(ship, n, draft=None,
roll=Units.parseQuantity("0 deg"),
trim=Units.parseQuantity("0 deg")):
""" Compute the ship transversal areas
Position arguments:
ship -- Ship object (see createShip)
n -- Number of points to compute
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:
List of sections, each section contains 2 values, the x longitudinal
coordinate, and the transversal area. If n < 2, an empty list will be
returned.
"""
if n < 2:
return []
# We will take a duplicate of ship shape in order to conviniently
if draft is None:
draft = ship.Draft
# We will take a duplicate of ship shape in order to conveniently
# 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
@ -63,26 +141,26 @@ def areas(ship, draft, roll=0.0, trim=0.0, yaw=0.0, n=30):
# 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))
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))
shape.translate(Vector(draft * math.sin(math.radians(trim)), 0.0, 0.0))
shape.translate(Vector(0.0, 0.0, -draft))
shape = getUnderwaterSide(shape)
# Sections distance computation
bbox = shape.BoundBox
xmin = bbox.XMin
xmax = bbox.XMax
ymin = bbox.YMin
ymax = bbox.YMax
dx = (xmax - xmin) / (n - 1.0)
# Since we are computing the sections in the total length (not in the
# length between perpendiculars), we can grant that the starting and
# ending sections have null area
areas = [[xmin / Units.Metre.Value, 0.0]]
areas = [(Units.Quantity(xmin, Units.Length),
Units.Quantity(0.0, Units.Area))]
# And since we just need to compute areas we will create boxes with its
# front face at the desired transversal area position, computing the
# common solid part, dividing it by faces, and getting only the desired
@ -96,12 +174,15 @@ def areas(ship, draft, roll=0.0, trim=0.0, yaw=0.0, n=30):
try:
f = Part.Face(shape.slice(Vector(1,0,0), x))
except Part.OCCError:
areas.append([x / Units.Metre.Value, 0.0])
areas.append((Units.Quantity(x, Units.Length),
Units.Quantity(0.0, Units.Area)))
continue
# It is a valid face, so we can add this area
areas.append([x / Units.Metre.Value, f.Area / Units.Metre.Value**2])
areas.append((Units.Quantity(x, Units.Length),
Units.Quantity(f.Area, Units.Area)))
# Last area is equal to zero (due to the total length usage)
areas.append([xmax / Units.Metre.Value, 0.0])
areas.append((Units.Quantity(xmax, Units.Length),
Units.Quantity(0.0, Units.Area)))
App.Console.PrintMessage("Done!\n")
return areas