Пример #1
0
    def onData(self, value):
        """ Method called when input data is changed.
         @param value Changed value.
        """
        min_draft = Units.parseQuantity(
            Locale.fromString(self.form.min_draft.text()))
        max_draft = Units.parseQuantity(
            Locale.fromString(self.form.max_draft.text()))
        trim = Units.parseQuantity(Locale.fromString(self.form.trim.text()))
        if min_draft.Unit != Units.Length or \
            max_draft.Unit != Units.Length or \
            trim.Unit != Units.Angle:
            return

        # Clamp the values to the bounds
        bbox = self.ship.Shape.BoundBox
        draft_min = Units.Quantity(bbox.ZMin, Units.Length)
        draft_max = Units.Quantity(bbox.ZMax, Units.Length)
        min_draft = self.clampValue(self.form.min_draft, draft_min, draft_max,
                                    min_draft)
        max_draft = self.clampValue(self.form.max_draft, draft_min, draft_max,
                                    max_draft)
        # Check that the minimum value is lower than
        # the maximum one
        min_draft = self.clampValue(self.form.min_draft, draft_min, max_draft,
                                    min_draft)

        # Clamp the trim angle to sensible values
        trim = self.clampValue(self.form.trim, Units.parseQuantity("-90 deg"),
                               Units.parseQuantity("90 deg"), trim)
Пример #2
0
    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.parseQuantity(Locale.fromString(form.draft.text()))
        except:
            draft = self.ship.Draft
            form.draft.setText(draft.UserString)
        try:
            trim = Units.parseQuantity(Locale.fromString(form.trim.text()))
        except:
            trim = Units.parseQuantity("0 deg")
            form.trim.setText(trim.UserString)

        bbox = self.ship.Shape.BoundBox
        draft_min = Units.Quantity(bbox.ZMin, Units.Length)
        draft_max = Units.Quantity(bbox.ZMax, Units.Length)
        draft = self.clampValue(form.draft, draft_min, draft_max, draft)

        trim_min = Units.parseQuantity("-180 deg")
        trim_max = Units.parseQuantity("180 deg")
        trim = self.clampValue(form.trim, trim_min, trim_max, trim)

        self.onUpdate()
        self.preview.update(draft, trim, self.ship)
Пример #3
0
    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")
        form.num = self.widget(QtGui.QSpinBox, "Num")
        draft = Units.parseQuantity(Locale.fromString(form.draft.text()))
        trim = Units.parseQuantity(Locale.fromString(form.trim.text()))
        num = form.num.value()

        disp, B, _ = Hydrostatics.displacement(self.ship,
                                               draft,
                                               Units.parseQuantity("0 deg"),
                                               trim)
        xcb = Units.Quantity(B.x, Units.Length)
        data = Hydrostatics.areas(self.ship,
                                  num,
                                  draft=draft,
                                  trim=trim)
        x = []
        y = []
        for i in range(0, len(data)):
            x.append(data[i][0].getValueAs("m").Value)
            y.append(data[i][1].getValueAs("m^2").Value)
        PlotAux.Plot(x, y, disp, xcb, self.ship)
        self.preview.clean()
        return True
Пример #4
0
def tankCapacityCurve(tank, n):
    """Create a tank capacity curve

    Position arguments:
    tank -- Tank object (see createTank)
    ship -- n Number of filling levels to test

    Returned value:
    List of computed points. Each point contains the filling level percentage
    (interval [0, 1]), the filling level (0 for the bottom of the tank), and
    the volume.
    """
    bbox = tank.Shape.BoundBox
    dz = Units.Quantity(bbox.ZMax - bbox.ZMin, Units.Length)
    dlevel = 1.0 / (n - 1)
    out = [(0.0, Units.parseQuantity("0 m"), Units.parseQuantity("0 m^3"))]

    msg = QtGui.QApplication.translate("ship_console",
                                       "Computing capacity curve", None)
    App.Console.PrintMessage(msg + '...\n')
    for i in range(1, n):
        App.Console.PrintMessage("\t{} / {}\n".format(i + 1, n))
        level = i * dlevel
        vol = tank.Proxy.getVolume(tank, level)
        out.append((level, level * dz, vol))
    return out
Пример #5
0
    def getMoment(self, fp):
        """Compute the mass of the object, already taking into account the
        type of subentities.

        Position arguments:
        fp -- Part::FeaturePython object affected.

        Returned value:
        List of moments toward x, y and z
        """
        m = [
            Units.parseQuantity('0 kg*m'),
            Units.parseQuantity('0 kg*m'),
            Units.parseQuantity('0 kg*m')
        ]
        for s in fp.Shape.Solids:
            mom = self._getVolumetricMoment(fp, s)
            for i in range(len(m)):
                m[i] = m[i] + mom[i]
        for f in fp.Shape.Faces:
            mom = self._getAreaMoment(fp, f)
            for i in range(len(m)):
                m[i] = m[i] + mom[i]
        for e in fp.Shape.Edges:
            mom = self._getLinearMoment(fp, e)
            for i in range(len(m)):
                m[i] = m[i] + mom[i]
        for v in fp.Shape.Vertexes:
            mom = self._getPuntualMoment(fp, v)
            for i in range(len(m)):
                m[i] = m[i] + mom[i]
        return m
Пример #6
0
def cog(lc, roll=Units.parseQuantity("0 deg"),
            trim=Units.parseQuantity("0 deg")):
    """Compute the center of gravity in the upright ship reference system

    Position arguments:
    lc -- The load condition

    Keyword arguments:
    roll -- The roll angle
    trim -- The trim angle

    Returns:
    The center of gravity and the total weight (In Newtons)
    """
    cog, w = GZ.weights_cog(get_lc_weights(lc))
    # Add the tanks effect
    tw = Units.parseQuantity("0 kg")
    mom_x = Units.Quantity(cog.x, Units.Length) * w
    mom_y = Units.Quantity(cog.y, Units.Length) * w
    mom_z = Units.Quantity(cog.z, Units.Length) * w
    for t, dens, level in get_lc_tanks(lc):        
        vol = t.Proxy.getVolume(t, level)
        t_weight = vol * dens * GZ.G
        t_cog = t.Proxy.getCoG(t, vol, roll, trim)
        mom_x += Units.Quantity(t_cog.x, Units.Length) * t_weight
        mom_y += Units.Quantity(t_cog.y, Units.Length) * t_weight
        mom_z += Units.Quantity(t_cog.z, Units.Length) * t_weight
        tw += vol * dens
    w += tw * GZ.G

    return Vector(mom_x / w, mom_y / w, mom_z / w), w
