External faces detection implemented that allows to compute wetted area.
This commit is contained in:
parent
c524a0268a
commit
6c1158e2e9
|
@ -22,6 +22,7 @@
|
|||
#***************************************************************************
|
||||
|
||||
import time
|
||||
from math import *
|
||||
|
||||
# COIN
|
||||
from pivy.coin import *
|
||||
|
@ -48,6 +49,7 @@ class Ship:
|
|||
obj.addProperty("App::PropertyLength","Draft","Ship", str(Translator.translate("Ship draft (T) [m]"))).Draft=0.0
|
||||
# Add shapes
|
||||
obj.Shape = Part.makeCompound(solids)
|
||||
obj.addProperty("Part::PropertyPartShape","ExternalFaces","Ship", str(Translator.translate("Ship only external faces")))
|
||||
obj.Proxy = self
|
||||
|
||||
def onChanged(self, fp, prop):
|
||||
|
@ -64,37 +66,6 @@ class Ship:
|
|||
"""
|
||||
fp.Shape = Part.makeCompound(fp.Shape.Solids)
|
||||
|
||||
def lineFaceSection(self,line,surface):
|
||||
""" Returns the point of section of a line with a face
|
||||
@param line Line object, that can be a curve.
|
||||
@param surface Surface object (must be a Part::Shape)
|
||||
@return Section points array, [] if line don't cut surface
|
||||
"""
|
||||
# Get initial data
|
||||
result = []
|
||||
vertexes = line.Vertexes
|
||||
nVertex = len(vertexes)
|
||||
# Perform the cut
|
||||
section = line.cut(surface)
|
||||
# Filter all old points
|
||||
points = section.Vertexes
|
||||
nPoint = len(points)
|
||||
if nPoint <= nVertex:
|
||||
# Any valid point
|
||||
return result
|
||||
for i in range(0,nPoint):
|
||||
disp = len(result)
|
||||
flag = 0
|
||||
if not Math.isAprox(points[i].X,vertexes[i-disp].X,0.0001):
|
||||
flag = flag+1
|
||||
if not Math.isAprox(points[i].Y,vertexes[i-disp].Y,0.0001):
|
||||
flag = flag+1
|
||||
if not Math.isAprox(points[i].Z,vertexes[i-disp].Z,0.0001):
|
||||
flag = flag+1
|
||||
if flag > 0:
|
||||
result.append(points[i])
|
||||
return result
|
||||
|
||||
class ViewProviderShip:
|
||||
def __init__(self, obj):
|
||||
"Set this object to the proxy object of the actual view provider"
|
||||
|
|
|
@ -52,7 +52,6 @@ class ShipTank:
|
|||
if not shape:
|
||||
obj.IsShipTank=False
|
||||
return
|
||||
# obj.addProperty("Part::PropertyPartShape","Shape","ShipTank", str(Translator.translate("Tank solid"))).Shape = shape
|
||||
obj.Shape = shape
|
||||
obj.Proxy = self
|
||||
self.obj = obj
|
||||
|
|
|
@ -22,9 +22,10 @@
|
|||
#***************************************************************************
|
||||
|
||||
import os
|
||||
import math
|
||||
# FreeCAD modules
|
||||
import FreeCAD,FreeCADGui
|
||||
from FreeCAD import Part, Base
|
||||
from FreeCAD import Part, Base, Vector
|
||||
from FreeCAD import Image, ImageGui
|
||||
# FreeCADShip modules
|
||||
from shipUtils import Paths, Translator
|
||||
|
@ -107,11 +108,19 @@ class Plot(object):
|
|||
Output.write(" # 11: Cm (Main frame coefficient)\n")
|
||||
Output.write(" #\n")
|
||||
Output.write(" #################################################################\n")
|
||||
# Get external faces
|
||||
faces = self.externalFaces(ship.Shape)
|
||||
if len(faces) == 0:
|
||||
msg = Translator.translate("Can't detect external faces from ship object.\n")
|
||||
FreeCAD.Console.PrintError(msg)
|
||||
else:
|
||||
faces = Part.makeShell(faces)
|
||||
# Print data
|
||||
FreeCAD.Console.PrintMessage("Computing hydrostatics...\n")
|
||||
for i in range(0,len(drafts)):
|
||||
FreeCAD.Console.PrintMessage("%d / %d" % (i+1, len(drafts)))
|
||||
FreeCAD.Console.PrintMessage("\t%d / %d\n" % (i+1, len(drafts)))
|
||||
draft = drafts[i]
|
||||
point = Tools.Point(ship,draft,trim)
|
||||
point = Tools.Point(ship,faces,draft,trim)
|
||||
string = "%f %f %f %f %f %f %f %f %f %f %f\n" % (point.disp, point.draft, point.wet, point.mom, point.xcb, point.farea, point.KBt, point.BMt, point.Cb, point.Cf, point.Cm)
|
||||
Output.write(string)
|
||||
# Close file
|
||||
|
@ -251,3 +260,86 @@ class Plot(object):
|
|||
FreeCAD.Console.PrintError(msg)
|
||||
return True
|
||||
return False
|
||||
|
||||
def lineFaceSection(self,line,surface):
|
||||
""" Returns the point of section of a line with a face
|
||||
@param line Line object, that can be a curve.
|
||||
@param surface Surface object (must be a Part::Shape)
|
||||
@return Section points array, [] if line don't cut surface
|
||||
"""
|
||||
# Get initial data
|
||||
result = []
|
||||
vertexes = line.Vertexes
|
||||
nVertex = len(vertexes)
|
||||
# Perform the cut
|
||||
section = line.cut(surface)
|
||||
# Filter all old points
|
||||
points = section.Vertexes
|
||||
return points
|
||||
|
||||
def externalFaces(self, shape):
|
||||
""" Returns detected external faces.
|
||||
@param shape Shape where external faces wanted.
|
||||
@return List of external faces detected.
|
||||
"""
|
||||
result = []
|
||||
faces = shape.Faces
|
||||
bbox = shape.BoundBox
|
||||
L = bbox.XMax - bbox.XMin
|
||||
B = bbox.YMax - bbox.YMin
|
||||
T = bbox.ZMax - bbox.ZMin
|
||||
dist = math.sqrt(L*L + B*B + T*T)
|
||||
FreeCAD.Console.PrintMessage("Computing external faces...\n")
|
||||
# Valid/unvalid faces detection loop
|
||||
for i in range(0,len(faces)):
|
||||
FreeCAD.Console.PrintMessage("\t%d / %d\n" % (i+1, len(faces)))
|
||||
f = faces[i]
|
||||
# Create a line normal to surface at middle point
|
||||
u = 0.0
|
||||
v = 0.0
|
||||
try:
|
||||
surf = f.Surface
|
||||
u = 0.5*(surf.getUKnots()[0]+surf.getUKnots()[-1])
|
||||
v = 0.5*(surf.getVKnots()[0]+surf.getVKnots()[-1])
|
||||
except:
|
||||
cog = f.CenterOfMass
|
||||
[u,v] = f.Surface.parameter(cog)
|
||||
p0 = f.valueAt(u,v)
|
||||
try:
|
||||
n = f.normalAt(u,v).normalize()
|
||||
except:
|
||||
continue
|
||||
p1 = p0 + n.multiply(1.5*dist)
|
||||
line = Part.makeLine(p0, p1)
|
||||
# Look for faces in front of this
|
||||
nPoints = 0
|
||||
for j in range(0,len(faces)):
|
||||
f2 = faces[j]
|
||||
section = self.lineFaceSection(line, f2)
|
||||
if len(section) <= 2:
|
||||
continue
|
||||
# Add points discarding start and end
|
||||
nPoints = nPoints + len(section) - 2
|
||||
# In order to avoid special directions we can modify line
|
||||
# normal a little bit.
|
||||
angle = 5
|
||||
line.rotate(p0,Vector(1,0,0),angle)
|
||||
line.rotate(p0,Vector(0,1,0),angle)
|
||||
line.rotate(p0,Vector(0,0,1),angle)
|
||||
nPoints2 = 0
|
||||
for j in range(0,len(faces)):
|
||||
if i == j:
|
||||
continue
|
||||
f2 = faces[j]
|
||||
section = self.lineFaceSection(line, f2)
|
||||
if len(section) <= 2:
|
||||
continue
|
||||
# Add points discarding start and end
|
||||
nPoints2 = nPoints + len(section) - 2
|
||||
# If the number of intersection points is pair, is a
|
||||
# external face. So if we found an odd points intersection,
|
||||
# face must be discarded.
|
||||
if (nPoints % 2) or (nPoints2 % 2):
|
||||
continue
|
||||
result.append(f)
|
||||
return result
|
||||
|
|
|
@ -175,19 +175,17 @@ def displacement(ship, draft, roll=0.0, trim=0.0, yaw=0.0):
|
|||
dens = 1.025 # [tons/m3], salt water
|
||||
return [dens*vol, B, vol/Vol]
|
||||
|
||||
def wettedArea(ship, draft, trim):
|
||||
def wettedArea(shape, draft, trim):
|
||||
""" Calculate wetted ship area.
|
||||
@param ship Selected ship instance
|
||||
@param shape Ship external faces instance.
|
||||
@param draft Draft.
|
||||
@param trim Trim in degrees.
|
||||
@return Wetted ship area.
|
||||
"""
|
||||
return 0.0
|
||||
faces = []
|
||||
area = 0.0
|
||||
nObjects = 0
|
||||
# We will take a duplicate of ship shape in order to place it
|
||||
shape = ship.Shape.copy()
|
||||
shape = shape.copy()
|
||||
shape.translate(Vector(0.0,0.0,-draft))
|
||||
shape.rotate(Vector(0.0,0.0,0.0), Vector(0.0,-1.0,0.0), trim)
|
||||
# Now we need to know the x range of values
|
||||
|
@ -200,57 +198,13 @@ def wettedArea(ship, draft, trim):
|
|||
p = Vector(-1.5*L, -1.5*B, bbox.ZMin - 1.0)
|
||||
box = Part.makeBox(3.0*L, 3.0*B, - bbox.ZMin + 1.0, p)
|
||||
# Compute common part with ship
|
||||
for s in shape.Solids:
|
||||
for f in shape.Faces:
|
||||
# Get solids intersection
|
||||
try:
|
||||
common = box.common(s)
|
||||
common = box.common(f)
|
||||
except:
|
||||
continue
|
||||
if common.Volume == 0.0:
|
||||
continue
|
||||
# Recompute object adding it to the scene, when we have
|
||||
# computed desired data we can remove it.
|
||||
try:
|
||||
Part.show(common)
|
||||
except:
|
||||
continue
|
||||
nObjects = nObjects + 1
|
||||
# Divide by faces and discard free surface faces
|
||||
faces = common.Faces
|
||||
for f in faces:
|
||||
fbox = f.BoundBox
|
||||
# Orientation filter
|
||||
if (fbox.ZMax-fbox.ZMin > 0.00001) and (abs(fbox.ZMax) > 0.00001):
|
||||
continue
|
||||
# Valid face, append it
|
||||
faces.append(f)
|
||||
# Study repeated faces, if a face is repeated, both of them must be
|
||||
# discarded.
|
||||
i = 0;
|
||||
while(i < len(faces)):
|
||||
j = i+1
|
||||
while(j < len(faces)):
|
||||
f0 = faces[i]
|
||||
f1 = faces[j]
|
||||
# We will consider same face if share all their vertexes
|
||||
nVertex = len(f0.Vertexes)
|
||||
for v0 in f0.Vertexes:
|
||||
for v1 in f1.Vertexes:
|
||||
if Math.isSameVertex(v0,v1):
|
||||
nVertex = nVertex - 1
|
||||
if nVertex <= 0:
|
||||
del faces[j]
|
||||
del faces[i]
|
||||
i = i-1
|
||||
break
|
||||
j = j+1
|
||||
i = i+1
|
||||
# Integrate areas
|
||||
for f in faces:
|
||||
area = area + f.Area
|
||||
# Destroy generated objects
|
||||
for i in range(0,nObjects):
|
||||
App.ActiveDocument.removeObject(App.ActiveDocument.Objects[-1].Name)
|
||||
area = area + common.Area
|
||||
return area
|
||||
|
||||
def moment(ship, draft, trim, disp, xcb):
|
||||
|
@ -435,16 +389,20 @@ class Point:
|
|||
Cm Main frame coefficient.
|
||||
@note Moment is positive when produce positive trim.
|
||||
"""
|
||||
def __init__(self, ship, draft, trim):
|
||||
def __init__(self, ship, faces, draft, trim):
|
||||
""" Use all hydrostatics tools to define a hydrostatics
|
||||
point.
|
||||
@param ship Selected ship instance
|
||||
@param faces Ship external faces
|
||||
@param draft Draft.
|
||||
@param trim Trim in degrees.
|
||||
"""
|
||||
# Hydrostatics computation
|
||||
dispData = displacement(ship,draft,0.0,trim,0.0)
|
||||
wet = wettedArea(ship,draft,trim)
|
||||
if not faces:
|
||||
wet = 0.0
|
||||
else:
|
||||
wet = wettedArea(faces,draft,trim)
|
||||
mom = moment(ship,draft,trim,dispData[0],dispData[1].x)
|
||||
farea = FloatingArea(ship,draft,trim)
|
||||
bm = BMT(ship,draft,trim)
|
||||
|
|
Loading…
Reference in New Issue
Block a user