Merge branch 'sanguinariojoe-ship' of ssh://free-cad.git.sourceforge.net/gitroot/free-cad/free-cad into sanguinariojoe-ship

This commit is contained in:
Jose Luis Cercos Pita 2012-07-25 19:09:17 +02:00
commit ca881d1455
22 changed files with 9125 additions and 11 deletions

View File

@ -2,6 +2,7 @@ SET(ShipMain_SRCS
InitGui.py InitGui.py
ShipGui.py ShipGui.py
Instance.py Instance.py
SimInstance.py
TankInstance.py TankInstance.py
) )
SOURCE_GROUP("" FILES ${ShipMain_SRCS}) SOURCE_GROUP("" FILES ${ShipMain_SRCS})
@ -36,6 +37,14 @@ SET(ShipIcons_SRCS
Icons/Weight.png Icons/Weight.png
Icons/Weight.xcf Icons/Weight.xcf
Icons/Weight.xpm Icons/Weight.xpm
Icons/SimIco.xcf
Icons/Sim.xpm
Icons/SimCreateIco.png
Icons/SimCreateIco.xpm
Icons/SimRunIco.png
Icons/SimRunIco.xpm
Icons/SimStopIco.png
Icons/SimStopIco.xpm
Icons/Tank.png Icons/Tank.png
Icons/Tank.xcf Icons/Tank.xcf
Icons/Tank.xpm Icons/Tank.xpm
@ -121,9 +130,24 @@ SET(ShipGZ_SRCS
tankGZ/TaskPanel.py tankGZ/TaskPanel.py
tankGZ/TaskPanel.ui tankGZ/TaskPanel.ui
) )
SOURCE_GROUP("shipcreatetank" FILES ${ShipCreateTank_SRCS}) SOURCE_GROUP("shipgz" FILES ${ShipGZ_SRCS})
SET(all_files ${ShipMain_SRCS} ${ShipIcons_SRCS} ${ShipExamples_SRCS} ${ShipLoadExample_SRCS} ${ShipCreateShip_SRCS} ${ShipOutlineDraw_SRCS} ${ShipAreasCurve_SRCS} ${ShipHydrostatics_SRCS} ${ShipUtils_SRCS} ${ShipWeights_SRCS} ${ShipCreateTank_SRCS} ${ShipGZ_SRCS}) SET(SimCreate_SRCS
simCreate/__init__.py
simCreate/TaskPanel.py
simCreate/TaskPanel.ui
)
SOURCE_GROUP("simcreate" FILES ${SimCreate_SRCS})
SET(SimRun_SRCS
simRun/__init__.py
simRun/Simulation.py
simRun/TaskPanel.py
simRun/TaskPanel.ui
)
SOURCE_GROUP("simrun" FILES ${SimRun_SRCS})
SET(all_files ${ShipMain_SRCS} ${ShipIcons_SRCS} ${ShipExamples_SRCS} ${ShipLoadExample_SRCS} ${ShipCreateShip_SRCS} ${ShipOutlineDraw_SRCS} ${ShipAreasCurve_SRCS} ${ShipHydrostatics_SRCS} ${ShipUtils_SRCS} ${ShipWeights_SRCS} ${ShipCreateTank_SRCS} ${ShipGZ_SRCS} ${SimCreate_SRCS} ${SimRun_SRCS})
ADD_CUSTOM_TARGET(Ship ALL ADD_CUSTOM_TARGET(Ship ALL
SOURCES ${all_files} SOURCES ${all_files}
@ -197,6 +221,18 @@ INSTALL(
DESTINATION DESTINATION
Mod/Ship/tankGZ Mod/Ship/tankGZ
) )
INSTALL(
FILES
${SimCreate_SRCS}
DESTINATION
Mod/Ship/simCreate
)
INSTALL(
FILES
${SimRun_SRCS}
DESTINATION
Mod/Ship/simRun
)
INSTALL( INSTALL(
FILES FILES
${ShipMain_SRCS} ${ShipMain_SRCS}

336
src/Mod/Ship/Icons/Sim.xpm Normal file
View File

@ -0,0 +1,336 @@
/* XPM */
static char * Sim_xpm[] = {
"32 32 301 2",
" c None",
". c #CCCCCC",
"+ c #A9A9A9",
"@ c #989898",
"# c #A1A1A1",
"$ c #C3C3C3",
"% c #C1C0C1",
"& c #BFBFBF",
"* c #A7A7A7",
"= c #808080",
"- c #5C5C5C",
"; c #565655",
"> c #4E4E4E",
", c #676767",
"' c #898989",
") c #B6B5B6",
"! c #BABABA",
"~ c #B9B9B9",
"{ c #A5A5A5",
"] c #7E7E7E",
"^ c #595A59",
"/ c #575656",
"( c #535353",
"_ c #505050",
": c #4D4D4C",
"< c #474747",
"[ c #404040",
"} c #4D4D4D",
"| c #787878",
"1 c #B8B7B8",
"2 c #B6B6B6",
"3 c #888888",
"4 c #7C7C7C",
"5 c #575657",
"6 c #535354",
"7 c #4E4D4E",
"8 c #4A4A4A",
"9 c #444444",
"0 c #414141",
"a c #3E3E3E",
"b c #393938",
"c c #313131",
"d c #393939",
"e c #636363",
"f c #ABABAB",
"g c #B3B3B3",
"h c #848484",
"i c #787979",
"j c #545454",
"k c #515151",
"l c #4B4B4B",
"m c #484748",
"n c #3B3B3B",
"o c #383838",
"p c #353535",
"q c #323232",
"r c #2F2F2E",
"s c #2A2A2A",
"t c #222323",
"u c #252625",
"v c #AFAFAF",
"w c #767676",
"x c #484848",
"y c #454545",
"z c #424242",
"A c #3F3F3E",
"B c #3B3B3C",
"C c #393838",
"D c #2F2F2F",
"E c #2C2C2C",
"F c #292929",
"G c #262626",
"H c #222222",
"I c #1F1F20",
"J c #171716",
"K c #959595",
"L c #747474",
"M c #4E4E4F",
"N c #4C4B4C",
"O c #484849",
"P c #424243",
"Q c #282828",
"R c #525251",
"S c #373737",
"T c #353636",
"U c #333233",
"V c #30302F",
"W c #2C2D2D",
"X c #232323",
"Y c #201F20",
"Z c #1D1D1D",
"` c #151414",
" . c #717272",
".. c #4C4C4C",
"+. c #484949",
"@. c #464545",
"#. c #424343",
"$. c #3A3A3A",
"%. c #5D4A49",
"&. c #7E7E86",
"*. c #56569F",
"=. c #3E3E41",
"-. c #757575",
";. c #575757",
">. c #222221",
",. c #262627",
"'. c #242423",
"). c #212020",
"!. c #1A1A1A",
"~. c #121212",
"{. c #939493",
"]. c #6F6F6F",
"^. c #494949",
"/. c #464646",
"(. c #434343",
"_. c #554545",
":. c #686863",
"<. c #939394",
"[. c #BDBDBD",
"}. c #202021",
"|. c #1E1E1E",
"1. c #171718",
"2. c #0F0F0F",
"3. c #929292",
"4. c #6C6D6D",
"5. c #464746",
"6. c #525F73",
"7. c #444648",
"8. c #3D3D3D",
"9. c #2D2C2A",
"0. c #A1A2A2",
"a. c #AAACAC",
"b. c #A6A7A7",
"c. c #A8AAAA",
"d. c #AFB0B0",
"e. c #777676",
"f. c #9A9A9A",
"g. c #1B1B1B",
"h. c #181818",
"i. c #0C0C0C",
"j. c #909090",
"k. c #6B6A6B",
"l. c #55657E",
"m. c #6990FB",
"n. c #6483CD",
"o. c #5871B2",
"p. c #434E7E",
"q. c #A97C76",
"r. c #AB7777",
"s. c #AC7070",
"t. c #A26565",
"u. c #805C5C",
"v. c #848686",
"w. c #424342",
"x. c #151515",
"y. c #0A0909",
"z. c #8F8F8F",
"A. c #676868",
"B. c #3B3A3A",
"C. c #383738",
"D. c #353534",
"E. c #45525F",
"F. c #6367AC",
"G. c #804682",
"H. c #942A39",
"I. c #991312",
"J. c #540901",
"K. c #393742",
"L. c #1C1C1C",
"M. c #191919",
"N. c #161515",
"O. c #121313",
"P. c #070707",
"Q. c #8D8E8D",
"R. c #656566",
"S. c #3E3F3F",
"T. c #2F2E2F",
"U. c #353838",
"V. c #35496A",
"W. c #3E4D88",
"X. c #354889",
"Y. c #5573D7",
"Z. c #5D80FB",
"`. c #374899",
" + c #293338",
".+ c #101010",
"++ c #0D0D0D",
"@+ c #040404",
"#+ c #8C8C8C",
"$+ c #8B8B8B",
"%+ c #4B4A4B",
"&+ c #303030",
"*+ c #333232",
"=+ c #2F2F30",
"-+ c #232223",
";+ c #1A1919",
">+ c #2E3949",
",+ c #5C7BA3",
"'+ c #36467D",
")+ c #536F93",
"!+ c #0A0A0A",
"~+ c #010101",
"{+ c #C1C1C1",
"]+ c #B8B8B8",
"^+ c #A0A0A0",
"/+ c #3F3F3F",
"(+ c #222122",
"_+ c #202020",
":+ c #161717",
"<+ c #141414",
"[+ c #111011",
"}+ c #0D0E0E",
"|+ c #0B0B0A",
"1+ c #000000",
"2+ c #525252",
"3+ c #686868",
"4+ c #ADADAD",
"5+ c #9E9F9F",
"6+ c #6D6D6D",
"7+ c #3C3C3C",
"8+ c #131414",
"9+ c #111111",
"0+ c #0E0E0E",
"a+ c #0B0B0B",
"b+ c #080708",
"c+ c #050504",
"d+ c #4C4D4C",
"e+ c #4D4C4D",
"f+ c #494A4A",
"g+ c #454444",
"h+ c #9D9D9D",
"i+ c #9E9E9E",
"j+ c #AEAEAE",
"k+ c #BEBEBF",
"l+ c #BEBDBD",
"m+ c #979797",
"n+ c #6A6B6A",
"o+ c #3F3F40",
"p+ c #020202",
"q+ c #030303",
"r+ c #878787",
"s+ c #69696A",
"t+ c #868685",
"u+ c #646464",
"v+ c #474647",
"w+ c #656565",
"x+ c #9E9F9E",
"y+ c #A8A8A8",
"z+ c #AFAFAE",
"A+ c #A4A4A4",
"B+ c #7A7A7A",
"C+ c #969696",
"D+ c #363636",
"E+ c #777776",
"F+ c #8C8D8D",
"G+ c #7D7D7D",
"H+ c #5E5E5E",
"I+ c #4F4F50",
"J+ c #808181",
"K+ c #707070",
"L+ c #909191",
"M+ c #9C9C9C",
"N+ c #787877",
"O+ c #696969",
"P+ c #616161",
"Q+ c #6E6E6E",
"R+ c #7C7B7C",
"S+ c #777677",
"T+ c #6F6E6E",
"U+ c #595959",
"V+ c #717171",
"W+ c #8D8D8D",
"X+ c #515051",
"Y+ c #49494A",
"Z+ c #4B4A4A",
"`+ c #606060",
" @ c #6A6A6A",
".@ c #616162",
"+@ c #6C6D6C",
"@@ c #767777",
"#@ c #727272",
"$@ c #6B6B6B",
"%@ c #828283",
"&@ c #757475",
"*@ c #444545",
"=@ c #565656",
"-@ c #5A595A",
";@ c #666666",
">@ c #878687",
",@ c #8A8A8A",
"'@ c #797979",
")@ c #444344",
"!@ c #7F8080",
"~@ c #737373",
"{@ c #484747",
"]@ c #707170",
"^@ c #7F7F7F",
"/@ c #676867",
"(@ c #4D4C4C",
"_@ c #5F5F5F",
":@ c #434444",
" ",
" ",
" . + ",
" @ # $ % & * ",
" = - ; > , ' ) ! ~ { ",
" ] ^ / ( _ : < [ } | # 1 2 # 3 ",
" 4 5 6 _ 7 8 < 9 0 a b c d e ' f g + h ",
" i j k 7 l m 9 0 a n o p q r s t u < | v ",
" w k > l x y z A B C p q D E F G H I J K ",
" L M N O y P Q R S T U V W F G X Y Z ` K ",
" ...+.@.#.$.%.&.*.=.-.;.>.,.'.).Z !.~.{. ",
" ].^./.(.[ c _._ :.<.[.$ ' /.}.|.!.1.2.3. ",
" 4.5.6.7.8.9.# 0.a.b.c.d.e.f.g.g.h.` i.j. ",
" k.9 l.m.n.o.p.q.r.s.t.u.v.w.g.h.x.~.y.z. ",
" A.0 a B.C.D.E.F.G.H.I.J.K.L.M.N.O.2.P.Q. ",
" R.S.n o p q T.E U.V.W.X.Y.Z.`. +.+++@+#+ ",
" $+%+&+q *+=+E F G -+I Z ;+>+,+'+)+!+~+$+ ",
" {+]+^+w /+H (+X _+Z !.:+<+[+}+|+P.1+' ",
" k 2+_ > 3+z.4+5+6+7+x.~.8+9+0+a+b+c+1+3 ",
" %+..d+e+..f+< g+h+i+j+k+l+m+n+o+P.p+q+p+1+r+ ",
" s+t+u+< (.< v+y 9 (.w+x+y+z+y+h+A+B+C+K ].D+1+h ",
" E+i+F+f.j.G+H+9 [ (.z I+J+m+f.j.K+z 9 9 9 K+L+r+/.9 (. ",
" L M+N+O+u+P+Q+R+S+T+U+y 8 - ;...9 9 9 9 9 9 9 9 (.(.k w+ ",
" V+m+' W+r+] , X+Y+(.: r+L P+k 9 z (.9 9 9 9 (.(.Z+;.- `+ ",
" ].C+w @u+.@+@@@#@$@j %@B+&@#@L $@H+2+/.0 (.*@+.} 2+=@-@ ",
" ;@| >@,@'@u+k 8 )@..!@| ~@V+#@#@#@#@L 6+..(.9 {@.._ ( ",
" e ]@^@] /@k G+w #@#@#@#@#@V+ @$@_ 9 9 9 /.Y+(@ ",
" - R.T+L ~@#@#@#@#@]._ _@_ 9 9 9 (.9 x ",
" =@_@O+L ~@#@~@L _ 9 9 :@ ",
" ;.H+ @-._ (. ",
" ",
" "};

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because it is too large Load Diff

View File

@ -35,12 +35,33 @@ class ShipWorkbench ( Workbench ):
list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"] list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"]
self.appendToolbar("Ship design",list) self.appendToolbar("Ship design",list)
list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"] list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"]
self.appendToolbar("Loading",list) self.appendToolbar("Weights",list)
# Simulation stuff only if pyOpenCL & numpy are present
hasOpenCL = True
hasNumpy = True
try:
import pyopencl
except ImportError:
hasOpenCL = False
msg = Translator.translate("pyOpenCL not installed, ship simulations disabled\n")
App.Console.PrintWarning(msg)
try:
import numpy
except ImportError:
hasNumpy = False
msg = Translator.translate("numpy not installed, ship simulations disabled\n")
App.Console.PrintWarning(msg)
if hasOpenCL and hasNumpy:
list = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim"]
self.appendToolbar("Simulation",list)
# Menu # Menu
list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"] list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"]
self.appendMenu("Ship design",list) self.appendMenu("Ship design",list)
list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"] list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"]
self.appendToolbar("Loading",list) self.appendMenu("Weights",list)
if hasOpenCL and hasNumpy:
list = ["Ship_CreateSim", "Ship_RunSim", "Ship_StopSim"]
self.appendMenu("Simulation",list)
Gui.addWorkbench(ShipWorkbench()) Gui.addWorkbench(ShipWorkbench())