Пример #7
0
def moment(ship, draft=None,
                 roll=Units.parseQuantity("0 deg"),
                 trim=Units.parseQuantity("0 deg")):
    """Compute the moment required to trim the ship 1cm

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    Moment required to trim the ship 1cm. Such moment is positive if it cause a
    positive trim angle. The moment is expressed as a mass by a distance, not as
    a force by a distance
    """
    disp_orig, B_orig, _ = displacement(ship, draft, roll, trim)
    xcb_orig = Units.Quantity(B_orig.x, Units.Length)

    factor = 10.0
    x = 0.5 * ship.Length.getValueAs('cm').Value
    y = 1.0
    angle = math.atan2(y, x) * Units.Radian
    trim_new = trim + factor * angle
    disp_new, B_new, _ = displacement(ship, draft, roll, trim_new)
    xcb_new = Units.Quantity(B_new.x, Units.Length)

    mom0 = -disp_orig * xcb_orig
    mom1 = -disp_new * xcb_new
    return (mom1 - mom0) / factor
Пример #8
0
def wettedArea(shape,
               draft,
               roll=Units.parseQuantity("0 deg"),
               trim=Units.parseQuantity("0 deg")):
    """Compute the ship wetted area

    Position arguments:
    shape -- External faces of the ship hull
    draft -- Ship draft

    Keyword arguments:
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    The wetted area, i.e. The underwater surface area
    """
    shape, _ = placeShipShape(shape.copy(), draft, roll, trim)
    shape = getUnderwaterSide(shape, force=False)
    submerged_length = shape.BoundBox.ZLength

    area = 0.0
    for f in shape.Faces:
        if f.BoundBox.ZLength < 0.01 * submerged_length and \
           abs(f.BoundBox.ZMin) < 0.01 * submerged_length:
            # Discard the eventual intersections with the free surface
            continue
        area = area + f.Area
    return Units.Quantity(area, Units.Area)
Пример #9
0
    def onUpdate(self):
        """ Method called when the data update is requested. """
        if not self.ship:
            return
        draft = Units.parseQuantity(Locale.fromString(self.form.draft.text()))
        trim = Units.parseQuantity(Locale.fromString(self.form.trim.text()))

        # Calculate the drafts at each perpendicular
        angle = trim.getValueAs("rad").Value
        draftAP = draft + 0.5 * self.ship.Length * math.tan(angle)
        if draftAP < 0.0:
            draftAP = 0.0
        draftFP = draft - 0.5 * self.ship.Length * math.tan(angle)
        if draftFP < 0.0:
            draftFP = 0.0
        # Calculate the involved hydrostatics
        disp, B, _ = Hydrostatics.displacement(self.ship, draft,
                                               Units.parseQuantity("0 deg"),
                                               trim)
        xcb = Units.Quantity(B.x, Units.Length)
        # Setup the html string
        string = u'L = {0}<BR>'.format(self.ship.Length.UserString)
        string += u'B = {0}<BR>'.format(self.ship.Breadth.UserString)
        string += u'T = {0}<HR>'.format(draft.UserString)
        string += u'Trim = {0}<BR>'.format(trim.UserString)
        string += u'T<sub>AP</sub> = {0}<BR>'.format(draftAP.UserString)
        string += u'T<sub>FP</sub> = {0}<HR>'.format(draftFP.UserString)
        string += u'&#916; = {0}<BR>'.format(disp.UserString)
        string += u'XCB = {0}'.format(xcb.UserString)
        self.form.output_data.setHtml(string)
Пример #10
0
    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")
        form.num = self.widget(QtGui.QSpinBox, "Num")

        draft = Units.parseQuantity(Locale.fromString(form.draft.text()))
        trim = Units.parseQuantity(Locale.fromString(form.trim.text()))
        num = form.num.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))
            except:
                tooltip = "Areas curve tool draft selected [m]"
            self.ship.addProperty("App::PropertyLength",
                                  "AreaCurveDraft",
                                  "Ship",
                                  tooltip)
        self.ship.AreaCurveDraft = draft
        try:
            props.index("AreaCurveTrim")
        except ValueError:
            try:
                tooltip = str(QtGui.QApplication.translate(
                    "ship_areas",
                    "Areas curve tool trim selected [deg]",
                    None))
            except:
                tooltip = "Areas curve tool trim selected [deg]"
            self.ship.addProperty("App::PropertyAngle",
                                  "AreaCurveTrim",
                                  "Ship",
                                  tooltip)
        self.ship.AreaCurveTrim = trim
        try:
            props.index("AreaCurveNum")
        except ValueError:
            try:
                tooltip = str(QtGui.QApplication.translate(
                    "ship_areas",
                    "Areas curve tool number of points",
                    None))
            except:
                tooltip = "Areas curve tool number of points"
            self.ship.addProperty("App::PropertyInteger",
                                  "AreaCurveNum",
                                  "Ship",
                                  tooltip)
        self.ship.AreaCurveNum = num
Пример #11
0
def solve(ship, weights, tanks, rolls, var_trim=True):
    """Compute the ship GZ stability curve

    Position arguments:
    ship -- Ship object
    weights -- List of weights to consider
    tanks -- List of tanks to consider (each one should be a tuple with the
    tank instance, the density of the fluid inside, and the filling level ratio)
    rolls -- List of roll angles

    Keyword arguments:
    var_trim -- True if the equilibrium trim should be computed for each roll
    angle, False if null trim angle can be used instead.

    Returned value:
    List of GZ curve points. Each point contains the GZ stability length, the
    equilibrium draft, and the equilibrium trim angle (0 deg if var_trim is
    False)
    """
    # Get the unloaded weight (ignoring the tanks for the moment).
    W = Units.parseQuantity("0 kg")
    mom_x = Units.parseQuantity("0 kg*m")
    mom_y = Units.parseQuantity("0 kg*m")
    mom_z = Units.parseQuantity("0 kg*m")
    for w in weights:
        W += w.Proxy.getMass(w)
        m = w.Proxy.getMoment(w)
        mom_x += m[0]
        mom_y += m[1]
        mom_z += m[2]
    COG = Vector(mom_x / W, mom_y / W, mom_z / W)
    W = W * G

    # Get the tanks weight
    TW = Units.parseQuantity("0 kg")
    VOLS = []
    for t in tanks:
        # t[0] = tank object
        # t[1] = load density
        # t[2] = filling level
        vol = t[0].Proxy.getVolume(t[0], t[2])
        VOLS.append(vol)
        TW += vol * t[1]
    TW = TW * G

    points = []
    for i,roll in enumerate(rolls):
        App.Console.PrintMessage("{0} / {1}\n".format(i + 1, len(rolls)))
        point = solve_point(W, COG, TW, VOLS,
                            ship, tanks, roll, var_trim)
        if point is None:
            return []
        points.append(point)

    return points
