External faces detection implemented that allows to compute wetted area.

This commit is contained in:
Jose Luis Cercós pita 2012-06-15 11:35:30 +02:00
parent c524a0268a
commit 6c1158e2e9
4 changed files with 109 additions and 89 deletions

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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)