diff --git a/src/Mod/Ship/shipHydrostatics/Plot.py b/src/Mod/Ship/shipHydrostatics/Plot.py index 5e4f4d327..8d5338e10 100644 --- a/src/Mod/Ship/shipHydrostatics/Plot.py +++ b/src/Mod/Ship/shipHydrostatics/Plot.py @@ -60,6 +60,7 @@ class Plot(object): return ImageGui.open(self.path + 'volume.png') ImageGui.open(self.path + 'stability.png') + ImageGui.open(self.path + 'coeffs.png') def createDirectory(self): """ Create needed folder to write data and scripts. @@ -93,21 +94,24 @@ class Plot(object): Output.write(" #\n") Output.write(" # File automatically exported by FreeCAD-Ship\n") Output.write(" # This file contains transversal areas data, filled with following columns:\n") - Output.write(" # 1: Ship displacement [ton]\n") - Output.write(" # 2: Draft [m]\n") - Output.write(" # 3: Wetted surface [m2]\n") - Output.write(" # 4: 1cm triming ship moment [ton m]\n") - Output.write(" # 5: Bouyance center x coordinate\n") - Output.write(" # 6: Floating area\n") - Output.write(" # 7: KBt\n") - Output.write(" # 8: BMt\n") + Output.write(" # 1: Ship displacement [ton]\n") + Output.write(" # 2: Draft [m]\n") + Output.write(" # 3: Wetted surface [m2]\n") + Output.write(" # 4: 1cm triming ship moment [ton m]\n") + Output.write(" # 5: Bouyance center x coordinate\n") + Output.write(" # 6: Floating area\n") + Output.write(" # 7: KBt\n") + Output.write(" # 8: BMt\n") + Output.write(" # 9: Cb (block coefficient)\n") + Output.write(" # 10: Cf (Floating coefficient)\n") + Output.write(" # 11: Cm (Main frame coefficient)\n") Output.write(" #\n") Output.write(" #################################################################\n") # Print data for i in range(0,len(drafts)): draft = drafts[i] point = Tools.Point(ship,draft,trim) - string = "%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) + 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 Output.close() @@ -186,6 +190,21 @@ class Plot(object): Output.write(" '' using 6:1 title 'Floating area' axes x2y1 with lines style 2, \\\n") Output.write(" '' using 7:1 title '$KB_{T}$' axes x3y1 with lines style 3, \\\n") Output.write(" '' using 8:1 title '$BM_{T}$' axes x4y1 with lines style 4\n") + # Prepare third plot + Output.write("set output '%s'\n" % (self.path + 'coeffs.eps')) + Output.write("# X axis\n") + Output.write("set x2label '$C_{B}$'\n") + Output.write("set x2tic\n") + Output.write("set x3label '$C_{F}$'\n") + Output.write("set x3tic\n") + Output.write("set x4label '$C_{M}$'\n") + Output.write("set x4tic\n") + # Write plot call + Output.write("# Plot\n") + Output.write("plot '%s' using 2:1 title 'Draft' axes x1y1 with lines style 1, \\\n" % (self.dataFile)) + Output.write(" '' using 9:1 title '$C_{B}$' axes x2y1 with lines style 2, \\\n") + Output.write(" '' using 10:1 title '$C_{F}$' axes x3y1 with lines style 3, \\\n") + Output.write(" '' using 11:1 title '$C_{M}$' axes x4y1 with lines style 4\n") # Close file self.layoutFile = filename Output.close() @@ -204,7 +223,7 @@ class Plot(object): msg = Translator.translate("Plot will not generated\n") FreeCAD.Console.PrintError(msg) return True - # Convert volume + # Convert volume image comm = "gs -r300 -dEPSCrop -dTextAlphaBits=4 -sDEVICE=png16m -sOutputFile=%s.png -dBATCH -dNOPAUSE %s.eps" % (filename,filename) if os.system(comm): msg = Translator.translate("Can't execute ghostscript. Maybe is not installed?\n") @@ -212,9 +231,18 @@ class Plot(object): msg = Translator.translate("Generated image will not converted to png\n") FreeCAD.Console.PrintError(msg) return True - # Convert stability + # Convert stability image filename = self.path + 'stability' comm = "gs -r300 -dEPSCrop -dTextAlphaBits=4 -sDEVICE=png16m -sOutputFile=%s.png -dBATCH -dNOPAUSE %s.eps" % (filename,filename) + if os.system(comm): + msg = Translator.translate("Can't execute ghostscript. Maybe is not installed?\n") + FreeCAD.Console.PrintError(msg) + msg = Translator.translate("Generated image will not converted to png\n") + FreeCAD.Console.PrintError(msg) + return True + # Convert coefficients image + filename = self.path + 'coeffs' + comm = "gs -r300 -dEPSCrop -dTextAlphaBits=4 -sDEVICE=png16m -sOutputFile=%s.png -dBATCH -dNOPAUSE %s.eps" % (filename,filename) if os.system(comm): msg = Translator.translate("Can't execute ghostscript. Maybe is not installed?\n") FreeCAD.Console.PrintError(msg) diff --git a/src/Mod/Ship/shipHydrostatics/Tools.py b/src/Mod/Ship/shipHydrostatics/Tools.py index b36ed8d2e..a2b1f2c65 100644 --- a/src/Mod/Ship/shipHydrostatics/Tools.py +++ b/src/Mod/Ship/shipHydrostatics/Tools.py @@ -120,15 +120,19 @@ def Displacement(ship, draft, trim): areas : Area of each section \n disp: Ship displacement \n xcb: X bouyance center coordinate + Cb: Block coefficient """ angle = math.radians(trim) sections = Instance.sections(ship) xCoord = ship.xSection[:] + minX = None + maxX = None + maxY = 0.0 areas = [] vol = 0.0 moment = 0.0 if not sections: - return [[],0.0,0.0] + return [[],0.0,0.0,0.0] for i in range(0, len(sections)): # Get the section section = sections[i] @@ -143,7 +147,10 @@ def Displacement(ship, draft, trim): section = convertSection(section, x, Z) if not section: areas.append(0.0) - continue + continue + maxX = x + if not minX: + minX = x # Integrate area area = 0.0 for j in range(0, len(section)-1): @@ -164,6 +171,7 @@ def Displacement(ship, draft, trim): dy = 0.5*((y00 - y10) + (y01 - y11)) dz = 0.5*((z01 - z00) + (z11 - z10)) area = area + dy*dz + maxY = max([maxY,y00,y10,y01,y11]) if(len(section[j]) < len(section[j+1])): # y01,z01 ------- y11,z11 # | __/ @@ -180,6 +188,7 @@ def Displacement(ship, draft, trim): dy = y01 - y11 dz = z01 - z00 area = area + 0.5*dy*dz + maxY = max([maxY,y00,y01,y11]) elif(len(section[j]) > len(section[j+1])): # y01,z01 # | \__ @@ -196,6 +205,7 @@ def Displacement(ship, draft, trim): dy = y00 - y10 dz = z01 - z00 area = area + 0.5*dy*dz + maxY = max([maxY,y00,y10,y01]) elif(len(section[j]) == 1): # y1,z1 ------- # | @@ -210,6 +220,7 @@ def Displacement(ship, draft, trim): dy = 0.5 * (y0 + y1) dz = z1 - z0 area = area + dy*dz + maxY = max([maxY,y0,y1]) areas.append(2.0*area) # 2x because only half ship is represented # Add volume & moment if proceed if i > 0: @@ -219,11 +230,14 @@ def Displacement(ship, draft, trim): vol = vol + area*dx moment = moment + area*dx*x # Compute displacement and xcb - disp = vol / 1.025 # rho = 1.025 ton/m3 (salt water density) - xcb = 0.0 + disp = vol / 1.025 # rho = 1.025 ton/m3 (salt water density) + xcb = 0.0 + cb = 0.0 if vol > 0.0: xcb = moment / vol - return [areas,disp,xcb] + block = (maxX-minX)*2.0*maxY*draft + cb = vol / block + return [areas,disp,xcb,cb] def WettedArea(ship, draft, trim): """ Calculate wetted ship area. @@ -360,15 +374,19 @@ def FloatingArea(ship, draft, trim): @param ship Selected ship instance @param draft Draft. @param trim Trim in degrees. - @return Ship floating area. + @return Ship floating area, and floating coefficient. """ angle = math.radians(trim) sections = Instance.sections(ship) xCoord = ship.xSection[:] lines = [] area = 0.0 + minX = None + maxX = None + maxY = 0.0 + cf = 0.0 if not sections: - return 0.0 + return [0.0, 0.0] for i in range(0, len(sections)): # Get the section section = sections[i] @@ -384,6 +402,9 @@ def FloatingArea(ship, draft, trim): if not section: lines.append(0.0) continue + maxX = x + if not minX: + minX = x # Get floating line length line = 0.0 flag = True # Even lines compute for floating areas, odd no @@ -395,10 +416,12 @@ def FloatingArea(ship, draft, trim): y0 = abs(section[j][k-1].y) y1 = abs(section[j][k].y) line = line + (y1 - y0) + maxY = max([maxY,y1,y0]) flag = not flag if flag: # Central body computation lefts y = abs(section[j][0].y) line = line + y + maxY = max([maxY,y]) lines.append(2.0*line) # 2x because only half ship is represented # Add area if proceed if i > 0: @@ -406,7 +429,9 @@ def FloatingArea(ship, draft, trim): x = 0.5*(xCoord[i] + xCoord[i-1]) line = 0.5*(lines[i] + lines[i-1]) area = area + line*dx - return area + if area: + cf = area / ( (maxX-minX) * 2.0*maxY ) + return [area, cf] def KBT(ship, draft, trim, roll=0.0): """ Calculate ship Keel to Bouyance center transversal distance. @@ -699,6 +724,112 @@ def BMT(ship, draft, trim): BM = BM + 0.5*BB/math.tan(math.radians(0.5*roll)) / nRoll # nRoll is the weight function return BM +def MainFrameCoeff(ship, draft): + """ Calculate main frame coefficient. + @param ship Selected ship instance + @param draft Draft. + @return Main frame coefficient + """ + sections = Instance.sections(ship) + xCoord = ship.xSection[:] + cm = 0.0 + if not sections: + return 0.0 + # Look for nearest to main frame section + sectionID = 0 + X = xCoord[0] + for i in range(1, len(sections)): + # Get the position of the section + x = xCoord[i] + if abs(x) < abs(X): + sectionID = i + X = x + # Get the section + section = sections[sectionID] + if len(section) < 2: # Empty section + return 0.0 + x = X + # Get the maximum Z value + Z = draft + # Format section + section = convertSection(section, x, Z) + if not section: + return 0.0 + # Integrate area + area = 0.0 + maxY = 0.0 + 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 + maxY = max([maxY,y00,y10,y01,y11]) + 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 + maxY = max([maxY,y00,y01,y11]) + 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 + maxY = max([maxY,y00,y10,y01]) + 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 + maxY = max([maxY,y0,y1]) + if maxY*draft > 0.0: + cm = area / (maxY*draft) + return cm + class Point: """ Hydrostatics point, that conatins: \n draft Ship draft [m]. \n @@ -710,6 +841,9 @@ class Point: farea Floating area [m2]. KBt Transversal KB height [m]. BMt Transversal BM height [m]. + Cb Block coefficient. + Cf Floating coefficient. + Cm Main frame coefficient. @note Moment is positive when produce positive trim. """ def __init__(self, ship, draft, trim): @@ -726,13 +860,17 @@ class Point: farea = FloatingArea(ship,draft,trim) kb = KBT(ship,draft,trim) bm = BMT(ship,draft,trim) + cm = MainFrameCoeff(ship,draft) # Store final data self.draft = draft self.trim = trim self.disp = areasData[1] self.xcb = areasData[2] self.wet = wettedArea - self.farea = farea + self.farea = farea[0] self.mom = moment self.KBt = kb[1] self.BMt = bm + self.Cb = areasData[3] + self.Cf = farea[1] + self.Cm = cm