Пример #12
0
def weights_cog(weights):
    W = Units.parseQuantity("0 kg")
    mom_x = Units.parseQuantity("0 kg*m")
    mom_y = Units.parseQuantity("0 kg*m")
    mom_z = Units.parseQuantity("0 kg*m")
    for w in weights:
        W += w.Proxy.getMass(w)
        m = w.Proxy.getMoment(w)
        mom_x += m[0]
        mom_y += m[1]
        mom_z += m[2]
    W = W
    return Vector(mom_x / W, mom_y / W, mom_z / W), W * G
Пример #13
0
    def accept(self):
        """Compute the RAOs and plot them"""
        if not self.lc:
            return False
        if self.running:
            return
        self.form.group_pbar.show()

        min_period = Units.parseQuantity(self.form.min_period.text())
        max_period = Units.parseQuantity(self.form.max_period.text())
        n_period = self.form.n_period.value()
        periods = [min_period + (max_period - min_period) * i / (n_period - 1) \
            for i in range(n_period)]
        omegas = [2.0 * np.pi / T.getValueAs('s').Value for T in periods]

        # Generate the simulations
        sims = Tools.simulation(self.lc, self.ship, self.weights, self.tanks,
                                self.mesh, omegas)

        # Start solving the problems
        self.loop = QtCore.QEventLoop()
        self.timer = QtCore.QTimer()
        self.timer.setSingleShot(True)
        QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"),
                               self.loop, QtCore.SLOT("quit()"))
        self.running = True
        n = len(periods) * len(Tools.DIRS)
        self.form.pbar.setMinimum(0)
        self.form.pbar.setMaximum(n)
        self.form.pbar.setValue(0)
        msg = QtGui.QApplication.translate("ship_console", "Computing RAOs",
                                           None)
        App.Console.PrintMessage(msg + '...\n')
        points = []
        plts = {}
        for dof in Tools.DOFS:
            plts[dof] = PlotAux.Plot(dof, periods)
        for i, data in enumerate(Tools.solve_sim(sims, omegas)):
            App.Console.PrintMessage("\t{} / {}\n".format(i + 1, n))
            self.form.pbar.setValue(i + 1)
            ii, jj, dataset = data
            for dof in Tools.DOFS:
                rao_complex = dataset.sel(radiating_dof=dof).data[0]
                plts[dof].rao[ii, jj + 1] = abs(rao_complex)
                plts[dof].phase[ii, jj + 1] = cmath.phase(rao_complex)
                plts[dof].update()
            self.timer.start(0.0)
            self.loop.exec_()
            if (not self.running):
                break
        return True
Пример #14
0
def floatingArea(ship,
                 draft=None,
                 roll=Units.parseQuantity("0 deg"),
                 trim=Units.parseQuantity("0 deg")):
    """Compute the ship floating area

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned values:
    area -- Ship floating area
    cf -- Floating area coefficient
    """
    if draft is None:
        draft = ship.Draft

    # We want to intersect the whole ship with the free surface, so in this case
    # we must not use the underwater side (or the tool will fail)
    shape, _ = placeShipShape(ship.Shape.copy(), draft, roll, trim)

    try:
        f = Part.Face(shape.slice(Vector(0, 0, 1), 0.0))
        area = Units.Quantity(f.Area, Units.Area)
    except Part.OCCError:
        msg = QtGui.QApplication.translate(
            "ship_console", "Part.OCCError: Floating area cannot be computed",
            None)
        App.Console.PrintError(msg + '\n')
        f = None
        area = Units.Quantity(0.0, Units.Area)

    bbox = shape.BoundBox
    Area = Units.Quantity((bbox.XMax - bbox.XMin) * (bbox.YMax - bbox.YMin),
                          Units.Area)
    try:
        cf = (area / Area).Value
    except ZeroDivisionError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "ZeroDivisionError: Null area found during the floating area"
            " computation!", None)
        App.Console.PrintError(msg + '\n')
        cf = 0.0

    return area, cf, f
Пример #15
0
    def getCoG(self, fp, vol, roll=Units.parseQuantity("0 deg"),
                              trim=Units.parseQuantity("0 deg")):
        """Return the fluid volume center of gravity, provided the volume of
        fluid inside the tank.

        The returned center of gravity is referred to the untransformed ship.

        Keyword arguments:
        fp -- Part::FeaturePython object affected.
        vol -- Volume of fluid.
        roll -- Ship roll angle.
        trim -- Ship trim angle.

        If the fluid volume is bigger than the total tank one, it will be
        conveniently clamped.
        """
        if vol <= 0.0:
            return Vector()
        if vol >= fp.Shape.Volume:
            vol = 0.0
            cog = Vector()
            for solid in fp.Shape.Solids:
                vol += solid.Volume
                sCoG = solid.CenterOfMass
                cog.x = cog.x + sCoG.x * solid.Volume
                cog.y = cog.y + sCoG.y * solid.Volume
                cog.z = cog.z + sCoG.z * solid.Volume
            cog.x = cog.x / vol
            cog.y = cog.y / vol
            cog.z = cog.z / vol
            return cog

        shape = self.getFluidShape(fp, vol, roll, trim)

        # Get the center of gravity
        vol = 0.0
        cog = Vector()
        if len(shape.Solids) > 0:
            for solid in shape.Solids:
                vol += solid.Volume
                sCoG = solid.CenterOfMass
                cog.x = cog.x + sCoG.x * solid.Volume
                cog.y = cog.y + sCoG.y * solid.Volume
                cog.z = cog.z + sCoG.z * solid.Volume
            cog.x = cog.x / vol
            cog.y = cog.y / vol
            cog.z = cog.z / vol

        return cog