View File

@ -5,6 +5,7 @@ data_DATA = \
InitGui.py \ InitGui.py \
ShipGui.py \ ShipGui.py \
Instance.py \ Instance.py \
SimInstance.py \
TankInstance.py TankInstance.py
nobase_data_DATA = \ nobase_data_DATA = \
@ -37,6 +38,14 @@ nobase_data_DATA = \
Icons/Weight.png \ Icons/Weight.png \
Icons/Weight.xcf \ Icons/Weight.xcf \
Icons/Weight.xpm \ Icons/Weight.xpm \
Icons/SimIco.xcf \
Icons/Sim.xpm \
Icons/SimCreateIco.png \
Icons/SimCreateIco.xpm \
Icons/SimRunIco.png \
Icons/SimRunIco.xpm \
Icons/SimStopIco.png \
Icons/SimStopIco.xpm \
Icons/Tank.png \ Icons/Tank.png \
Icons/Tank.xcf \ Icons/Tank.xcf \
Icons/Tank.xpm \ Icons/Tank.xpm \
@ -80,7 +89,14 @@ nobase_data_DATA = \
tankGZ/__init__.py \ tankGZ/__init__.py \
tankGZ/Plot.py \ tankGZ/Plot.py \
tankGZ/TaskPanel.py \ tankGZ/TaskPanel.py \
tankGZ/TaskPanel.ui tankGZ/TaskPanel.ui \
simCreate/__init__.py \
simCreate/TaskPanel.py \
simCreate/TaskPanel.ui \
simRun/__init__.py \
simRun/Simulation.py \
simRun/TaskPanel.py \
simRun/TaskPanel.ui
CLEANFILES = $(BUILT_SOURCES) CLEANFILES = $(BUILT_SOURCES)

