Added some hydrostatics computation.

This commit is contained in:
Jose Luis Cercós pita 2012-02-17 13:41:50 +01:00
parent 6c870f2ebd
commit 87782c32cb
5 changed files with 396 additions and 2 deletions

View File

@ -77,6 +77,7 @@ SOURCE_GROUP("shipareascurve" FILES ${ShipAreasCurve_SRCS})
SET(ShipHydrostatics_SRCS
shipHydrostatics/__init__.py
shipHydrostatics/Plot.py
shipHydrostatics/TaskPanel.py
shipHydrostatics/TaskPanel.ui
shipHydrostatics/Tools.py

View File

@ -54,6 +54,7 @@ nobase_data_DATA = \
shipAreasCurve/TaskPanel.py \
shipAreasCurve/TaskPanel.ui \
shipHydrostatics/__init__.py \
shipHydrostatics/Plot.py \
shipHydrostatics/TaskPanel.py \
shipHydrostatics/TaskPanel.ui \
shipHydrostatics/Tools.py \

View File

@ -0,0 +1,194 @@
#***************************************************************************
#* *
#* Copyright (c) 2011, 2012 *
#* Jose Luis Cercos Pita <jlcercos@gmail.com> *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************
import os
# FreeCAD modules
import FreeCAD,FreeCADGui
from FreeCAD import Part, Base
from FreeCAD import Image, ImageGui
# FreeCADShip modules
from shipUtils import Paths, Translator
import Tools
header = """ #################################################################
##### #### ### #### ##### # # ### ####
# # # # # # # # # # # #
# ## #### #### # # # # # # # # # # #
#### # # # # # # # ##### # # ## ## ##### # ####
# # #### #### # # # # # # # # # #
# # # # # # # # # # # # # #
# # #### #### ### # # #### ##### # # ### #
#################################################################
"""
class Plot(object):
def __init__(self, ship, trim, drafts):
""" Constructor. performs plot and show it (Using pyxplot).
@param ship Selected ship instance
@param trim Trim in degrees.
@param drafts List of drafts to be performed.
"""
if self.createDirectory():
return
if self.saveData(ship, trim, drafts):
return
if self.saveLayout(trim):
return
if self.execute():
return
ImageGui.open(self.path + 'volume.png')
def createDirectory(self):
""" Create needed folder to write data and scripts.
@return True if error happens.
"""
self.path = FreeCAD.ConfigGet("UserAppData") + "ShipOutput/"
if not os.path.exists(self.path):
os.makedirs(self.path)
if not os.path.exists(self.path):
msg = Translator.translate("Can't create '" + self.path + "' folder.\n")
FreeCAD.Console.PrintError(msg)
return False
def saveData(self, ship, trim, drafts):
""" Write data file.
@param ship Selected ship instance
@param trim Trim in degrees.
@param drafts List of drafts to be performed.
@return True if error happens.
"""
# Open the file
filename = self.path + 'hydrostatics.dat'
try:
Output = open(filename, "w")
except IOError:
msg = Translator.translate("Can't write '" + filename + "' file.\n")
FreeCAD.Console.PrintError(msg)
return True
# Print header
Output.write(header)
Output.write(" #\n")
Output.write(" # File automatically exported by FreeCAD-Ship\n")
Output.write(" # This file contains transversal areas data, filled with following columns:\n")
Output.write(" # 1: Ship displacement [ton]\n")
Output.write(" # 2: Draft [m]\n")
Output.write(" # 3: Wetted surface [m2]\n")
Output.write(" # 4: 1cm triming ship moment [ton m]\n")
Output.write(" # 5: Bouyance center x coordinate\n")
Output.write(" #\n")
Output.write(" #################################################################\n")
# Print data
for i in range(0,len(drafts)):
draft = drafts[i]
point = Tools.Point(ship,draft,trim)
string = "%f %f %f %f %f\n" % (point.disp, point.draft, point.wet, point.mom, point.xcb)
Output.write(string)
# Close file
Output.close()
self.dataFile = filename
msg = Translator.translate("Data saved at '" + self.dataFile + "'.\n")
FreeCAD.Console.PrintMessage(msg)
return False
def saveLayout(self, trim):
""" Prints the pyxplot layout.
@param trim Trim in degrees.
@return True if error happens.
"""
filename = self.path + 'volume.pyxplot'
# Open the file
try:
Output = open(filename, "w")
except IOError:
msg = Translator.translate("Can't write '" + filename + "' file.\n")
FreeCAD.Console.PrintError(msg)
return True
# Write header
Output.write(header)
Output.write(" #\n")
Output.write(" # File automatically exported by FreeCAD-Ship\n")
Output.write(" # This file contains a script to plot transversal areas curve.\n")
Output.write(" # To use it execute:\n")
Output.write(" #\n")
Output.write(" # pyxplot %s\n" % (filename))
Output.write(" #\n")
Output.write(" #################################################################\n")
# Write general options for hydrostatics
Output.write("set numeric display latex\n")
Output.write("set output '%s'\n" % (self.path + 'volume.eps'))
Output.write("set title '$trim$ = %g [degrees]'\n" % (trim))
Output.write("set key below\n")
Output.write("set grid\n")
# Configure axis
Output.write("# Y axis\n")
Output.write("set ylabel '$\\bigtriangleup$ / $\\mathrm{ton}$'\n")
Output.write("set ytic\n")
Output.write("# X axis\n")
Output.write("set xlabel '$Draft$ / $\\mathrm{m}$'\n")
Output.write("set xtic\n")
Output.write("set x2label '\\textit{Wetted area} / $\\mathrm{m}^2$'\n")
Output.write("set x2tic\n")
Output.write("set x3label '\\textit{1cm trim moment} / $\\mathrm{ton} \\times \\mathrm{m}$'\n")
Output.write("set x3tic\n")
Output.write("set x4label '$XCB$ / $\\mathrm{m}$'\n")
Output.write("set x4tic\n")
Output.write("set axis x2 top\n")
Output.write("set axis x4 top\n")
Output.write("# Line styles\n")
Output.write("set style 1 line linetype 1 linewidth 1 colour rgb (0):(0):(0)\n")
Output.write("set style 2 line linetype 1 linewidth 1 colour rgb (1):(0):(0)\n")
Output.write("set style 3 line linetype 1 linewidth 1 colour rgb (0):(0):(1)\n")
Output.write("set style 4 line linetype 1 linewidth 1 colour rgb (1):(0):(1)\n")
# Write plot call
Output.write("# Plot\n")
Output.write("plot '%s' using 2:1 title '$\\bigtriangleup$' axes x1y1 with lines style 1, \\\n" % (self.dataFile))
Output.write(" '' using 3:1 title 'Wetted area' axes x2y1 with lines style 2, \\\n")
Output.write(" '' using 4:1 title '1cm trim moment' axes x3y1 with lines style 3, \\\n")
Output.write(" '' using 5:1 title 'XCB' axes x4y1 with lines style 4\n")
# Close file
self.layoutFile = filename
Output.close()
return False
def execute(self):
""" Calls pyxplot in order to plot an save an image.
@return True if error happens.
"""
filename = self.path + 'volume'
comm = "pyxplot %s" % (self.layoutFile)
if os.system(comm):
msg = Translator.translate("Can't execute pyxplot. Maybe is not installed?\n")
FreeCAD.Console.PrintError(msg)
msg = Translator.translate("Plot will not generated\n")
FreeCAD.Console.PrintError(msg)
return True
comm = "gs -r300 -dEPSCrop -dTextAlphaBits=4 -sDEVICE=png16m -sOutputFile=%s.png -dBATCH -dNOPAUSE %s.eps" % (filename,filename)
if os.system(comm):
msg = Translator.translate("Can't execute ghostscript. Maybe is not installed?\n")
FreeCAD.Console.PrintError(msg)
msg = Translator.translate("Generated image will not converted to png\n")
FreeCAD.Console.PrintError(msg)
return True
return False

View File

@ -28,7 +28,7 @@ import FreeCADGui as Gui
# Qt library
from PyQt4 import QtGui,QtCore
# Module
# import Plot
import Plot
import Instance
from shipUtils import Paths, Translator
from surfUtils import Geometry
@ -43,6 +43,13 @@ class TaskPanel:
if not self.ship:
return False
self.save()
draft = self.form.minDraft.value()
drafts = [draft]
dDraft = (self.form.maxDraft.value() - self.form.minDraft.value())/self.form.nDraft.value()
for i in range(1,self.form.nDraft.value()):
draft = draft + dDraft
drafts.append(draft)
Plot.Plot(self.ship, self.form.trim.value(), drafts)
return True
def reject(self):

View File

@ -32,7 +32,7 @@ from shipUtils import Math
def Displacement(ship, draft, trim):
""" Calculate ship displacement.
@param ship Selected ship instance
@param traft Draft.
@param draft Draft.
@param trim Trim in degrees.
@return [areas,disp,xcb]: \n
areas : Area of each section \n
@ -174,3 +174,194 @@ def Displacement(ship, draft, trim):
if vol > 0.0:
xcb = moment / vol
return [areas,disp,xcb]
def WettedArea(ship, draft, trim):
""" Calculate wetted ship area.
@param ship Selected ship instance
@param draft Draft.
@param trim Trim in degrees.
@return Wetted ship area.
"""
angle = math.radians(trim)
sections = Instance.sections(ship)
xCoord = ship.xSection[:]
lines = []
area = 0.0
if not sections:
return 0.0
for i in range(0, len(sections)):
# Get the section
section = sections[i]
if len(section) < 2: # Empty section
lines.append(0.0)
continue
# Get the position of the section
x = xCoord[i]
# Get the maximum Z value
Z = draft - x*math.tan(angle)
# Count the number of valid points
n = 0
for j in range(0,len(section)):
z = section[j].z
if z > Z:
break
n = n+1
# Discard invalid sections
if n == 0:
lines.append(0.0)
continue
# Truncate only valid points
points = section[0:n]
# Study if additional point is needed
if n < len(section):
y0 = section[n-1].y
z0 = section[n-1].z
y1 = section[n].y
z1 = section[n].z
if (Z > z0) and not (Math.isAprox(Z,z0)):
factor = (Z - z0) / (z1 - z0)
y = y0 + factor*(y1 - y0)
points.append(App.Base.Vector(x,y,Z))
# Convert into array with n elements (Number of points by sections)
# with m elements into them (Number of points with the same height,
# typical of multibody)
section = []
nPoints = 0
j = 0
while j < len(points)-1:
section.append([points[j]])
k = j+1
while(Math.isAprox(points[j].z, points[k].z)):
section[nPoints].append(points[k])
k = k+1
nPoints = nPoints + 1
j = k
# Integrate line area
line = 0.0
for j in range(0, len(section)-1):
for k in range(0, min(len(section[j])-1, len(section[j+1])-1)):
# y11,z11 ------- y01,z01
# | |
# | |
# | |
# y10,z10 ------- y00,z00
y00 = abs(section[j][k].y)
z00 = section[j][k].z
y10 = abs(section[j][k+1].y)
z10 = section[j][k+1].z
y01 = abs(section[j+1][k].y)
z01 = section[j+1][k].z
y11 = abs(section[j+1][k+1].y)
z11 = section[j+1][k+1].z
dy = y11 - y10
dz = z11 - z10
line = line + math.sqrt(dy*dy + dz*dz)
dy = y01 - y00
dz = z01 - z00
line = line + math.sqrt(dy*dy + dz*dz)
if(len(section[j]) < len(section[j+1])):
# y01,z01 ------- y11,z11
# | __/
# | __/
# | /
# y00,z00
k = len(section[j])-1
y00 = abs(section[j][k].y)
z00 = section[j][k].z
y01 = abs(section[j+1][k].y)
z01 = section[j+1][k].z
y11 = abs(section[j+1][k+1].y)
z11 = section[j+1][k+1].z
dy = y11 - y00
dz = z11 - z00
line = line + math.sqrt(dy*dy + dz*dz)
dy = y01 - y00
dz = z01 - z00
line = line + math.sqrt(dy*dy + dz*dz)
elif(len(section[j]) > len(section[j+1])):
# y01,z01
# | \__
# | \__
# | \
# y00,z00 ------- y10,z10
k = len(section[j+1])-1
y00 = abs(section[j][k].y)
z00 = section[j][k].z
y10 = abs(section[j][k+1].y)
z10 = section[j][k+1].z
y01 = abs(section[j+1][k].y)
z01 = section[j+1][k].z
dy = y01 - y00
dz = z01 - z00
line = line + math.sqrt(dy*dy + dz*dz)
dy = y01 - y10
dz = z01 - z10
line = line + math.sqrt(dy*dy + dz*dz)
elif(len(section[j]) == 1):
# y1,z1 -------
# |
# |
# |
# y0,z0 -------
k = 0
y0 = abs(section[j][k].y)
z0 = section[j][k].z
y1 = abs(section[j+1][k].y)
z1 = section[j+1][k].z
dy = y1 - y0
dz = z1 - z0
line = line + math.sqrt(dy*dy + dz*dz)
lines.append(2.0*line) # 2x because only half ship is represented
# Add area if proceed
if i > 0:
dx = xCoord[i] - xCoord[i-1]
x = 0.5*(xCoord[i] + xCoord[i-1])
line = 0.5*(lines[i] + lines[i-1])
area = area + line*dx
return area
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.
"""
angle = math.degrees(math.atan2(0.01,0.5*ship.Length))
newTrim = trim + angle
data = Displacement(ship,draft,newTrim)
mom0 = -disp*xcb
mom1 = -data[1]*data[2]
return mom1 - mom0
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].
@note Moment is positive when produce positive trim.
"""
def __init__(self, ship, draft, trim):
""" Use all hydrostatics tools to define a hydrostatics
point.
@param ship Selected ship instance
@param draft Draft.
@param trim Trim in degrees.
"""
# Hydrostatics computation
areasData = Displacement(ship,draft,trim)
wettedArea = WettedArea(ship,draft,trim)
moment = Moment(ship,draft,trim,areasData[1],areasData[2])
# Store final data
self.draft = draft
self.trim = trim
self.disp = areasData[1]
self.xcb = areasData[2]
self.wet = wettedArea
self.mom = moment