Пример #16
0
def floatingArea(ship, draft=None,
                       roll=Units.parseQuantity("0 deg"),
                       trim=Units.parseQuantity("0 deg")):
    """Compute the ship floating area

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned values:
    area -- Ship floating area
    cf -- Floating area coefficient
    """
    if draft is None:
        draft = ship.Draft

    # We want to intersect the whole ship with the free surface, so in this case
    # we must not use the underwater side (or the tool will fail)
    shape, _ = placeShipShape(ship.Shape.copy(), draft, roll, trim)

    try:
        f = Part.Face(shape.slice(Vector(0,0,1), 0.0))
        area = Units.Quantity(f.Area, Units.Area)
    except Part.OCCError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "Part.OCCError: Floating area cannot be computed",
            None)
        App.Console.PrintError(msg + '\n')
        area = Units.Quantity(0.0, Units.Area)

    bbox = shape.BoundBox
    Area = (bbox.XMax - bbox.XMin) * (bbox.YMax - bbox.YMin)
    try:
        cf = area.Value / Area
    except ZeroDivisionError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "ZeroDivisionError: Null area found during the floating area"
            " computation!",
            None)
        App.Console.PrintError(msg + '\n')
        cf = 0.0

    return area, cf
Пример #17
0
def get_lc_tanks(lc):
    objs = []
    i = 6
    while True:
        cells = ['{}{}'.format(c, i) for c in ('C', 'D', 'E')]
        try:
            label = lc.get('C{}'.format(i))
            dens = lc.get('D{}'.format(i))
            level = lc.get('E{}'.format(i))
        except ValueError:
            break
        i += 1
        tanks = lc.Document.getObjectsByLabel(label)
        if len(tanks) != 1:
            msg = QtGui.QApplication.translate(
                "ship_console",
                "Several tanks are labelled '{}'!".format(label), None)
            App.Console.PrintError(msg + '\n')
            continue
        tank = tanks[0]
        try:
            if not tank.IsTank:
                continue
        except AttributeError:
            continue
        try:
            dens = float(dens)
            level = float(level)
        except ValueError:
            continue
        dens = Units.parseQuantity('{} kg / m^3'.format(dens))
        objs.append((tank, dens, level))
    return objs
Пример #18
0
    def _getPuntualMass(self, fp, shape):
        """Compute the mass of a puntual element.

        Position arguments:
        fp -- Part::FeaturePython object affected.
        shape -- Vertex shape object.
        """
        return Units.parseQuantity('{0} kg'.format(fp.Mass))
Пример #19
0
def mainFrameCoeff(ship, draft=None):
    """Compute the main frame coefficient

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)

    Returned value:
    Ship main frame area coefficient
    """
    if draft is None:
        draft = ship.Draft

    shape, _ = placeShipShape(ship.Shape.copy(), draft,
                              Units.parseQuantity("0 deg"),
                              Units.parseQuantity("0 deg"))
    shape = getUnderwaterSide(shape)

    try:
        f = Part.Face(shape.slice(Vector(1,0,0), 0.0))
        area = f.Area
    except Part.OCCError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "Part.OCCError: Main frame area cannot be computed",
            None)
        App.Console.PrintError(msg + '\n')
        area = 0.0

    bbox = shape.BoundBox
    Area = (bbox.YMax - bbox.YMin) * (bbox.ZMax - bbox.ZMin)

    try:
        cm = area / Area
    except ZeroDivisionError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "ZeroDivisionError: Null area found during the main frame area"
            " coefficient computation!",
            None)
        App.Console.PrintError(msg + '\n')
        cm = 0.0

    return cm
Пример #20
0
def BMT(ship, fs, draft=None, trim=Units.parseQuantity("0 deg")):
    """Calculate "ship Bouyance center" - "transversal metacenter" radius

    Position arguments:
    ship -- Ship object (see createShip)
    fs -- The shape of the free surface. If None is passed, the BMT will be
          computed heuristically, i.e. the ship will be rotated a small angle,
          tracking the bouyance center.

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    BMT radius
    """
    if draft is None:
        draft = ship.Draft

    roll = Units.parseQuantity("0 deg")
    disp, B0, _ = displacement(ship, draft, roll=roll, trim=trim)
    if fs is not None:
        vol = disp / DENS
        inertia_unit = (Units.Quantity(1, Units.Length)**4).Unit
        return Units.Quantity(fs.MatrixOfInertia.A11, inertia_unit) / vol

    nRoll = 2
    maxRoll = Units.parseQuantity("7 deg")

    BM = 0.0
    for i in range(nRoll):
        roll = (maxRoll / nRoll) * (i + 1)
        _, B1, _ = displacement(ship, draft, roll, trim)
        #     * M
        #    / \
        #   /   \  BM     ==|>   BM = (BB/2) / sin(alpha/2)
        #  /     \
        # *-------*
        #     BB
        BB = B1 - B0
        BB.x = 0.0
        # nRoll is actually representing the weight function
        BM += 0.5 * BB.Length / math.sin(math.radians(0.5 * roll)) / nRoll
    return Units.Quantity(BM, Units.Length)
Пример #21
0
    def _getVolumetricMass(self, fp, shape):
        """Compute the mass of a volumetric element.

        Position arguments:
        fp -- Part::FeaturePython object affected.
        shape -- Solid shape object.
        """
        rho = Units.parseQuantity('{0} kg/m^3'.format(fp.Dens))
        v = Units.Quantity(shape.Volume, Units.Volume)
        return rho * v
Пример #22
0
    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.parseQuantity(Locale.fromString(form.draft.text()))
        trim = Units.parseQuantity(Locale.fromString(form.trim.text()))

        # Calculate the drafts at each perpendicular
        angle = trim.getValueAs("rad").Value
        L = self.ship.Length.getValueAs('m').Value
        B = self.ship.Breadth.getValueAs('m').Value
        draftAP = draft + 0.5 * self.ship.Length * math.tan(angle)
        if draftAP < 0.0:
            draftAP = 0.0
        draftFP = draft - 0.5 * self.ship.Length * math.tan(angle)
        if draftFP < 0.0:
            draftFP = 0.0
        # Calculate the involved hydrostatics
        disp, B, _ = Hydrostatics.displacement(self.ship,
                                               draft,
                                               Units.parseQuantity("0 deg"),
                                               trim)
        xcb = Units.Quantity(B.x, Units.Length)
        # Setup the html string
        string = u'L = {0}<BR>'.format(self.ship.Length.UserString)
        string += u'B = {0}<BR>'.format(self.ship.Breadth.UserString)
        string += u'T = {0}<HR>'.format(draft.UserString)
        string += u'Trim = {0}<BR>'.format(trim.UserString)
        string += u'T<sub>AP</sub> = {0}<BR>'.format(draftAP.UserString)
        string += u'T<sub>FP</sub> = {0}<HR>'.format(draftFP.UserString)
        dispText = QtGui.QApplication.translate(
            "ship_areas",
            'Displacement',
            None)
        string += dispText + u' = {0}<BR>'.format(disp.UserString)
        string += u'XCB = {0}'.format(xcb.UserString)
        form.output.setHtml(string)
