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.