View File

@ -120,6 +120,42 @@ class GZ:
ToolTip = str(Translator.translate('Transversal stability GZ curve computation')) ToolTip = str(Translator.translate('Transversal stability GZ curve computation'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class CreateSim:
def Activated(self):
import simCreate
simCreate.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/SimCreateIco.png"
MenuText = str(Translator.translate('Create a new simulation'))
ToolTip = str(Translator.translate('Create a new simulation in order to process later'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class RunSim:
def Activated(self):
import simRun
simRun.load()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/SimRunIco.png"
MenuText = str(Translator.translate('Run a simulation'))
ToolTip = str(Translator.translate('Run a simulation'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
class StopSim:
def Activated(self):
import simRun
simRun.stop()
def GetResources(self):
from shipUtils import Paths, Translator
IconPath = Paths.iconsPath() + "/SimStopIco.png"
MenuText = str(Translator.translate('Stop active simulation'))
ToolTip = str(Translator.translate('Stop active simulation'))
return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip}
FreeCADGui.addCommand('Ship_LoadExample', LoadExample()) FreeCADGui.addCommand('Ship_LoadExample', LoadExample())
FreeCADGui.addCommand('Ship_CreateShip', CreateShip()) FreeCADGui.addCommand('Ship_CreateShip', CreateShip())
FreeCADGui.addCommand('Ship_OutlineDraw', OutlineDraw()) FreeCADGui.addCommand('Ship_OutlineDraw', OutlineDraw())
@ -128,3 +164,6 @@ FreeCADGui.addCommand('Ship_Hydrostatics', Hydrostatics())
FreeCADGui.addCommand('Ship_Weights', SetWeights()) FreeCADGui.addCommand('Ship_Weights', SetWeights())
FreeCADGui.addCommand('Ship_CreateTank', CreateTank()) FreeCADGui.addCommand('Ship_CreateTank', CreateTank())
FreeCADGui.addCommand('Ship_GZ', GZ()) FreeCADGui.addCommand('Ship_GZ', GZ())
FreeCADGui.addCommand('Ship_CreateSim', CreateSim())
FreeCADGui.addCommand('Ship_RunSim', RunSim())
FreeCADGui.addCommand('Ship_StopSim', StopSim())

656
src/Mod/Ship/SimInstance.py Normal file
View File

@ -0,0 +1,656 @@
#***************************************************************************
#* *
#* 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 time
from math import *
import threading
# COIN
from pivy.coin import *
from pivy import coin
# FreeCAD
import FreeCAD,FreeCADGui
from FreeCAD import Part, Base, Vector
# Ship design module
from shipUtils import Paths, Translator, Math
class FreeSurfaceFace:
def __init__(self, pos, normal, l, b):
""" Face storage.
@param pos Face position.
@param normal Face normal.
@param l Element length (distance between elements at x direction)
@param b Element beam (distance between elements at y direction)
"""
self.pos = pos
self.normal = normal
self.area = l*b
def __init__(self, pos, normal, area):
""" Face storage.
@param pos Face position.
@param normal Face normal.
@param area Element area
"""
self.pos = pos
self.normal = normal
self.area = area
class ShipSimulation:
def __init__(self, obj, fsMeshData, waves):
""" Creates a new simulation instance on active document.
@param obj Created Part::FeaturePython object.
@param fsMeshData [L,B,N] Free surface mesh data, with lenght
(x), Beam (y) and desired number of points.
@param waves [[A,T,phi,heading],] Waves involved
"""
# Add uniqueness property to identify Tank instances
obj.addProperty("App::PropertyBool","IsShipSimulation","ShipSimulation", str(Translator.translate("True if is a valid ship simulation instance"))).IsShipSimulation=True
# Compute free surface mesh
self.createFSMesh(obj,fsMeshData)
# Store waves
obj.addProperty("App::PropertyVectorList","Waves","ShipSimulation", str(Translator.translate("Waves (Amplitude,period,phase)"))).Waves=[]
obj.addProperty("App::PropertyFloatList","Waves_Dir","ShipSimulation", str(Translator.translate("Waves direction (0 deg to stern waves)"))).Waves_Dir=[]
w = []
d = []
for i in range(0,len(waves)):
w.append(Vector(waves[i][0], waves[i][1], waves[i][2]))
d.append(waves[i][3])
obj.Waves = w
obj.Waves_Dir = d
# Add shapes
shape = self.computeShape(obj)
if not shape:
obj.IsShipSimulation=False
return
obj.Shape = shape
obj.Proxy = self
def onChanged(self, fp, prop):
""" Property changed, tank must be recomputed """
if prop == "IsShipSimulation":
FreeCAD.Console.PrintWarning("Ussually you don't want to modify manually this option.\n")
def execute(self, obj):
""" Shape recomputation called """
obj.Shape = self.computeShape(obj)
def createFSMesh(self, obj, fsMeshData):
""" Create or modify free surface mesh.
@param obj Created Part::FeaturePython object.
@param fsMeshData [L,B,N] Free surface mesh data, with lenght
(x), Beam (y) and desired number of points.
"""
# Study input object
try:
props = obj.PropertiesList
props.index("IsShipSimulation")
if not obj.IsShipSimulation:
msg = str(Translator.translate("Object is not a valid ship simulation.\n"))
FreeCAD.Console.PrintError(msg)
return
except ValueError:
msg = str(Translator.translate("Object is not a ship simulation.\n"))
FreeCAD.Console.PrintError(msg)
return
# Get areas and number of elements per direction
L = fsMeshData[0]
B = fsMeshData[1]
N = fsMeshData[2]
A = L*B
area = A/N
l = sqrt(area)
b = sqrt(area)
nx = int(round(L / l))
ny = int(round(B / b))
# Start data fields if not already exist
props = obj.PropertiesList
try:
props.index("FS_Nx")
except ValueError:
obj.addProperty("App::PropertyInteger","FS_Nx","ShipSimulation", str(Translator.translate("Free surface number of elements at x direction"))).FS_Nx=0
try:
props.index("FS_Ny")
except ValueError:
obj.addProperty("App::PropertyInteger","FS_Ny","ShipSimulation", str(Translator.translate("Free surface number of elements at y direction"))).FS_Ny=0
try:
props.index("FS_Position")
except ValueError:
obj.addProperty("App::PropertyVectorList","FS_Position","ShipSimulation", str(Translator.translate("Free surface elements position"))).FS_Position=[]
try:
props.index("FS_Area")
except ValueError:
obj.addProperty("App::PropertyFloatList","FS_Area","ShipSimulation", str(Translator.translate("Free surface elements area"))).FS_Area=[]
try:
props.index("FS_Normal")
except ValueError:
obj.addProperty("App::PropertyVectorList","FS_Normal","ShipSimulation", str(Translator.translate("Free surface elements normal"))).FS_Normal=[]
# Fill data
obj.FS_Nx = nx
obj.FS_Ny = ny
pos = []
areas = []
normal = []
for i in range(0,nx):
for j in range(0,ny):
pos.append(Vector(-0.5*L + (i+0.5)*l,-0.5*B + (j+0.5)*b,0.0))
areas.append(l*b)
normal.append(Vector(0.0,0.0,1.0))
obj.FS_Position = pos[:]
obj.FS_Area = areas[:]
obj.FS_Normal = normal[:]
def computeShape(self, obj):
""" Computes simulation involved shapes.
@param obj Created Part::FeaturePython object.
@return Shape
"""
print("[ShipSimulation] Computing mesh shape...")
nx = obj.FS_Nx
ny = obj.FS_Ny
mesh = FSMesh(obj)
planes = []
# Create planes
Percentage = 0
Count = 0
print("0%")
for i in range(1,nx-1):
for j in range(1,ny-1):
Count = Count+1
done = int(round(100 * Count / ((nx-2)*(ny-2))))
if done != Percentage:
Percentage = done
print("%i%%" % (done))
v0 = (mesh[i][j].pos + mesh[i-1][j].pos + mesh[i][j-1].pos + mesh[i-1][j-1].pos).multiply(0.25)
v1 = (mesh[i][j].pos + mesh[i+1][j].pos + mesh[i][j-1].pos + mesh[i+1][j-1].pos).multiply(0.25)
v2 = (mesh[i][j].pos + mesh[i+1][j].pos + mesh[i][j+1].pos + mesh[i+1][j+1].pos).multiply(0.25)
v3 = (mesh[i][j].pos + mesh[i-1][j].pos + mesh[i][j+1].pos + mesh[i-1][j+1].pos).multiply(0.25)
p = Part.makePolygon([v0,v1,v2,v3,v0])
planes.append(Part.makeFilledFace(p.Edges))
# Join into a compound
return Part.makeCompound(planes)
class ViewProviderShipSimulation:
def __init__(self, obj):
""" Set this object to the proxy object of the actual view provider """
obj.Proxy = self
def attach(self, obj):
""" Setup the scene sub-graph of the view provider, this method is mandatory """
return
def updateData(self, fp, prop):
""" If a property of the handled feature has changed we have the chance to handle this here """
return
def getDisplayModes(self,obj):
''' Return a list of display modes. '''
modes=[]
return modes
def getDefaultDisplayMode(self):
''' Return the name of the default display mode. It must be defined in getDisplayModes. '''
return "Flat Lines"
def setDisplayMode(self,mode):
''' Map the display mode defined in attach with those defined in getDisplayModes.
Since they have the same names nothing needs to be done. This method is optinal.
'''
return mode
def onChanged(self, vp, prop):
''' Print the name of the property that has changed '''
# FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n")
def __getstate__(self):
''' When saving the document this object gets stored using Python's cPickle module.
Since we have some un-pickable here -- the Coin stuff -- we must define this method
to return a tuple of all pickable objects or None.
'''
return None
def __setstate__(self,state):
''' When restoring the pickled object from document we have the chance to set some
internals here. Since no data were pickled nothing needs to be done here.
'''
return None
def getIcon(self):
return """
/* XPM */
static char * Sim_xpm[] = {
"32 32 301 2",
" c None",
". c #CCCCCC",
"+ c #A9A9A9",
"@ c #989898",
"# c #A1A1A1",
"$ c #C3C3C3",
"% c #C1C0C1",
"& c #BFBFBF",
"* c #A7A7A7",
"= c #808080",
"- c #5C5C5C",
"; c #565655",
"> c #4E4E4E",
", c #676767",
"' c #898989",
") c #B6B5B6",
"! c #BABABA",
"~ c #B9B9B9",
"{ c #A5A5A5",
"] c #7E7E7E",
"^ c #595A59",
"/ c #575656",
"( c #535353",
"_ c #505050",
": c #4D4D4C",
"< c #474747",
"[ c #404040",
"} c #4D4D4D",
"| c #787878",
"1 c #B8B7B8",
"2 c #B6B6B6",
"3 c #888888",
"4 c #7C7C7C",
"5 c #575657",
"6 c #535354",
"7 c #4E4D4E",
"8 c #4A4A4A",
"9 c #444444",
"0 c #414141",
"a c #3E3E3E",
"b c #393938",
"c c #313131",
"d c #393939",
"e c #636363",
"f c #ABABAB",
"g c #B3B3B3",
"h c #848484",
"i c #787979",
"j c #545454",
"k c #515151",
"l c #4B4B4B",
"m c #484748",
"n c #3B3B3B",
"o c #383838",
"p c #353535",
"q c #323232",
"r c #2F2F2E",
"s c #2A2A2A",
"t c #222323",
"u c #252625",
"v c #AFAFAF",
"w c #767676",
"x c #484848",
"y c #454545",
"z c #424242",
"A c #3F3F3E",
"B c #3B3B3C",
"C c #393838",
"D c #2F2F2F",
"E c #2C2C2C",
"F c #292929",
"G c #262626",
"H c #222222",
"I c #1F1F20",
"J c #171716",
"K c #959595",
"L c #747474",
"M c #4E4E4F",
"N c #4C4B4C",
"O c #484849",
"P c #424243",
"Q c #282828",
"R c #525251",
"S c #373737",
"T c #353636",
"U c #333233",
"V c #30302F",
"W c #2C2D2D",
"X c #232323",
"Y c #201F20",
"Z c #1D1D1D",
"` c #151414",
" . c #717272",
".. c #4C4C4C",
"+. c #484949",
"@. c #464545",
"#. c #424343",
"$. c #3A3A3A",
"%. c #5D4A49",
"&. c #7E7E86",
"*. c #56569F",
"=. c #3E3E41",
"-. c #757575",
";. c #575757",
">. c #222221",
",. c #262627",
"'. c #242423",
"). c #212020",
"!. c #1A1A1A",
"~. c #121212",
"{. c #939493",
"]. c #6F6F6F",
"^. c #494949",
"/. c #464646",
"(. c #434343",
"_. c #554545",
":. c #686863",
"<. c #939394",
"[. c #BDBDBD",
"}. c #202021",
"|. c #1E1E1E",
"1. c #171718",
"2. c #0F0F0F",
"3. c #929292",
"4. c #6C6D6D",
"5. c #464746",
"6. c #525F73",
"7. c #444648",
"8. c #3D3D3D",
"9. c #2D2C2A",
"0. c #A1A2A2",
"a. c #AAACAC",
"b. c #A6A7A7",
"c. c #A8AAAA",
"d. c #AFB0B0",
"e. c #777676",
"f. c #9A9A9A",
"g. c #1B1B1B",
"h. c #181818",
"i. c #0C0C0C",
"j. c #909090",
"k. c #6B6A6B",
"l. c #55657E",
"m. c #6990FB",
"n. c #6483CD",
"o. c #5871B2",
"p. c #434E7E",
"q. c #A97C76",
"r. c #AB7777",
"s. c #AC7070",
"t. c #A26565",
"u. c #805C5C",
"v. c #848686",
"w. c #424342",
"x. c #151515",
"y. c #0A0909",
"z. c #8F8F8F",
"A. c #676868",
"B. c #3B3A3A",
"C. c #383738",
"D. c #353534",
"E. c #45525F",
"F. c #6367AC",
"G. c #804682",
"H. c #942A39",
"I. c #991312",
"J. c #540901",
"K. c #393742",
"L. c #1C1C1C",
"M. c #191919",
"N. c #161515",
"O. c #121313",
"P. c #070707",
"Q. c #8D8E8D",
"R. c #656566",
"S. c #3E3F3F",
"T. c #2F2E2F",
"U. c #353838",
"V. c #35496A",
"W. c #3E4D88",
"X. c #354889",
"Y. c #5573D7",
"Z. c #5D80FB",
"`. c #374899",
" + c #293338",
".+ c #101010",
"++ c #0D0D0D",
"@+ c #040404",
"#+ c #8C8C8C",
"$+ c #8B8B8B",
"%+ c #4B4A4B",
"&+ c #303030",
"*+ c #333232",
"=+ c #2F2F30",
"-+ c #232223",
";+ c #1A1919",
">+ c #2E3949",
",+ c #5C7BA3",
"'+ c #36467D",
")+ c #536F93",
"!+ c #0A0A0A",
"~+ c #010101",
"{+ c #C1C1C1",
"]+ c #B8B8B8",
"^+ c #A0A0A0",
"/+ c #3F3F3F",
"(+ c #222122",
"_+ c #202020",
":+ c #161717",
"<+ c #141414",
"[+ c #111011",
"}+ c #0D0E0E",
"|+ c #0B0B0A",
"1+ c #000000",
"2+ c #525252",
"3+ c #686868",
"4+ c #ADADAD",
"5+ c #9E9F9F",
"6+ c #6D6D6D",
"7+ c #3C3C3C",
"8+ c #131414",
"9+ c #111111",
"0+ c #0E0E0E",
"a+ c #0B0B0B",
"b+ c #080708",
"c+ c #050504",
"d+ c #4C4D4C",
"e+ c #4D4C4D",
"f+ c #494A4A",
"g+ c #454444",
"h+ c #9D9D9D",
"i+ c #9E9E9E",
"j+ c #AEAEAE",
"k+ c #BEBEBF",
"l+ c #BEBDBD",
"m+ c #979797",
"n+ c #6A6B6A",
"o+ c #3F3F40",
"p+ c #020202",
"q+ c #030303",
"r+ c #878787",
"s+ c #69696A",
"t+ c #868685",
"u+ c #646464",
"v+ c #474647",
"w+ c #656565",
"x+ c #9E9F9E",
"y+ c #A8A8A8",
"z+ c #AFAFAE",
"A+ c #A4A4A4",
"B+ c #7A7A7A",
"C+ c #969696",
"D+ c #363636",
"E+ c #777776",
"F+ c #8C8D8D",
"G+ c #7D7D7D",
"H+ c #5E5E5E",
"I+ c #4F4F50",
"J+ c #808181",
"K+ c #707070",
"L+ c #909191",
"M+ c #9C9C9C",
"N+ c #787877",
"O+ c #696969",
"P+ c #616161",
"Q+ c #6E6E6E",
"R+ c #7C7B7C",
"S+ c #777677",
"T+ c #6F6E6E",
"U+ c #595959",
"V+ c #717171",
"W+ c #8D8D8D",
"X+ c #515051",
"Y+ c #49494A",
"Z+ c #4B4A4A",
"`+ c #606060",
" @ c #6A6A6A",
".@ c #616162",
"+@ c #6C6D6C",
"@@ c #767777",
"#@ c #727272",
"$@ c #6B6B6B",
"%@ c #828283",
"&@ c #757475",
"*@ c #444545",
"=@ c #565656",
"-@ c #5A595A",
";@ c #666666",
">@ c #878687",
",@ c #8A8A8A",
"'@ c #797979",
")@ c #444344",
"!@ c #7F8080",
"~@ c #737373",
"{@ c #484747",
"]@ c #707170",
"^@ c #7F7F7F",
"/@ c #676867",
"(@ c #4D4C4C",
"_@ c #5F5F5F",
":@ c #434444",
" ",
" ",
" . + ",
" @ # $ % & * ",
" = - ; > , ' ) ! ~ { ",
" ] ^ / ( _ : < [ } | # 1 2 # 3 ",
" 4 5 6 _ 7 8 < 9 0 a b c d e ' f g + h ",
" i j k 7 l m 9 0 a n o p q r s t u < | v ",
" w k > l x y z A B C p q D E F G H I J K ",
" L M N O y P Q R S T U V W F G X Y Z ` K ",
" ...+.@.#.$.%.&.*.=.-.;.>.,.'.).Z !.~.{. ",
" ].^./.(.[ c _._ :.<.[.$ ' /.}.|.!.1.2.3. ",
" 4.5.6.7.8.9.# 0.a.b.c.d.e.f.g.g.h.` i.j. ",
" k.9 l.m.n.o.p.q.r.s.t.u.v.w.g.h.x.~.y.z. ",
" A.0 a B.C.D.E.F.G.H.I.J.K.L.M.N.O.2.P.Q. ",
" R.S.n o p q T.E U.V.W.X.Y.Z.`. +.+++@+#+ ",
" $+%+&+q *+=+E F G -+I Z ;+>+,+'+)+!+~+$+ ",
" {+]+^+w /+H (+X _+Z !.:+<+[+}+|+P.1+' ",
" k 2+_ > 3+z.4+5+6+7+x.~.8+9+0+a+b+c+1+3 ",
" %+..d+e+..f+< g+h+i+j+k+l+m+n+o+P.p+q+p+1+r+ ",
" s+t+u+< (.< v+y 9 (.w+x+y+z+y+h+A+B+C+K ].D+1+h ",
" E+i+F+f.j.G+H+9 [ (.z I+J+m+f.j.K+z 9 9 9 K+L+r+/.9 (. ",
" L M+N+O+u+P+Q+R+S+T+U+y 8 - ;...9 9 9 9 9 9 9 9 (.(.k w+ ",
" V+m+' W+r+] , X+Y+(.: r+L P+k 9 z (.9 9 9 9 (.(.Z+;.- `+ ",
" ].C+w @u+.@+@@@#@$@j %@B+&@#@L $@H+2+/.0 (.*@+.} 2+=@-@ ",
" ;@| >@,@'@u+k 8 )@..!@| ~@V+#@#@#@#@L 6+..(.9 {@.._ ( ",
" e ]@^@] /@k G+w #@#@#@#@#@V+ @$@_ 9 9 9 /.Y+(@ ",
" - R.T+L ~@#@#@#@#@]._ _@_ 9 9 9 (.9 x ",
" =@_@O+L ~@#@~@L _ 9 9 :@ ",
" ;.H+ @-._ (. ",
" ",
" "};
"""
def FSMesh(obj, recompute=False):
""" Get free surface mesh in matrix mode.
@param obj Created Part::FeaturePython object.
@param recompute True if mesh must be recomputed, False otherwise.
@return Faces matrix
"""
nx = obj.FS_Nx
ny = obj.FS_Ny
if not recompute:
faces = []
for i in range(0,nx):
faces.append([])
for j in range(0,ny):
faces[i].append(FreeSurfaceFace(obj.FS_Position[j + i*ny],
obj.FS_Normal[j + i*ny],
obj.FS_Area[j + i*ny]))
return faces
# Transform positions into a mesh
pos = []
for i in range(0,nx):
pos.append([])
for j in range(0,ny):
pos[i].append(obj.FS_Position[j + i*ny])
# Recompute normals and dimensions
normal = []
l = []
b = []
for i in range(0,nx):
normal.append([])
l.append([])
b.append([])
for j in range(0,ny):
i0 = i-1
i1 = i+1
fi = 1.0
j0 = j-1
j1 = j+1
fj = 1.0
if i == 0:
i0 = i
i1 = i+1
fi = 2.0
if i == nx-1:
i0 = i-1
i1 = i
fi = 2.0
if j == 0:
j0 = j
j1 = j+1
fj = 2.0
if j == ny-1:
j0 = j-1
j1 = j
fj = 2.0
l[i].append(fi*(obj.FS_Position[j + i1*ny].x - obj.FS_Position[j + i0*ny].x))
b[i].append(fj*(obj.FS_Position[j1 + i*ny].y - obj.FS_Position[j0 + i*ny].y))
xvec = Vector(obj.FS_Position[j + i1*ny].x - obj.FS_Position[j + i0*ny].x,
obj.FS_Position[j + i1*ny].y - obj.FS_Position[j + i0*ny].y,
obj.FS_Position[j + i1*ny].z - obj.FS_Position[j + i0*ny].z)
yvec = Vector(obj.FS_Position[j1 + i*ny].x - obj.FS_Position[j0 + i*ny].x,
obj.FS_Position[j1 + i*ny].y - obj.FS_Position[j0 + i*ny].y,
obj.FS_Position[j1 + i*ny].z - obj.FS_Position[j0 + i*ny].z)
n = Vector(xvec.cross(yvec)) # Z positive
normal[i].append(n.normalize())
# Create faces
faces = []
for i in range(0,nx):
faces.append([])
for j in range(0,ny):
faces[i].append(FreeSurfaceFace(pos[i][j], normal[i][j], l[i][j], b[i][j]))
# Reconstruct mesh data
for i in range(0,nx):
for j in range(0,ny):
obj.FS_Position[j + i*ny] = faces[i][j].pos
obj.FS_Normal[j + i*ny] = faces[i][j].normal
obj.FS_Area[j + i*ny] = faces[i][j].area
return faces

View File

@ -31,7 +31,6 @@ from PyQt4 import QtGui,QtCore
import Plot import Plot
import Instance import Instance
from shipUtils import Paths, Translator from shipUtils import Paths, Translator
from surfUtils import Geometry
import Tools import Tools
class TaskPanel: class TaskPanel:
@ -45,7 +44,7 @@ class TaskPanel:
self.save() self.save()
draft = self.form.minDraft.value() draft = self.form.minDraft.value()
drafts = [draft] drafts = [draft]
dDraft = (self.form.maxDraft.value() - self.form.minDraft.value())/self.form.nDraft.value() dDraft = (self.form.maxDraft.value() - self.form.minDraft.value())/(self.form.nDraft.value()-1)
for i in range(1,self.form.nDraft.value()): for i in range(1,self.form.nDraft.value()):
draft = draft + dDraft draft = draft + dDraft
drafts.append(draft) drafts.append(draft)
@ -108,7 +107,7 @@ class TaskPanel:
""" Set initial values for fields """ Set initial values for fields
""" """
# Get objects # Get objects
selObjs = Geometry.getSelectedObjs() selObjs = Gui.Selection.getSelection()
if not selObjs: if not selObjs:
msg = Translator.translate("Ship instance must be selected (no object selected)\n") msg = Translator.translate("Ship instance must be selected (no object selected)\n")
App.Console.PrintError(msg) App.Console.PrintError(msg)

View File

@ -279,9 +279,9 @@ def FloatingArea(ship, draft, trim):
# Valid face, compute area # Valid face, compute area
area = area + f.Area area = area + f.Area
maxX = max(maxX, faceBounds.XMax) maxX = max(maxX, faceBounds.XMax)
minX = max(minX, faceBounds.XMin) minX = min(minX, faceBounds.XMin)
maxY = max(maxY, faceBounds.YMax) maxY = max(maxY, faceBounds.YMax)
minY = max(minY, faceBounds.YMin) minY = min(minY, faceBounds.YMin)
# Destroy last object generated # Destroy last object generated
App.ActiveDocument.removeObject(App.ActiveDocument.Objects[-1].Name) App.ActiveDocument.removeObject(App.ActiveDocument.Objects[-1].Name)
dx = maxX - minX dx = maxX - minX
@ -416,7 +416,7 @@ class Point:
self.wet = wet self.wet = wet
self.farea = farea[0] self.farea = farea[0]
self.mom = mom self.mom = mom
self.KBt = dispData[1].y self.KBt = dispData[1].z
self.BMt = bm self.BMt = bm
self.Cb = dispData[2] self.Cb = dispData[2]
self.Cf = farea[1] self.Cf = farea[1]

View File

@ -0,0 +1,174 @@
#***************************************************************************
#* *
#* 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 *
#* *
#***************************************************************************
# FreeCAD modules
import FreeCAD as App
import FreeCADGui as Gui
# Qt library
from PyQt4 import QtGui,QtCore
# Module
import SimInstance
from shipUtils import Paths, Translator
class TaskPanel:
def __init__(self):
self.ui = Paths.modulePath() + "/simCreate/TaskPanel.ui"
def accept(self):
form = self.form
# Read waves data
w = []
for i in range(0,form.waves.rowCount() - 1):
item = form.waves.item(i,0)
A = item.text().toFloat()[0]
item = form.waves.item(i,1)
T = item.text().toFloat()[0]
item = form.waves.item(i,2)
phi = item.text().toFloat()[0]
item = form.waves.item(i,3)
head = item.text().toFloat()[0]
w.append([A,T,phi,head])
obj = App.ActiveDocument.addObject("Part::FeaturePython","ShipSimulation")
sim = SimInstance.ShipSimulation(obj,
[form.length.value(), form.beam.value(), form.n.value()],
w)
SimInstance.ViewProviderShipSimulation(obj.ViewObject)
return True
def reject(self):
return True
def clicked(self, index):
pass
def open(self):
pass
def needsFullSpace(self):
return True
def isAllowedAlterSelection(self):
return False
def isAllowedAlterView(self):
return True
def isAllowedAlterDocument(self):
return False
def helpRequested(self):
pass
def setupUi(self):
mw = self.getMainWindow()
form = mw.findChild(QtGui.QWidget, "TaskPanel")
form.length = form.findChild(QtGui.QDoubleSpinBox, "Length")
form.beam = form.findChild(QtGui.QDoubleSpinBox, "Beam")
form.n = form.findChild(QtGui.QSpinBox, "N")
form.waves = form.findChild(QtGui.QTableWidget, "Waves")
self.form = form
# Initial values
if self.initValues():
return True
self.retranslateUi()
# Connect Signals and Slots
QtCore.QObject.connect(form.length, QtCore.SIGNAL("valueChanged(double)"), self.onFS)
QtCore.QObject.connect(form.beam, QtCore.SIGNAL("valueChanged(double)"), self.onFS)
QtCore.QObject.connect(form.n, QtCore.SIGNAL("valueChanged(int)"), self.onFS)
QtCore.QObject.connect(form.waves,QtCore.SIGNAL("cellChanged(int,int)"),self.onWaves);
def getMainWindow(self):
"returns the main window"
# using QtGui.qApp.activeWindow() isn't very reliable because if another
# widget than the mainwindow is active (e.g. a dialog) the wrong widget is
# returned
toplevel = QtGui.qApp.topLevelWidgets()
for i in toplevel:
if i.metaObject().className() == "Gui::MainWindow":
return i
raise Exception("No main window found")
def initValues(self):
""" Set initial values for fields
"""
msg = Translator.translate("Ready to work\n")
App.Console.PrintMessage(msg)
return False
def retranslateUi(self):
""" Set user interface locale strings.
"""
self.form.setWindowTitle(Translator.translate("Create a new ship simulation"))
self.form.findChild(QtGui.QGroupBox, "FSDataBox").setTitle(Translator.translate("Free surface"))
self.form.findChild(QtGui.QLabel, "LengthLabel").setText(Translator.translate("Length"))
self.form.findChild(QtGui.QLabel, "BeamLabel").setText(Translator.translate("Beam"))
self.form.findChild(QtGui.QLabel, "NLabel").setText(Translator.translate("Number of points"))
self.form.findChild(QtGui.QGroupBox, "WavesDataBox").setTitle(Translator.translate("Waves"))
labels = []
labels.append(Translator.translate("Amplitude") + " [m]")
labels.append(Translator.translate("Period") + " [s]")
labels.append(Translator.translate("Phase") + " [rad]")
labels.append(Translator.translate("Heading") + " [deg]")
self.form.waves.setHorizontalHeaderLabels(labels)
def onFS(self, value):
""" Method called when free surface data is changed.
@param value Changed value.
"""
pass
def onWaves(self, row, column):
""" Method called when waves data is changed.
@param row Affected row.
@param col Affected column.
"""
item = self.form.waves.item(row,column)
# Row deletion
if column == 0:
if not item.text():
self.form.waves.removeRow(row)
# Ensure that exist one empty item at the end
nRow = self.form.waves.rowCount()
last = self.form.waves.item(nRow-1,0)
if last:
if(last.text() != ''):
self.form.waves.setRowCount(nRow+1)
# Fields must be numbers
for i in range(0,self.form.waves.rowCount()-1): # Avoid last row
for j in range(0,self.form.waves.columnCount()): # Avoid name column
item = self.form.waves.item(i,j)
if not item:
item = QtGui.QTableWidgetItem('0.0')
self.form.waves.setItem(i,j,item)
continue
(number,flag) = item.text().toFloat()
if not flag:
item.setText('0.0')
def createTask():
panel = TaskPanel()
Gui.Control.showDialog(panel)
if panel.setupUi():
Gui.Control.closeDialog(panel)
return None
return panel

View File

@ -0,0 +1,269 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaskPanel</class>
<widget class="QWidget" name="TaskPanel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>269</width>
<height>384</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>384</height>
</size>
</property>
<property name="windowTitle">
<string>Create new simulation</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="QGroupBox" name="FSDataBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>128</height>
</size>
</property>
<property name="title">
<string>Free surface</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="flat">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="LengthLabel">
<property name="text">
<string>Length</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="Length">
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
<property name="singleStep">
<double>10.000000000000000</double>
</property>
<property name="value">
<double>100.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="BeamLabel">
<property name="text">
<string>Beam</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="Beam">
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>1000000.000000000000000</double>
</property>
<property name="singleStep">
<double>10.000000000000000</double>
</property>
<property name="value">
<double>100.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="NLabel">
<property name="text">
<string>Number of points</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="N">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000000000</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="WavesDataBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>2</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="title">
<string>Waves</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="0">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QTableWidget" name="Waves">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="rowCount">
<number>1</number>
</property>
<attribute name="horizontalHeaderVisible">
<bool>true</bool>
</attribute>
<row/>
<column>
<property name="text">
<string>Amplitude [m]</string>
</property>
</column>
<column>
<property name="text">
<string>Period [s]</string>
</property>
</column>
<column>
<property name="text">
<string>Phase [rad]</string>
</property>
</column>
<column>
<property name="text">
<string>Heading [deg]</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,36 @@
#***************************************************************************
#* *
#* 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 *
#* *
#***************************************************************************
# FreeCAD modules
import FreeCAD
import FreeCADGui
# Qt libraries
from PyQt4 import QtGui,QtCore
# Main object
import TaskPanel
def load():
""" Loads the tool """
TaskPanel.createTask()

View File

@ -0,0 +1,96 @@
#***************************************************************************
#* *
#* 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 time
from math import *
import threading
# pyOpenCL
import pyopencl as cl
import numpy as np
# FreeCAD
import FreeCAD,FreeCADGui
from FreeCAD import Part, Base, Vector
# Ship design module
from shipUtils import Paths, Translator, Math
class Singleton(type):
def __init__(cls, name, bases, dct):
cls.__instance = None
type.__init__(cls, name, bases, dct)
def __call__(cls, *args, **kw):
if cls.__instance is None:
cls.__instance = type.__call__(cls, *args,**kw)
return cls.__instance
class FreeCADShipSimulation(threading.Thread):
__metaclass__ = Singleton
def __init__ (self, device, endTime, output, FSmesh, waves):
""" Thread constructor.
@param device Device to use.
@param endTime Maximum simulation time.
@param output [Rate,Type] Output rate, Type=0 if FPS, 1 if IPF.
@param FSmesh Free surface mesh faces.
@param waves Waves parameters (A,T,phi,heading)
"""
threading.Thread.__init__(self)
# Setup as stopped
self.active = False
# Build OpenCL context and command queue
self.device = device
self.context = cl.Context(devices=[self.device])
self.queue = cl.CommandQueue(self.context)
# Storage data
self.endTime = endTime
self.output = output
self.FSmesh = FSmesh
self.waves = waves
def run(self):
""" Runs the simulation.
"""
self.active = True
# Perform work here
while self.active:
print("Im thread, Im running...")
time.sleep(1)
# ...
print("Im thread, step done!")
# Set thread as stopped (and prepare it to restarting)
self.active = False
threading.Event().set()
threading.Thread.__init__(self)
def stop(self):
""" Call to stop execution.
"""
self.active = False
def isRunning(self):
""" Report thread state
@return True if thread is running, False otherwise.
"""
return self.active

View File

@ -0,0 +1,203 @@
#***************************************************************************
#* *
#* 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 *
#* *
#***************************************************************************
# FreeCAD modules
import FreeCAD as App
import FreeCADGui as Gui
# Qt library
from PyQt4 import QtGui,QtCore
# pyOpenCL
import pyopencl as cl
# Module
import SimInstance
from shipUtils import Paths, Translator
from Simulation import FreeCADShipSimulation as Sim
import time
class TaskPanel:
def __init__(self):
self.ui = Paths.modulePath() + "/simRun/TaskPanel.ui"
self.sim = False
def accept(self):
msg = Translator.translate("Building data...\n")
App.Console.PrintMessage(msg)
# Get GUI data
endTime = self.form.time.value()
output = []
output.append(self.form.output.value())
output.append(self.form.outputType.currentIndex())
devId = self.form.device.currentIndex()
# Get OpenCL device
count = 0
platforms = cl.get_platforms()
for p in platforms:
devs = p.get_devices()
for d in devs:
if count == devId:
device = d
count = count + 1
# Get free surfaces data
FSMesh = SimInstance.FSMesh(self.sim)
wData = self.sim.Waves
wDir = self.sim.Waves_Dir
waves = []
for i in range(0,len(wData)):
waves.append([wData[i].x, wData[i].y, wData[i].z, wDir[i]])
msg = Translator.translate("Launching simulation...\n")
App.Console.PrintMessage(msg)
# Build simulation thread
simulator = Sim(device, endTime, output, FSMesh, waves)
simulator.start()
msg = Translator.translate("Done!\n")
App.Console.PrintMessage(msg)
return True
def reject(self):
return True
def clicked(self, index):
pass
def open(self):
pass
def needsFullSpace(self):
return True
def isAllowedAlterSelection(self):
return False
def isAllowedAlterView(self):
return True
def isAllowedAlterDocument(self):
return False
def helpRequested(self):
pass
def setupUi(self):
mw = self.getMainWindow()
form = mw.findChild(QtGui.QWidget, "TaskPanel")
form.time = form.findChild(QtGui.QDoubleSpinBox, "SimTime")
form.output = form.findChild(QtGui.QDoubleSpinBox, "Output")
form.outputType = form.findChild(QtGui.QComboBox, "OutputType")
form.device = form.findChild(QtGui.QComboBox, "Device")
self.form = form
# Initial values
if self.initValues():
return True
self.retranslateUi()
# Connect Signals and Slots
# QtCore.QObject.connect(form.time, QtCore.SIGNAL("valueChanged(double)"), self.onData)
def getMainWindow(self):
"returns the main window"
# using QtGui.qApp.activeWindow() isn't very reliable because if another
# widget than the mainwindow is active (e.g. a dialog) the wrong widget is
# returned
toplevel = QtGui.qApp.topLevelWidgets()
for i in toplevel:
if i.metaObject().className() == "Gui::MainWindow":
return i
raise Exception("No main window found")
def initValues(self):
""" Set initial values for fields
"""
# Get objects
selObjs = Gui.Selection.getSelection()
if not selObjs:
msg = Translator.translate("Ship simulation instance must be selected (no object selected)\n")
App.Console.PrintError(msg)
return True
for i in range(0,len(selObjs)):
obj = selObjs[i]
# Test if is a ship instance
props = obj.PropertiesList
try:
props.index("IsShipSimulation")
except ValueError:
continue
if obj.IsShipSimulation:
# Test if another ship already selected
if self.sim:
msg = Translator.translate("More than one ship simulation selected (extra simulations will be neglected)\n")
App.Console.PrintWarning(msg)
break
self.sim = obj
# Test if any valid ship was selected
if not self.sim:
msg = Translator.translate("Ship simulation instance must be selected (no valid simulation found at selected objects)\n")
App.Console.PrintError(msg)
return True
# Get the list of devices
devices = []
platforms = cl.get_platforms()
for p in platforms:
devs = p.get_devices()
for d in devs:
devices.append([p,d])
dname = d.get_info(cl.device_info.NAME)
pname = p.get_info(cl.platform_info.NAME)
self.form.device.addItem(dname + " (" + pname + ")")
if not len(devices):
msg = Translator.translate("This tool requires an active OpenCL context to work\n")
App.Console.PrintError(msg)
return True
msg = Translator.translate("Ready to work\n")
App.Console.PrintMessage(msg)
return False
def retranslateUi(self):
""" Set user interface locale strings.
"""
self.form.setWindowTitle(Translator.translate("Run the simulation"))
self.form.findChild(QtGui.QLabel, "SimTimeLabel").setText(Translator.translate("Simulation time"))
self.form.findChild(QtGui.QLabel, "OutputLabel").setText(Translator.translate("Output"))
self.form.findChild(QtGui.QLabel, "DeviceLabel").setText(Translator.translate("OpenCL device"))
def createTask():
panel = TaskPanel()
Gui.Control.showDialog(panel)
if panel.setupUi():
Gui.Control.closeDialog(panel)
return None
return panel
def stopSimulation():
try:
simulator = Sim()
if not simulator.isRunning():
msg = Translator.translate("Simulation already stopped\n")
App.Console.PrintWarning(msg)
return
except:
msg = Translator.translate("Any active simulation to stop!\n")
App.Console.PrintError(msg)
return
simulator.stop()
msg = Translator.translate("Simulation will stop at the end of actual iteration\n")
App.Console.PrintMessage(msg)

View File

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaskPanel</class>
<widget class="QWidget" name="TaskPanel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>102</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
<property name="windowTitle">
<string>Create new simulation</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="SimTimeLabel">
<property name="text">
<string>Simulation time</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="SimTime">
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>10000000.000000000000000</double>
</property>
<property name="singleStep">
<double>10.000000000000000</double>
</property>
<property name="value">
<double>3600.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="SimTimeUnitsLabel">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>s</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="OutputLabel">
<property name="text">
<string>Output</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="Output">
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="OutputType">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>56</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string comment="FPS = Frames per second, IPF = Iterations per frame"/>
</property>
<item>
<property name="text">
<string>FPS</string>
</property>
</item>
<item>
<property name="text">
<string>IPF</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="DeviceLabel">
<property name="text">
<string>OpenCL device</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QComboBox" name="Device"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,40 @@
#***************************************************************************
#* *
#* 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 *
#* *
#***************************************************************************
# FreeCAD modules
import FreeCAD
import FreeCADGui
# Qt libraries
from PyQt4 import QtGui,QtCore
# Main object
import TaskPanel
def load():
""" Loads the tool """
TaskPanel.createTask()
def stop():
""" Stops the simulation """
TaskPanel.stopSimulation()