Пример #23
0
    def _getAreaMass(self, fp, shape):
        """Compute the mass of an area element.

        Position arguments:
        fp -- Part::FeaturePython object affected.
        shape -- Face shape object.
        """
        rho = Units.parseQuantity('{0} kg/m^2'.format(fp.AreaDens))
        a = Units.Quantity(shape.Area, Units.Area)
        return rho * a
Пример #24
0
    def _getLinearMass(self, fp, shape):
        """Compute the mass of a linear element.

        Position arguments:
        fp -- Part::FeaturePython object affected.
        shape -- Edge shape object.
        """
        rho = Units.parseQuantity('{0} kg/m'.format(fp.LineDens))
        l = Units.Quantity(shape.Length, Units.Length)
        return rho * l
Пример #25
0
    def getFluidShape(self, fp, vol, roll=Units.parseQuantity("0 deg"),
                                     trim=Units.parseQuantity("0 deg")):
        """Return the tank fluid shape for the provided rotation angles. The
        returned shape is however not rotated at all

        Keyword arguments:
        fp -- Part::FeaturePython object affected.
        vol -- Volume of fluid.
        roll -- Ship roll angle.
        trim -- Ship trim angle.
        """
        if vol <= 0.0:
            return None
        if vol >= fp.Shape.Volume:
            return fp.Shape.copy()
        
        # Get a first estimation of the level
        level = vol.Value / fp.Shape.Volume

        # Transform the tank shape
        current_placement = fp.Placement
        m = current_placement.toMatrix()
        m.rotateX(roll)
        m.rotateY(-trim)
        fp.Placement = Placement(m)

        # Iterate to find the fluid shape
        for i in range(COMMON_BOOLEAN_ITERATIONS):
            shape = self.getVolume(fp, level, return_shape=True)
            error = (vol.Value - shape.Volume) / fp.Shape.Volume
            if abs(error) < 0.01:
                break
            level += COMMON_BOOLEAN_RELAXATION[i] * error

        # Untransform the object to retrieve the original position
        fp.Placement = current_placement
        m = shape.Placement.toMatrix()
        m.rotateY(trim)
        m.rotateX(-roll)
        shape.Placement = Placement(m)

        return shape
Пример #26
0
    def accept(self):
        if not self.tank:
            return False
        self.form.group_pbar.show()

        n = self.form.points.value()
        self.form.pbar.setMinimum(0)
        self.form.pbar.setMaximum(n - 1)
        self.form.pbar.setValue(0)

        # Start iterating
        self.loop = QtCore.QEventLoop()
        self.timer = QtCore.QTimer()
        self.timer.setSingleShot(True)
        QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"),
                               self.loop, QtCore.SLOT("quit()"))
        self.running = True
        # Get the hydrostatics
        msg = QtGui.QApplication.translate("ship_console",
                                           "Computing capacity curve", None)
        App.Console.PrintMessage(msg + '...\n')
        l = [0.0]
        z = [Units.parseQuantity("0 m")]
        v = [Units.parseQuantity("0 m^3")]
        plt = None
        for i in range(1, n):
            App.Console.PrintMessage("\t{} / {}\n".format(i, n - 1))
            self.form.pbar.setValue(i)
            level = i / (n - 1)
            h, vol = Tools.compute_capacity(self.tank, level)
            l.append(100 * level)
            z.append(h)
            v.append(vol)
            if plt is None:
                plt = PlotAux.Plot(l, z, v)
            else:
                plt.update(l, z, v)
            self.timer.start(0.0)
            self.loop.exec_()
            if (not self.running):
                break
        return True
Пример #27
0
    def onData(self, value):
        """ Method called when the tool input data is touched.
        @param value Changed value.
        """
        draft = Units.parseQuantity(Locale.fromString(self.form.draft.text()))
        trim = Units.parseQuantity(Locale.fromString(self.form.trim.text()))
        if draft.Unit != Units.Length or trim.Unit != Units.Angle:
            return

        bbox = self.ship.Shape.BoundBox
        draft_min = Units.Quantity(bbox.ZMin, Units.Length)
        draft_max = Units.Quantity(bbox.ZMax, Units.Length)
        draft = self.clampValue(self.form.draft, draft_min, draft_max, draft)

        trim_min = Units.parseQuantity("-90 deg")
        trim_max = Units.parseQuantity("90 deg")
        trim = self.clampValue(self.form.trim, trim_min, trim_max, trim)

        self.onUpdate()
        self.preview.update(draft, trim, self.ship)
Пример #28
0
def TMC(ship,
        fs,
        draft=None,
        roll=Units.parseQuantity("0 deg"),
        trim=Units.parseQuantity("0 deg")):
    """Compute the moment required to trim the ship 1cm

    Position arguments:
    ship -- Ship object (see createShip)
    fs -- The shape of the free surface. If None is passed, the BML will be
          computed heuristically, i.e. the ship will be rotated a small angle,
          tracking the bouyance center.

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    Moment required to trim the ship 1cm. Such moment is positive if it cause a
    positive trim angle. The moment is expressed as a mass by a distance, not as
    a force by a distance
    """
    if draft is None:
        draft = ship.Draft

    if fs is not None:
        bml, disp = BML(ship, fs, draft=draft, roll=roll, trim=trim)
        return disp * bml / ship.Length.getValueAs('cm').Value

    disp_orig, B_orig, _ = displacement(ship, draft, roll, trim)
    factor = 10.0
    x = 0.5 * ship.Length.getValueAs('cm').Value
    y = 1.0
    angle = math.atan2(y, x) * Units.Radian
    trim_new = trim + factor * angle
    disp_new, B_new, _ = displacement(ship, draft, roll, trim_new)

    mom0 = disp_orig * Units.Quantity(B_orig.x, Units.Length)
    mom1 = disp_new * Units.Quantity(B_new.x, Units.Length)
    return (mom1 - mom0) / factor
