Added some hydrostatics computation.
This commit is contained in:
parent
6c870f2ebd
commit
87782c32cb
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
194
src/Mod/Ship/shipHydrostatics/Plot.py
Normal file
194
src/Mod/Ship/shipHydrostatics/Plot.py
Normal 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
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user