diff --git a/src/Mod/Ship/CMakeLists.txt b/src/Mod/Ship/CMakeLists.txt index 7ddd6fc4a..10f63449c 100644 --- a/src/Mod/Ship/CMakeLists.txt +++ b/src/Mod/Ship/CMakeLists.txt @@ -80,6 +80,11 @@ SET(ShipCapacityCurve_SRCS ) SOURCE_GROUP("shipcapacitycurve" FILES ${ShipCapacityCurve_SRCS}) +SET(ShipCreateLoadCondition_SRCS + shipCreateLoadCondition/__init__.py +) +SOURCE_GROUP("shipcreateloadcondition" FILES ${ShipCreateLoadCondition_SRCS}) + SET(ShipGZ_SRCS shipGZ/__init__.py shipGZ/PlotAux.py @@ -97,7 +102,7 @@ SET(ShipUtils_SRCS ) SOURCE_GROUP("shiputils" FILES ${ShipUtils_SRCS}) -SET(all_files ${ShipMain_SRCS} ${ShipExamples_SRCS} ${ShipLoadExample_SRCS} ${ShipCreateShip_SRCS} ${ShipOutlineDraw_SRCS} ${ShipAreasCurve_SRCS} ${ShipHydrostatics_SRCS} ${ShipCreateWeight_SRCS} ${ShipCreateTank_SRCS} ${ShipCapacityCurve_SRCS} ${ShipGZ_SRCS} ${ShipUtils_SRCS}) +SET(all_files ${ShipMain_SRCS} ${ShipExamples_SRCS} ${ShipLoadExample_SRCS} ${ShipCreateShip_SRCS} ${ShipOutlineDraw_SRCS} ${ShipAreasCurve_SRCS} ${ShipHydrostatics_SRCS} ${ShipCreateWeight_SRCS} ${ShipCreateTank_SRCS} ${ShipCapacityCurve_SRCS} ${ShipCreateLoadCondition_SRCS} ${ShipGZ_SRCS} ${ShipUtils_SRCS}) ADD_CUSTOM_TARGET(Ship ALL SOURCES ${all_files} ${Ship_QRC_SRCS} @@ -164,6 +169,12 @@ INSTALL( DESTINATION Mod/Ship/shipCapacityCurve ) +INSTALL( + FILES + ${ShipCreateLoadCondition_SRCS} + DESTINATION + Mod/Ship/shipCreateLoadCondition +) INSTALL( FILES ${ShipGZ_SRCS} diff --git a/src/Mod/Ship/InitGui.py b/src/Mod/Ship/InitGui.py index 832cb57d3..04ffd62fa 100644 --- a/src/Mod/Ship/InitGui.py +++ b/src/Mod/Ship/InitGui.py @@ -53,6 +53,7 @@ class ShipWorkbench(Workbench): weightslist = ["Ship_Weight", "Ship_Tank", "Ship_Capacity", + "Ship_LoadCondition", "Ship_GZ"] self.appendToolbar( diff --git a/src/Mod/Ship/Instance.py b/src/Mod/Ship/Instance.py index 0f4b0b81e..03ccf9503 100644 --- a/src/Mod/Ship/Instance.py +++ b/src/Mod/Ship/Instance.py @@ -109,6 +109,15 @@ class Ship: "Tanks", "Ship", tooltip).Tanks = [] + tooltip = str(QtGui.QApplication.translate( + "Ship", + "Set of load conditions", + None, + QtGui.QApplication.UnicodeUTF8)) + obj.addProperty("App::PropertyStringList", + "LoadConditions", + "Ship", + tooltip).LoadConditions = [] obj.Proxy = self diff --git a/src/Mod/Ship/ShipGui.py b/src/Mod/Ship/ShipGui.py index d179fdae9..881157c2c 100644 --- a/src/Mod/Ship/ShipGui.py +++ b/src/Mod/Ship/ShipGui.py @@ -170,6 +170,23 @@ class TankCapacity: 'ToolTip': ToolTip} +class LoadCondition: + def Activated(self): + import shipCreateLoadCondition + shipCreateLoadCondition.load() + + def GetResources(self): + MenuText = QtCore.QT_TRANSLATE_NOOP( + 'ship_loadcondition', + 'Create a new loading condition') + ToolTip = QtCore.QT_TRANSLATE_NOOP( + 'ship_loadcondition', + 'Create a new load condition spreadsheet') + return {'Pixmap': 'Ship_LoadCondition', + 'MenuText': MenuText, + 'ToolTip': ToolTip} + + class GZ: def Activated(self): import shipGZ @@ -195,4 +212,5 @@ FreeCADGui.addCommand('Ship_Hydrostatics', Hydrostatics()) FreeCADGui.addCommand('Ship_Weight', CreateWeight()) FreeCADGui.addCommand('Ship_Tank', CreateTank()) FreeCADGui.addCommand('Ship_Capacity', TankCapacity()) +FreeCADGui.addCommand('Ship_LoadCondition', LoadCondition()) FreeCADGui.addCommand('Ship_GZ', GZ()) diff --git a/src/Mod/Ship/resources/Ship.qrc b/src/Mod/Ship/resources/Ship.qrc index 9ed0d300b..f3bb5a50f 100644 --- a/src/Mod/Ship/resources/Ship.qrc +++ b/src/Mod/Ship/resources/Ship.qrc @@ -6,6 +6,7 @@ icons/Ship_GZ.svg icons/Ship_Hydrostatics.svg icons/Ship_Load.svg + icons/Ship_LoadCondition.svg icons/Ship_Logo.svg icons/Ship_Module.svg icons/Ship_OutlineDraw.svg diff --git a/src/Mod/Ship/resources/icons/Ship_LoadCondition.svg b/src/Mod/Ship/resources/icons/Ship_LoadCondition.svg new file mode 100644 index 000000000..b6f7df03d --- /dev/null +++ b/src/Mod/Ship/resources/icons/Ship_LoadCondition.svg @@ -0,0 +1,660 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TF + F + T + S + W + WNA + + + + diff --git a/src/Mod/Ship/shipCreateLoadCondition/__init__.py b/src/Mod/Ship/shipCreateLoadCondition/__init__.py new file mode 100644 index 000000000..0f5bdc2fb --- /dev/null +++ b/src/Mod/Ship/shipCreateLoadCondition/__init__.py @@ -0,0 +1,130 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* This program is distributed in the hope that it will be useful, * +#* but WITHOUT ANY WARRANTY; without even the implied warranty of * +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +#* GNU Library General Public License for more details. * +#* * +#* You should have received a copy of the GNU Library General Public * +#* License along with this program; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#*************************************************************************** + +import FreeCAD as App +import FreeCADGui as Gui +import Spreadsheet + + +def load(): + """Directly create the load condition""" + # Check that a ship has been selected + ship = None + selObjs = Gui.Selection.getSelection() + if not selObjs: + msg = QtGui.QApplication.translate( + "ship_console", + "A ship instance must be selected before using this tool (no" + " objects selected)", + None, + QtGui.QApplication.UnicodeUTF8) + App.Console.PrintError(msg + '\n') + return + for i in range(len(selObjs)): + obj = selObjs[i] + props = obj.PropertiesList + try: + props.index("IsShip") + except ValueError: + continue + if obj.IsShip: + if ship: + msg = QtGui.QApplication.translate( + "ship_console", + "More than one ship have been selected (the extra" + " ships will be ignored)", + None, + QtGui.QApplication.UnicodeUTF8) + App.Console.PrintWarning(msg + '\n') + break + ship = obj + + if not ship: + msg = QtGui.QApplication.translate( + "ship_console", + "A ship instance must be selected before using this tool (no" + " valid ship found at the selected objects)", + None, + QtGui.QApplication.UnicodeUTF8) + App.Console.PrintError(msg + '\n') + return + + # Create the spreadsheet + s = App.activeDocument().addObject('Spreadsheet::Sheet', + 'LoadCondition') + + # Add a reference to the owner ship + s.mergeCells('A1:D1') + s.setAlignment('A1:A1', 'center', 'keep') + s.setStyle('A1:A1', 'bold', 'add') + s.setStyle('A1:A1', 'underline', 'add') + s.set("A1", "SHIP") + s.set("A2", "ship") + s.set("A3", ship.Label) + s.set("B2", "internal ref") + s.set("B3", ship.Name) + s.setForeground('A1:B3', (0.5,0.5,0.5)) + + # Add the weights data + s.mergeCells('A4:D4') + s.setAlignment('A4:A4', 'center', 'keep') + s.setStyle('A4:A4', 'bold', 'add') + s.setStyle('A4:A4', 'underline', 'add') + s.set("A4", "WEIGHTS") + s.set("A5", "weight") + s.set("B5", "internal ref") + for i in range(len(ship.Weights)): + weight = App.activeDocument().getObject(ship.Weights[i]) + s.set("A{}".format(i + 6), weight.Label) + s.set("B{}".format(i + 6), weight.Name) + s.setForeground('A4:B{}'.format(5 + len(ship.Weights)), (0.5,0.5,0.5)) + + # Add the tanks data + s.mergeCells('A{0}:D{0}'.format(6 + len(ship.Weights))) + s.setAlignment('A{0}:A{0}'.format(6 + len(ship.Weights)), 'center', 'keep') + s.setStyle('A{0}:A{0}'.format(6 + len(ship.Weights)), 'bold', 'add') + s.setStyle('A{0}:A{0}'.format(6 + len(ship.Weights)), 'underline', 'add') + s.set("A{}".format(6 + len(ship.Weights)), "TANKS") + s.set("A{}".format(7 + len(ship.Weights)), "tank") + s.set("B{}".format(7 + len(ship.Weights)), "internal ref") + s.set("C{}".format(7 + len(ship.Weights)), "Fluid density [kg/m^3]") + s.set("D{}".format(7 + len(ship.Weights)), "Filling ratio") + for i in range(len(ship.Tanks)): + tank = App.activeDocument().getObject(ship.Tanks[i]) + s.set("A{}".format(i + 8 + len(ship.Weights)), tank.Label) + s.set("B{}".format(i + 8 + len(ship.Weights)), tank.Name) + s.set("C{}".format(i + 8 + len(ship.Weights)), "998.0") + s.set("D{}".format(i + 8 + len(ship.Weights)), "0.0") + s.setForeground('A{0}:A{0}'.format(6 + len(ship.Weights)), (0.5,0.5,0.5)) + s.setForeground('A{0}:D{0}'.format(7 + len(ship.Weights)), (0.5,0.5,0.5)) + s.setForeground('A{}:B{}'.format(8 + len(ship.Weights), + 8 + len(ship.Weights) + len(ship.Tanks)), + (0.5,0.5,0.5)) + + # Add the spreadsheet to the list of loading conditions of the ship + lcs = ship.LoadConditions[:] + lcs.append(s.Name) + ship.LoadConditions = lcs + + # Recompute to take the changes + App.activeDocument().recompute() \ No newline at end of file diff --git a/src/Mod/Ship/shipGZ/TaskPanel.py b/src/Mod/Ship/shipGZ/TaskPanel.py index 787bb2dc0..d40b163de 100644 --- a/src/Mod/Ship/shipGZ/TaskPanel.py +++ b/src/Mod/Ship/shipGZ/TaskPanel.py @@ -26,51 +26,17 @@ import FreeCAD as App import FreeCADGui as Gui import Units from PySide import QtGui, QtCore -import Preview import PlotAux -import Instance from shipUtils import Paths import shipUtils.Units as USys import shipUtils.Locale as Locale -from shipHydrostatics import Tools as Hydrostatics class TaskPanel: def __init__(self): - self.ui = Paths.modulePath() + "/shipAreasCurve/TaskPanel.ui" - self.preview = Preview.Preview() - self.ship = None + self.ui = Paths.modulePath() + "/shipGZ/TaskPanel.ui" def accept(self): - if not self.ship: - return False - self.save() - # Plot data - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.draft = self.widget(QtGui.QLineEdit, "Draft") - form.trim = self.widget(QtGui.QLineEdit, "Trim") - draft = Units.Quantity(Locale.fromString( - form.draft.text())).getValueAs('m').Value - trim = Units.Quantity(Locale.fromString( - form.trim.text())).getValueAs('deg').Value - data = Hydrostatics.displacement(self.ship, - draft, - 0.0, - trim) - disp = data[0] - xcb = data[1].x - data = Hydrostatics.areas(self.ship, - draft, - 0.0, - trim) - x = [] - y = [] - for i in range(0, len(data)): - x.append(data[i][0]) - y.append(data[i][1]) - PlotAux.Plot(x, y, disp, xcb, self.ship) - self.preview.clean() return True def reject(self): @@ -102,20 +68,14 @@ class TaskPanel: mw = self.getMainWindow() form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.draft = self.widget(QtGui.QLineEdit, "Draft") - form.trim = self.widget(QtGui.QLineEdit, "Trim") - form.output = self.widget(QtGui.QTextEdit, "OutputData") - form.doc = QtGui.QTextDocument(form.output) + form.angle = self.widget(QtGui.QLineEdit, "Angle") + form.n_points = self.widget(QtGui.QSpinBox, "NPoints") + form.var_draft = self.widget(QtGui.QCheckBox, "VariableDraft") + form.var_trim = self.widget(QtGui.QCheckBox, "VariableTrim") self.form = form if self.initValues(): return True self.retranslateUi() - QtCore.QObject.connect(form.draft, - QtCore.SIGNAL("valueChanged(double)"), - self.onData) - QtCore.QObject.connect(form.trim, - QtCore.SIGNAL("valueChanged(double)"), - self.onData) def getMainWindow(self): toplevel = QtGui.qApp.topLevelWidgets() @@ -138,75 +98,6 @@ class TaskPanel: def initValues(self): """ Set initial values for fields """ - selObjs = Gui.Selection.getSelection() - if not selObjs: - msg = QtGui.QApplication.translate( - "ship_console", - "A ship instance must be selected before using this tool (no" - " objects selected)", - None, - QtGui.QApplication.UnicodeUTF8) - App.Console.PrintError(msg + '\n') - return True - for i in range(0, len(selObjs)): - obj = selObjs[i] - props = obj.PropertiesList - try: - props.index("IsShip") - except ValueError: - continue - if obj.IsShip: - if self.ship: - msg = QtGui.QApplication.translate( - "ship_console", - "More than one ship have been selected (the extra" - " ships will be ignored)", - None, - QtGui.QApplication.UnicodeUTF8) - App.Console.PrintWarning(msg + '\n') - break - self.ship = obj - if not self.ship: - msg = QtGui.QApplication.translate( - "ship_console", - "A ship instance must be selected before using this tool (no" - " valid ship found at the selected objects)", - None, - QtGui.QApplication.UnicodeUTF8) - App.Console.PrintError(msg + '\n') - return True - - length_format = USys.getLengthFormat() - angle_format = USys.getAngleFormat() - - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.draft = self.widget(QtGui.QLineEdit, "Draft") - form.trim = self.widget(QtGui.QLineEdit, "Trim") - form.draft.setText(Locale.toString(length_format.format( - self.ship.Draft.getValueAs(USys.getLengthUnits()).Value))) - form.trim.setText(Locale.toString(angle_format.format(0.0))) - # Try to use saved values - props = self.ship.PropertiesList - try: - props.index("AreaCurveDraft") - form.draft.setText(Locale.toString(length_format.format( - self.ship.AreaCurveDraft.getValueAs( - USys.getLengthUnits()).Value))) - except: - pass - try: - props.index("AreaCurveTrim") - form.trim.setText(Locale.toString(angle_format.format( - self.ship.AreaCurveTrim.getValueAs( - USys.getAngleUnits()).Value))) - except ValueError: - pass - # Update GUI - draft = Units.Quantity(form.draft.text()).getValueAs('m').Value - trim = Units.Quantity(form.trim.text()).getValueAs('deg').Value - self.preview.update(draft, trim, self.ship) - self.onUpdate() return False def retranslateUi(self): @@ -214,178 +105,34 @@ class TaskPanel: mw = self.getMainWindow() form = mw.findChild(QtGui.QWidget, "TaskPanel") form.setWindowTitle(QtGui.QApplication.translate( - "ship_areas", - "Plot the transversal areas curve", + "ship_gz", + "Plot the GZ curve", None, QtGui.QApplication.UnicodeUTF8)) - self.widget(QtGui.QLabel, "DraftLabel").setText( + self.widget(QtGui.QLabel, "AngleLabel").setText( QtGui.QApplication.translate( - "ship_areas", - "Draft", + "ship_gz", + "Angle", None, QtGui.QApplication.UnicodeUTF8)) - self.widget(QtGui.QLabel, "TrimLabel").setText( + self.widget(QtGui.QLabel, "NPointsLabel").setText( QtGui.QApplication.translate( - "ship_areas", - "Trim", + "ship_gz", + "Number of points", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QCheckBox, "VariableDraft").setText( + QtGui.QApplication.translate( + "ship_gz", + "Variable draft", + None, + QtGui.QApplication.UnicodeUTF8)) + self.widget(QtGui.QCheckBox, "VariableTrim").setText( + QtGui.QApplication.translate( + "ship_gz", + "Variable trim", None, QtGui.QApplication.UnicodeUTF8)) - - def clampLength(self, widget, val_min, val_max, val): - if val >= val_min and val <= val_max: - return val - input_format = USys.getLengthFormat() - val = min(val_max, max(val_min, val)) - qty = Units.Quantity('{} m'.format(val)) - widget.setText(Locale.toString(input_format.format( - qty.getValueAs(USys.getLengthUnits()).Value))) - return val - - def clampAngle(self, widget, val_min, val_max, val): - if val >= val_min and val <= val_max: - return val - input_format = USys.getAngleFormat() - val = min(val_max, max(val_min, val)) - qty = Units.Quantity('{} deg'.format(val)) - widget.setText(Locale.toString(input_format.format( - qty.getValueAs(USys.getLengthUnits()).Value))) - return val - - def onData(self, value): - """ Method called when the tool input data is touched. - @param value Changed value. - """ - if not self.ship: - return - - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.draft = self.widget(QtGui.QLineEdit, "Draft") - form.trim = self.widget(QtGui.QLineEdit, "Trim") - - # Get the values (or fix them in bad setting case) - try: - draft = Units.Quantity(Locale.fromString( - form.draft.text())).getValueAs('m').Value - except: - draft = self.ship.Draft.getValueAs(USys.getLengthUnits()).Value - input_format = USys.getLengthFormat() - qty = Units.Quantity('{} m'.format(draft)) - widget.setText(Locale.toString(input_format.format( - qty.getValueAs(USys.getLengthUnits()).Value))) - try: - trim = Units.Quantity(Locale.fromString( - form.trim.text())).getValueAs('deg').Value - except: - trim = 0.0 - input_format = USys.getAngleFormat() - qty = Units.Quantity('{} deg'.format(trim)) - widget.setText(Locale.toString(input_format.format( - qty.getValueAs(USys.getLengthUnits()).Value))) - - bbox = self.ship.Shape.BoundBox - draft_min = bbox.ZMin / Units.Metre.Value - draft_max = bbox.ZMax / Units.Metre.Value - draft = self.clampLength(form.draft, draft_min, draft_max, draft) - - trim_min = -180.0 - trim_max = 180.0 - trim = self.clampAngle(form.trim, trim_min, trim_max, trim) - - self.onUpdate() - self.preview.update(draft, trim, self.ship) - - def onUpdate(self): - """ Method called when the data update is requested. """ - if not self.ship: - return - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.draft = self.widget(QtGui.QLineEdit, "Draft") - form.trim = self.widget(QtGui.QLineEdit, "Trim") - form.output = self.widget(QtGui.QTextEdit, "OutputData") - - draft = Units.Quantity(Locale.fromString( - form.draft.text())).getValueAs('m').Value - trim = Units.Quantity(Locale.fromString( - form.trim.text())).getValueAs('deg').Value - - # Calculate the drafts at each perpendicular - angle = math.radians(trim) - L = self.ship.Length.getValueAs('m').Value - B = self.ship.Breadth.getValueAs('m').Value - draftAP = draft + 0.5 * L * math.tan(angle) - if draftAP < 0.0: - draftAP = 0.0 - draftFP = draft - 0.5 * L * math.tan(angle) - if draftFP < 0.0: - draftFP = 0.0 - # Calculate the involved hydrostatics - data = Hydrostatics.displacement(self.ship, - draft, - 0.0, - trim) - # Setup the html string - string = 'L = {0} [m]
'.format(L) - string = string + 'B = {0} [m]
'.format(B) - string = string + 'T = {0} [m]
'.format(draft) - string = string + 'Trim = {0} [degrees]
'.format(trim) - string = string + 'TAP = {0} [m]
'.format(draftAP) - string = string + 'TFP = {0} [m]
'.format(draftFP) - dispText = QtGui.QApplication.translate( - "ship_areas", - 'Displacement', - None, - QtGui.QApplication.UnicodeUTF8) - string = string + dispText + ' = {0} [ton]
'.format(data[0]) - string = string + 'XCB = {0} [m]'.format(data[1].x) - form.output.setHtml(string) - - def save(self): - """ Saves the data into ship instance. """ - mw = self.getMainWindow() - form = mw.findChild(QtGui.QWidget, "TaskPanel") - form.draft = self.widget(QtGui.QLineEdit, "Draft") - form.trim = self.widget(QtGui.QLineEdit, "Trim") - - draft = Units.Quantity(Locale.fromString( - form.draft.text())).getValueAs('m').Value - trim = Units.Quantity(Locale.fromString( - form.trim.text())).getValueAs('deg').Value - - props = self.ship.PropertiesList - try: - props.index("AreaCurveDraft") - except ValueError: - try: - tooltip = str(QtGui.QApplication.translate( - "ship_areas", - "Areas curve tool draft selected [m]", - None, - QtGui.QApplication.UnicodeUTF8)) - except: - tooltip = "Areas curve tool draft selected [m]" - self.ship.addProperty("App::PropertyLength", - "AreaCurveDraft", - "Ship", - tooltip) - self.ship.AreaCurveDraft = '{} m'.format(draft) - try: - props.index("AreaCurveTrim") - except ValueError: - try: - tooltip = str(QtGui.QApplication.translate( - "ship_areas", - "Areas curve tool trim selected [deg]", - None, - QtGui.QApplication.UnicodeUTF8)) - except: - tooltip = "Areas curve tool trim selected [deg]" - self.ship.addProperty("App::PropertyAngle", - "AreaCurveTrim", - "Ship", - tooltip) - self.ship.AreaCurveTrim = '{} deg'.format(trim) def createTask(): @@ -394,4 +141,4 @@ def createTask(): if panel.setupUi(): Gui.Control.closeDialog(panel) return None - return panel + return panel \ No newline at end of file