Пример #29
0
    def accept(self):
        """Create the ship instance"""
        mw = self.getMainWindow()
        form = mw.findChild(QtGui.QWidget, "TaskPanel")
        form.ship = self.widget(QtGui.QComboBox, "Ship")
        form.weight = self.widget(QtGui.QLineEdit, "Weight")

        ship = self.ships[form.ship.currentIndex()]
        density = Units.parseQuantity(Locale.fromString(form.weight.text()))

        Tools.createWeight(self.shapes, ship, density)
        return True
Пример #30
0
    def accept(self):
        """Create the ship instance"""
        mw = self.getMainWindow()
        form = mw.findChild(QtGui.QWidget, "TaskPanel")
        form.ship = self.widget(QtGui.QComboBox, "Ship")
        form.weight = self.widget(QtGui.QLineEdit, "Weight")

        ship = self.ships[form.ship.currentIndex()]
        density = Units.parseQuantity(Locale.fromString(form.weight.text()))

        Tools.createWeight(self.shapes, ship, density)
        return True
Пример #31
0
def wettedArea(shape, draft, roll=Units.parseQuantity("0 deg"),
                             trim=Units.parseQuantity("0 deg")):
    """Compute the ship wetted area

    Position arguments:
    shape -- External faces of the ship hull
    draft -- Ship draft

    Keyword arguments:
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    The wetted area, i.e. The underwater side area
    """
    shape, _ = placeShipShape(shape.copy(), draft, roll, trim)
    shape = getUnderwaterSide(shape, force=False)

    area = 0.0
    for f in shape.Faces:
        area = area + f.Area
    return Units.Quantity(area, Units.Area)
Пример #32
0
    def accept(self):
        if not self.ship:
            return False
        self.save()
        # Plot data
        draft = Units.parseQuantity(Locale.fromString(self.form.draft.text()))
        trim = Units.parseQuantity(Locale.fromString(self.form.trim.text()))
        num = self.form.num.value()

        disp, B, _ = Hydrostatics.displacement(self.ship, draft,
                                               Units.parseQuantity("0 deg"),
                                               trim)
        xcb = Units.Quantity(B.x, Units.Length)
        data = Hydrostatics.areas(self.ship, num, draft=draft, trim=trim)
        x = []
        y = []
        for i in range(0, len(data)):
            x.append(data[i][0].getValueAs("m").Value)
            y.append(data[i][1].getValueAs("m^2").Value)
        PlotAux.Plot(x, y, disp, xcb, self.ship)
        self.preview.clean()
        return True
Пример #33
0
def BMT(ship, draft=None, trim=Units.parseQuantity("0 deg")):
    """Calculate "ship Bouyance center" - "transversal metacenter" radius

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    BMT radius
    """
    if draft is None:
        draft = ship.Draft

    roll = Units.parseQuantity("0 deg")
    _, B0, _ = displacement(ship, draft, roll, trim)


    nRoll = 2
    maxRoll = Units.parseQuantity("7 deg")

    BM = 0.0
    for i in range(nRoll):
        roll = (maxRoll / nRoll) * (i + 1)
        _, B1, _ = displacement(ship, draft, roll, trim)
        #     * M
        #    / \
        #   /   \  BM     ==|>   BM = (BB/2) / sin(alpha/2)
        #  /     \
        # *-------*
        #     BB
        BB = B1 - B0
        BB.x = 0.0
        # nRoll is actually representing the weight function
        BM += 0.5 * BB.Length / math.sin(math.radians(0.5 * roll)) / nRoll
    return Units.Quantity(BM, Units.Length)
Пример #34
0
#*                                                                         *
#***************************************************************************

import math
import FreeCAD as App
import FreeCADGui as Gui
from FreeCAD import Vector, Matrix, Placement
import Part
from FreeCAD import Units
import Instance as ShipInstance
import WeightInstance
import TankInstance
from shipHydrostatics import Tools as Hydrostatics


G = Units.parseQuantity("9.81 m/s^2")
MAX_EQUILIBRIUM_ITERS = 10
DENS = Units.parseQuantity("1025 kg/m^3")
TRIM_RELAX_FACTOR = 10.0


