diff --git a/src/Mod/Ship/CMakeLists.txt b/src/Mod/Ship/CMakeLists.txt
index 8f379a0bc..71aea43f0 100644
--- a/src/Mod/Ship/CMakeLists.txt
+++ b/src/Mod/Ship/CMakeLists.txt
@@ -38,6 +38,7 @@ SOURCE_GROUP("shipicons" FILES ${ShipIcons_SRCS})
SET(ShipExamples_SRCS
Examples/s60.fcstd
Examples/barehull5415.fcstd
+ Examples/s60_katamaran.fcstd
)
SOURCE_GROUP("shipexamples" FILES ${ShipExamples_SRCS})
diff --git a/src/Mod/Ship/Examples/s60_katamaran.fcstd b/src/Mod/Ship/Examples/s60_katamaran.fcstd
new file mode 100644
index 000000000..a7d72df94
Binary files /dev/null and b/src/Mod/Ship/Examples/s60_katamaran.fcstd differ
diff --git a/src/Mod/Ship/Instance.py b/src/Mod/Ship/Instance.py
index be4481ed8..64eecd5cc 100644
--- a/src/Mod/Ship/Instance.py
+++ b/src/Mod/Ship/Instance.py
@@ -120,7 +120,7 @@ class Ship:
for j in range(0,nP):
z = z0 + j*dz
rX = x1 - x0
- rY = y1 - y0
+ rY = max(y1 - y0, abs(y1), abs(y0))
planes.append(Part.makePlane(4*rX,4*rY,Base.Vector(-2*rX,-2*rY,z),Base.Vector(0,0,1)))
# Division are performed at x axis
dx = (x1 - x0) / (nS - 1.0)
@@ -134,12 +134,13 @@ class Ship:
wires = shape.slice(Vector(1.0,0.0,0.0), x)
if not wires:
if (i != 0) or (i != nS-1):
- msg = 'Found empty section at x=%g\n'
+ msg = 'Found empty section at x=%g\n' % (x)
msg = Translator.translate(msg)
FreeCAD.Console.PrintWarning(msg)
FreeCAD.Console.PrintWarning('\tThis may happens if a bad defined (or really complex) surface has been provided.\n')
FreeCAD.Console.PrintWarning('\tPlease, ensure that this section is correct, or fix surfaces and create a new ship.\n')
nPoints.append(0)
+ continue
# Desarrollate wires into edges list
edges = []
for j in range(0,len(wires)):
@@ -148,21 +149,25 @@ class Ship:
edges.append(wire[k])
# Slice curves to get points (Length based)
points = []
- for j in range(0,len(edges)):
- for k in range(0,nP):
+ for k in range(0,nP):
+ planePoints = []
+ for j in range(0,len(edges)):
aux = self.lineFaceSection(edges[j], planes[k])
- if not aux:
- points.append(Vector(x,0,z0 + k*dz))
for l in range(0,len(aux)):
- points.append(Vector(aux[l].X, aux[l].Y, aux[l].Z))
- # Sort section points at Y direction
- aux = []
- for j in range(0,len(points)):
- aux.append(points[j].y)
- aux.sort()
- for j in range(0,len(points)):
- section.append(Vector(points[j].x, aux[j], points[j].z))
+ planePoints.append(Vector(aux[l].X, aux[l].Y, aux[l].Z))
+ if not planePoints: # No section found, symmetry plane point will used
+ planePoints.append(Vector(x,0,z0 + k*dz))
+ # Get Y coordinates
+ auxY = []
+ for l in range(0,len(planePoints)):
+ auxY.append(planePoints[l].y)
+ # Sort them
+ auxY.sort()
+ # And store
+ for l in range(0,len(planePoints)):
+ points.append(Vector(planePoints[l].x, auxY[l], planePoints[l].z))
# Store points
+ section = points[:]
nPoints.append(len(section))
for j in range(0,len(section)):
mSections.append(section[j])
@@ -172,6 +177,9 @@ class Ship:
self.obj.nPoints = nPoints[:]
self.obj.xSection = xSection[:]
self.obj.mSections = mSections[:]
+ msg = '%d Discretization points performed\n' % (len(mSections))
+ msg = Translator.translate(msg)
+ FreeCAD.Console.PrintMessage(msg)
class ViewProviderShip:
def __init__(self, obj):
diff --git a/src/Mod/Ship/Makefile.am b/src/Mod/Ship/Makefile.am
index 0c8ff3229..87f2a4759 100644
--- a/src/Mod/Ship/Makefile.am
+++ b/src/Mod/Ship/Makefile.am
@@ -35,6 +35,7 @@ nobase_data_DATA = \
Icons/Ship.xpm \
Examples/s60.fcstd \
Examples/barehull5415.fcstd \
+ Examples/s60_katamaran.fcstd \
shipLoadExample/__init__.py \
shipLoadExample/TaskPanel.py \
shipLoadExample/TaskPanel.ui \
diff --git a/src/Mod/Ship/shipAreasCurve/TaskPanel.py b/src/Mod/Ship/shipAreasCurve/TaskPanel.py
index af4764e12..54d1ecff0 100644
--- a/src/Mod/Ship/shipAreasCurve/TaskPanel.py
+++ b/src/Mod/Ship/shipAreasCurve/TaskPanel.py
@@ -215,12 +215,12 @@ class TaskPanel:
props.index("AreaCurveDraft")
except ValueError:
self.ship.addProperty("App::PropertyFloat","AreaCurveDraft","Ship", str(Translator.translate("Areas curve draft selected [m]")))
- self.ship.AreaCurveDraft = self.form.draft.value()
+ self.ship.AreaCurveDraft = self.form.draft.value()
try:
props.index("AreaCurveTrim")
except ValueError:
self.ship.addProperty("App::PropertyFloat","AreaCurveTrim","Ship", str(Translator.translate("Areas curve trim selected [m]")))
- self.ship.AreaCurveTrim = self.form.draft.value()
+ self.ship.AreaCurveTrim = self.form.trim.value()
def createTask():
panel = TaskPanel()
diff --git a/src/Mod/Ship/shipCreateShip/TaskPanel.py b/src/Mod/Ship/shipCreateShip/TaskPanel.py
index e56827df4..7fab02097 100644
--- a/src/Mod/Ship/shipCreateShip/TaskPanel.py
+++ b/src/Mod/Ship/shipCreateShip/TaskPanel.py
@@ -159,16 +159,19 @@ class TaskPanel:
if maxZ < bbox.ZMax:
maxZ = bbox.ZMax
bounds[0] = maxX - minX
- bounds[1] = maxY - minY
+ bounds[1] = max(maxY - minY, abs(maxY), abs(minY))
bounds[2] = maxZ - minZ
# Set UI fields
self.form.length.setMaximum(bounds[0])
+ self.form.length.setMinimum(0.001)
self.form.length.setValue(bounds[0])
self.L = bounds[0]
self.form.beam.setMaximum(2.0*bounds[1])
+ self.form.beam.setMinimum(0.001)
self.form.beam.setValue(2.0*bounds[1])
self.B = 2.0*bounds[1]
self.form.draft.setMaximum(bounds[2])
+ self.form.draft.setMinimum(0.001)
self.form.draft.setValue(0.5*bounds[2])
self.T = 0.5*bounds[2]
msg = Translator.translate("Ready to work\n")
diff --git a/src/Mod/Ship/shipHydrostatics/Tools.py b/src/Mod/Ship/shipHydrostatics/Tools.py
index 32ce25dc0..3792708c9 100644
--- a/src/Mod/Ship/shipHydrostatics/Tools.py
+++ b/src/Mod/Ship/shipHydrostatics/Tools.py
@@ -27,6 +27,7 @@ import FreeCAD as App
import FreeCADGui as Gui
# Module
import Instance
+from shipUtils import Math
def Displacement(ship, draft, trim):
""" Calculate ship displacement.
@@ -75,20 +76,91 @@ def Displacement(ship, draft, trim):
z0 = section[n-1].z
y1 = section[n].y
z1 = section[n].z
- factor = (Z - z0) / (z1 - z0)
- y = y0 + factor*(y1 - y0)
- points.append(App.Base.Vector(x,y,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 area
area = 0.0
- for j in range(0, len(points)-1):
- y0 = abs(points[j].y)
- z0 = points[j].z
- y1 = abs(points[j+1].y)
- z1 = points[j+1].z
- y = 0.5 * (y0 + y1)
- dz = z1 - z0
- area = area + 2.0*y*dz # 2x because only half ship is represented
- areas.append(area)
+ 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 = 0.5*((y00 - y10) + (y01 - y11))
+ dz = 0.5*((z01 - z00) + (z11 - z10))
+ area = area + dy*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 = y01 - y11
+ dz = z01 - z00
+ area = area + 0.5*dy*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 = y00 - y10
+ dz = z01 - z00
+ area = area + 0.5*dy*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 = 0.5 * (y0 + y1)
+ dz = z1 - z0
+ area = area + dy*dz
+ areas.append(2.0*area) # 2x because only half ship is represented
# Add volume & moment if proceed
if i > 0:
dx = xCoord[i] - xCoord[i-1]
diff --git a/src/Mod/Ship/shipLoadExample/TaskPanel.py b/src/Mod/Ship/shipLoadExample/TaskPanel.py
index 1f6cd9f93..3c9b483c1 100644
--- a/src/Mod/Ship/shipLoadExample/TaskPanel.py
+++ b/src/Mod/Ship/shipLoadExample/TaskPanel.py
@@ -40,6 +40,8 @@ class TaskPanel:
App.open(path + "s60.fcstd")
elif(self.form.ship.currentIndex() == 1): # Barehull 5415
App.open(path + "barehull5415.fcstd")
+ elif(self.form.ship.currentIndex() == 2): # s60 (Katamaran)
+ App.open(path + "s60_katamaran.fcstd")
return True
def reject(self):
diff --git a/src/Mod/Ship/shipLoadExample/TaskPanel.ui b/src/Mod/Ship/shipLoadExample/TaskPanel.ui
index b9f7aeffe..77d744189 100644
--- a/src/Mod/Ship/shipLoadExample/TaskPanel.ui
+++ b/src/Mod/Ship/shipLoadExample/TaskPanel.ui
@@ -84,6 +84,11 @@
Barehull 5145
+ -
+
+ Serie 60 (Katamaran)
+
+
-
diff --git a/src/Mod/Ship/shipOutlineDraw/Plot.py b/src/Mod/Ship/shipOutlineDraw/Plot.py
index 155b6b0b6..7d21b2fbc 100644
--- a/src/Mod/Ship/shipOutlineDraw/Plot.py
+++ b/src/Mod/Ship/shipOutlineDraw/Plot.py
@@ -57,7 +57,8 @@ def Plot(scale, sections, shape):
border = border.oldFuse(edges[i]) # Only group objects, don't try to build more complex entities
border = border.oldFuse(edges[i].mirror(Vector(0.0, 0.0, 0.0),Vector(0.0, 1.0, 0.0)))
# Fuse sections & borders
- obj = sections.oldFuse(border)
+ # obj = sections.oldFuse(border)
+ obj = border.oldFuse(sections)
# Send to 3D view
Part.show(obj)
objs = FreeCAD.ActiveDocument.Objects
diff --git a/src/Mod/Ship/shipUtils/Math.py b/src/Mod/Ship/shipUtils/Math.py
index f8c583bef..018467c58 100644
--- a/src/Mod/Ship/shipUtils/Math.py
+++ b/src/Mod/Ship/shipUtils/Math.py
@@ -21,7 +21,7 @@
#* *
#***************************************************************************
-def isAprox(a,b,tol=0.0001):
+def isAprox(a,b,tol=0.000001):
"""returns if a value is into (b-tol,b+tol)
@param a Value to compare.
@param b Center of valid interval
@@ -32,7 +32,7 @@ def isAprox(a,b,tol=0.0001):
return True
return False
-def isSamePoint(a,b,tol=0.0001):
+def isSamePoint(a,b,tol=0.000001):
"""returns if two points are the same with a provided tolerance
@param a Point to compare.
@param b Reference point.