def solve(ship, weights, tanks, rolls, var_trim=True):
    """Compute the ship GZ stability curve

    Position arguments:
    ship -- Ship object
    weights -- List of weights to consider
    tanks -- List of tanks to consider (each one should be a tuple with the
    tank instance, the density of the fluid inside, and the filling level ratio)
    rolls -- List of roll angles
Пример #35
0
def solve_point(W, COG, TW, VOLS, ship, tanks, roll, var_trim=True):
    """ Compute the ship GZ value.
    @param W Empty ship weight.
    @param COG Empty ship Center of mass.
    @param TW Tanks weights.
    @param VOLS List of tank volumes.
    @param tanks Considered tanks.
    @param roll Roll angle.
    @param var_trim True if the trim angle should be recomputed at each roll
    angle, False otherwise.
    @return GZ value, equilibrium draft, and equilibrium trim angle (0 if
    variable trim has not been requested)
    """    
    # Look for the equilibrium draft (and eventually the trim angle too)
    max_draft = Units.Quantity(ship.Shape.BoundBox.ZMax, Units.Length)
    draft = ship.Draft
    max_disp = Units.Quantity(ship.Shape.Volume, Units.Volume) * DENS * G
    if max_disp < W + TW:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "Too much weight! The ship will never displace water enough",
            None)
        App.Console.PrintError(msg + ' ({} vs. {})\n'.format(
            (max_disp / G).UserString, ((W + TW) / G).UserString))
        return None

    trim = Units.parseQuantity("0 deg")
    for i in range(MAX_EQUILIBRIUM_ITERS):
        # Get the displacement, and the bouyance application point
        disp, B, _ = Hydrostatics.displacement(ship,
                                               draft,
                                               roll,
                                               trim)
        disp *= G

        # Add the tanks effect on the center of gravity
        mom_x = Units.Quantity(COG.x, Units.Length) * W
        mom_y = Units.Quantity(COG.y, Units.Length) * W
        mom_z = Units.Quantity(COG.z, Units.Length) * W
        for i,t in enumerate(tanks):
            tank_weight = VOLS[i] * t[1] * G
            tank_cog = t[0].Proxy.getCoG(t[0], VOLS[i], roll, trim)
            mom_x += Units.Quantity(tank_cog.x, Units.Length) * tank_weight
            mom_y += Units.Quantity(tank_cog.y, Units.Length) * tank_weight
            mom_z += Units.Quantity(tank_cog.z, Units.Length) * tank_weight
        cog_x = mom_x / (W + TW)
        cog_y = mom_y / (W + TW)
        cog_z = mom_z / (W + TW)
        # Compute the errors
        draft_error = -((disp - W - TW) / max_disp).Value
        R_x = cog_x - Units.Quantity(B.x, Units.Length)
        R_y = cog_y - Units.Quantity(B.y, Units.Length)
        R_z = cog_z - Units.Quantity(B.z, Units.Length)
        if not var_trim:
            trim_error = 0.0
        else:
            trim_error = -TRIM_RELAX_FACTOR * R_x / ship.Length

        # Check if we can tolerate the errors
        if abs(draft_error) < 0.01 and abs(trim_error) < 0.1:
            break

        # Get the new draft and trim
        draft += draft_error * max_draft
        trim += trim_error * Units.Degree

    # GZ should be provided in the Free surface oriented frame of reference
    c = math.cos(roll.getValueAs('rad'))
    s = math.sin(roll.getValueAs('rad'))
    return c * R_y - s * R_z, draft, trim
Пример #36
0
    def accept(self):
        if not self.ship:
            return False
        if self.running:
            return
        self.save()

        mw = self.getMainWindow()
        form = mw.findChild(QtGui.QWidget, "TaskPanel")
        form.trim = self.widget(QtGui.QLineEdit, "Trim")
        form.minDraft = self.widget(QtGui.QLineEdit, "MinDraft")
        form.maxDraft = self.widget(QtGui.QLineEdit, "MaxDraft")
        form.nDraft = self.widget(QtGui.QSpinBox, "NDraft")

        trim = Units.parseQuantity(Locale.fromString(form.trim.text()))
        min_draft = Units.parseQuantity(Locale.fromString(form.minDraft.text()))
        max_draft = Units.parseQuantity(Locale.fromString(form.maxDraft.text()))
        n_draft = form.nDraft.value()

        draft = min_draft
        drafts = [draft]
        dDraft = (max_draft - min_draft) / (n_draft - 1)
        for i in range(1, n_draft):
            draft = draft + dDraft
            drafts.append(draft)

        # Get external faces
        self.loop = QtCore.QEventLoop()
        self.timer = QtCore.QTimer()
        self.timer.setSingleShot(True)
        QtCore.QObject.connect(self.timer,
                               QtCore.SIGNAL("timeout()"),
                               self.loop,
                               QtCore.SLOT("quit()"))
        self.running = True
        faces = self.externalFaces(self.ship.Shape)
        if not self.running:
            return False
        if len(faces) == 0:
            msg = QtGui.QApplication.translate(
                "ship_console",
                "Failure detecting external faces from the ship object",
                None)
            App.Console.PrintError(msg + '\n')
            return False
        faces = Part.makeShell(faces)

        # Get the hydrostatics
        msg = QtGui.QApplication.translate(
            "ship_console",
            "Computing hydrostatics",
            None)
        App.Console.PrintMessage(msg + '...\n')
        points = []
        for i in range(len(drafts)):
            App.Console.PrintMessage("\t{} / {}\n".format(i + 1, len(drafts)))
            draft = drafts[i]
            point = Tools.Point(self.ship,
                                faces,
                                draft,
                                trim)
            points.append(point)
            self.timer.start(0.0)
            self.loop.exec_()
            if(not self.running):
                break
        PlotAux.Plot(self.ship, trim, points)
        return True
Пример #37
0
def displacement(ship, draft=None,
                       roll=Units.parseQuantity("0 deg"),
                       trim=Units.parseQuantity("0 deg")):
    """Compute the ship displacement

    Position arguments:
    ship -- Ship object (see createShip)

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned values:
    disp -- The ship displacement (a density of the water of 1025 kg/m^3 is
    assumed)
    B -- Bouyance application point, i.e. Center of mass of the underwater side
    Cb -- Block coefficient

    The Bouyance center is referred to the original ship position.
    """
    if draft is None:
        draft = ship.Draft

    shape, base_z = placeShipShape(ship.Shape.copy(), draft, roll, trim)
    shape = getUnderwaterSide(shape)

    vol = 0.0
    cog = Vector()
    if len(shape.Solids) > 0:
        for solid in shape.Solids:
            vol += solid.Volume
            sCoG = solid.CenterOfMass
            cog.x = cog.x + sCoG.x * solid.Volume
            cog.y = cog.y + sCoG.y * solid.Volume
            cog.z = cog.z + sCoG.z * solid.Volume
        cog.x = cog.x / vol
        cog.y = cog.y / vol
        cog.z = cog.z / vol

    bbox = shape.BoundBox
    Vol = (bbox.XMax - bbox.XMin) * (bbox.YMax - bbox.YMin) * abs(bbox.ZMin)

    # Undo the transformations on the bouyance point
    B = Part.Point(Vector(cog.x, cog.y, cog.z))
    m = Matrix()
    m.move(Vector(0.0, 0.0, draft))
    m.move(Vector(-draft * math.sin(trim.getValueAs("rad")), 0.0, 0.0))
    m.rotateY(trim.getValueAs("rad"))
    m.move(Vector(0.0,
                  -draft * math.sin(roll.getValueAs("rad")),
                  base_z))
    m.rotateX(-roll.getValueAs("rad"))
    B.transform(m)

    try:
        cb = vol / Vol
    except ZeroDivisionError:
        msg = QtGui.QApplication.translate(
            "ship_console",
            "ZeroDivisionError: Null volume found during the displacement"
            " computation!",
            None)
        App.Console.PrintError(msg + '\n')
        cb = 0.0


    # Return the computed data
    return (DENS * Units.Quantity(vol, Units.Volume),
            Vector(B.X, B.Y, B.Z),
            cb)
Пример #38
0
def areas(ship, n, draft=None,
                   roll=Units.parseQuantity("0 deg"),
                   trim=Units.parseQuantity("0 deg")):
    """Compute the ship transversal areas

    Position arguments:
    ship -- Ship object (see createShip)
    n -- Number of points to compute

    Keyword arguments:
    draft -- Ship draft (Design ship draft by default)
    roll -- Roll angle (0 degrees by default)
    trim -- Trim angle (0 degrees by default)

    Returned value:
    List of sections, each section contains 2 values, the x longitudinal
    coordinate, and the transversal area. If n < 2, an empty list will be
    returned.
    """
    if n < 2:
        return []

    if draft is None:
        draft = ship.Draft

    shape, _ = placeShipShape(ship.Shape.copy(), draft, roll, trim)
    shape = getUnderwaterSide(shape)

    # Sections distance computation
    bbox = shape.BoundBox
    xmin = bbox.XMin
    xmax = bbox.XMax
    dx = (xmax - xmin) / (n - 1.0)

    # Since we are computing the sections in the total length (not in the
    # length between perpendiculars), we can grant that the starting and
    # ending sections have null area
    areas = [(Units.Quantity(xmin, Units.Length),
              Units.Quantity(0.0, Units.Area))]
    # And since we just need to compute areas we will create boxes with its
    # front face at the desired transversal area position, computing the
    # common solid part, dividing it by faces, and getting only the desired
    # ones.
    App.Console.PrintMessage("Computing transversal areas...\n")
    App.Console.PrintMessage("Some Inventor representation errors can be"
                             " shown, please ignore them.\n")
    for i in range(1, n - 1):
        App.Console.PrintMessage("{0} / {1}\n".format(i, n - 2))
        x = xmin + i * dx
        try:
            f = Part.Face(shape.slice(Vector(1,0,0), x))
        except Part.OCCError:
            msg = QtGui.QApplication.translate(
                "ship_console",
                "Part.OCCError: Transversal area computation failed",
                None)
            App.Console.PrintError(msg + '\n')
            areas.append((Units.Quantity(x, Units.Length),
                          Units.Quantity(0.0, Units.Area)))
            continue
        # It is a valid face, so we can add this area
        areas.append((Units.Quantity(x, Units.Length),
                      Units.Quantity(f.Area, Units.Area)))
    # Last area is equal to zero (due to the total length usage)
    areas.append((Units.Quantity(xmax, Units.Length),
                  Units.Quantity(0.0, Units.Area)))
    App.Console.PrintMessage("Done!\n")
    return areas
Пример #39
0
#***************************************************************************

import math
import random
from FreeCAD import Vector, Rotation, Matrix, Placement
import Part
from FreeCAD import Units
import FreeCAD as App
import FreeCADGui as Gui
from PySide import QtGui, QtCore
import Instance
from shipUtils import Math
import shipUtils.Units as USys


DENS = Units.parseQuantity("1025 kg/m^3")  # Salt water
COMMON_BOOLEAN_ITERATIONS = 10


def placeShipShape(shape, draft, roll, trim):
    """Move the ship shape such that the free surface matches with the plane
    z=0. The transformation will be applied on the input shape, so copy it
    before calling this method if it should be preserved.

    Position arguments:
    shape -- Ship shape
    draft -- Ship draft
    roll -- Roll angle
    trim -- Trim angle

    Returned values:
Пример #40
0
def gz(lc, rolls, var_trim=True):
    """Compute the ship GZ stability curve

    Position arguments:
    lc -- Load condition spreadsheet
    rolls -- List of roll angles to compute

    Keyword arguments:
    var_trim -- True if the equilibrium trim should be computed for each roll
    angle, False if null trim angle can be used instead.

    Returned value:
    List of GZ curve points. Each point contains the GZ stability length, the
    equilibrium draft, and the equilibrium trim angle (0 deg if var_trim is
    False)
    """
    # B1 cell must be a ship
    # B2 cell must be the loading condition itself
    doc = lc.Document
    try:
        if lc not in doc.getObjectsByLabel(lc.get('B2')):
            return[]
        ships = doc.getObjectsByLabel(lc.get('B1'))
        if len(ships) != 1:
            if len(ships) == 0:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Wrong Ship label! (no instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    lc.get('B1')))
            else:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Ambiguous Ship label! ({} instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    len(ships),
                    lc.get('B1')))
            return[]
        ship = ships[0]
        if ship is None or not ship.PropertiesList.index("IsShip"):
            return[]
    except ValueError:
        return[]
    # Extract the weights and the tanks
    weights = []
    index = 6
    while True:
        try:
            ws = doc.getObjectsByLabel(lc.get('A{}'.format(index)))
        except ValueError:
            break
        index += 1
        if len(ws) != 1:
            if len(ws) == 0:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Wrong Weight label! (no instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    lc.get('A{}'.format(index - 1))))
            else:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Ambiguous Weight label! ({} instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    len(ws),
                    lc.get('A{}'.format(index - 1))))
            continue
        w = ws[0]
        try:
            if w is None or not w.PropertiesList.index("IsWeight"):
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Invalid Weight! (the object labeled as"
                    "'{}' is not a weight)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    len(ws),
                    lc.get('A{}'.format(index - 1))))
                continue
        except ValueError:
            continue
        weights.append(w)
    tanks = []
    index = 6
    while True:
        try:
            ts = doc.getObjectsByLabel(lc.get('C{}'.format(index)))
            dens = float(lc.get('D{}'.format(index)))
            level = float(lc.get('E{}'.format(index)))
            dens = Units.parseQuantity("{} kg/m^3".format(dens))
        except ValueError:
            break
        index += 1
        if len(ts) != 1:
            if len(ts) == 0:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Wrong Tank label! (no instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    lc.get('C{}'.format(index - 1))))
            else:
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Ambiguous Tank label! ({} instances labeled as"
                    "'{}' found)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    len(ts),
                    lc.get('C{}'.format(index - 1))))
            continue
        t = ts[0]
        try:
            if t is None or not t.PropertiesList.index("IsTank"):
                msg = QtGui.QApplication.translate(
                    "ship_console",
                    "Invalid Tank! (the object labeled as"
                    "'{}' is not a tank)",
                    None)
                App.Console.PrintError(msg + '\n'.format(
                    len(ws),
                    lc.get('C{}'.format(index - 1))))
                continue
        except ValueError:
            continue
        tanks.append((t, dens, level))

    return solve(ship, weights, tanks, rolls, var_trim)