Пример #1
0
 def testIssue2671(self):
     self.Doc = App.newDocument("Issue2671")
     Box = self.Doc.addObject("Part::Box","Box")
     Mirroring = self.Doc.addObject("Part::Mirroring", 'Mirroring')
     Spreadsheet = self.Doc.addObject('Spreadsheet::Sheet', 'Spreadsheet')
     Mirroring.Source = Box
     Mirroring.Base = (8, 5, 25)
     Mirroring.Normal = (0.5, 0.2, 0.9)
     Spreadsheet.set('A1', '=Mirroring.Base.x')
     Spreadsheet.set('B1', '=Mirroring.Base.y')
     Spreadsheet.set('C1', '=Mirroring.Base.z')
     Spreadsheet.set('A2', '=Mirroring.Normal.x')
     Spreadsheet.set('B2', '=Mirroring.Normal.y')
     Spreadsheet.set('C2', '=Mirroring.Normal.z')
     self.Doc.recompute()
     self.assertEqual(Spreadsheet.A1, Units.Quantity('8 mm'))
     self.assertEqual(Spreadsheet.B1, Units.Quantity('5 mm'))
     self.assertEqual(Spreadsheet.C1, Units.Quantity('25 mm'))
     self.assertEqual(Spreadsheet.A2, Units.Quantity('0.5 mm'))
     self.assertEqual(Spreadsheet.B2, Units.Quantity('0.2 mm'))
     self.assertEqual(Spreadsheet.C2, Units.Quantity('0.9 mm'))
     App.closeDocument("Issue2671")
Пример #2
0
 def get_region_data(self):
     # mesh regions
     if not self.mesh_obj.MeshRegionList:
         # print('  No mesh regions.')
         pass
     else:
         print('  Mesh regions, we need to get the elements.')
         # by the use of MeshRegion object and a BooleanSplitCompound
         # there could be problems with node numbers see
         # http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467
         # http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&p=149520#p149520
         part = self.part_obj
         if self.mesh_obj.MeshRegionList:
             # other part obj might not have a Proxy, thus an exception would be raised
             if part.Shape.ShapeType == "Compound" and hasattr(
                     part, "Proxy"):
                 if (part.Proxy.Type == "FeatureBooleanFragments"
                         or part.Proxy.Type == "FeatureSlice"
                         or part.Proxy.Type == "FeatureXOR"):
                     error_message = (
                         '  The mesh to shape is a boolean split tools Compound '
                         'and the mesh has mesh region list. '
                         'Gmsh could return unexpected meshes in such circumstances. '
                         'It is strongly recommended to extract the shape to mesh '
                         'from the Compound and use this one.')
                     FreeCAD.Console.PrintError(error_message + "\n")
                     # TODO: no gui popup because FreeCAD will be in a endless output loop
                     #       as long as the pop up is on --> maybe find a better solution for
                     #       either of both --> thus the pop up is in task panel
         for mr_obj in self.mesh_obj.MeshRegionList:
             # print(mr_obj.Name)
             # print(mr_obj.CharacteristicLength)
             # print(Units.Quantity(mr_obj.CharacteristicLength).Value)
             if mr_obj.CharacteristicLength:
                 if mr_obj.References:
                     for sub in mr_obj.References:
                         # print(sub[0])  # Part the elements belongs to
                         # check if the shape of the mesh region is an element of the Part to mesh,
                         # if not try to find the element in the shape to mesh
                         search_ele_in_shape_to_mesh = False
                         if not self.part_obj.Shape.isSame(sub[0].Shape):
                             # print("  One element of the meshregion " + mr_obj.Name + " is not an element of the Part to mesh.")
                             # print("  But we are going to try to find it in the Shape to mesh :-)")
                             search_ele_in_shape_to_mesh = True
                         for elems in sub[1]:
                             # print(elems)  # elems --> element
                             if search_ele_in_shape_to_mesh:
                                 # we're going to try to find the element in the Shape to mesh and use the found element as elems
                                 # the method getElement(element) does not return Solid elements
                                 ele_shape = FemMeshTools.get_element(
                                     sub[0], elems)
                                 found_element = FemMeshTools.find_element_in_shape(
                                     self.part_obj.Shape, ele_shape)
                                 if found_element:
                                     elems = found_element
                                 else:
                                     FreeCAD.Console.PrintError(
                                         "One element of the meshregion {} could not be found "
                                         "in the Part to mesh. It will be ignored.\n"
                                         .format(mr_obj.Name))
                             # print(elems)  # element
                             if elems not in self.ele_length_map:
                                 self.ele_length_map[
                                     elems] = Units.Quantity(
                                         mr_obj.CharacteristicLength).Value
                             else:
                                 FreeCAD.Console.PrintError(
                                     "The element " + elems +
                                     " of the meshregion " + mr_obj.Name +
                                     " has been added to another mesh region.\n"
                                 )
                 else:
                     FreeCAD.Console.PrintError(
                         "The meshregion: " + mr_obj.Name +
                         " is not used to create the mesh because the reference list is empty.\n"
                     )
             else:
                 FreeCAD.Console.PrintError(
                     "The meshregion: " + mr_obj.Name +
                     " is not used to create the mesh because the CharacteristicLength is 0.0 mm.\n"
                 )
         for eleml in self.ele_length_map:
             ele_shape = FemMeshTools.get_element(
                 self.part_obj, eleml
             )  # the method getElement(element) does not return Solid elements
             ele_vertexes = FemMeshTools.get_vertexes_by_element(
                 self.part_obj.Shape, ele_shape)
             self.ele_node_map[eleml] = ele_vertexes
         print('  {}'.format(self.ele_length_map))
         print('  {}'.format(self.ele_node_map))
Пример #3
0
    def initUI(self):
        #self.setMinimumHeight(self.minHeight)
        self.setWindowTitle(translate("A2plus_constraintDialog",'Constraint properties'))
        #self.resize(300,600)

        self.mainLayout = QtGui.QGridLayout() # a VBoxLayout for the whole form
        #==============================
        lbl1 = QtGui.QLabel(self)
        lbl1.setText(self.constraintObject.Label)
        lbl1.setFrameStyle(
            QtGui.QFrame.Panel |
            QtGui.QFrame.Sunken
            )
        self.mainLayout.addWidget(lbl1,self.lineNo,0,1,4)
        self.lineNo += 1

        #==============================
        if hasattr(self.constraintObject,"directionConstraint"):
            lbl3 = QtGui.QLabel(self)
            lbl3.setText("Direction")
            lbl3.setFixedHeight(32)
            self.mainLayout.addWidget(lbl3,self.lineNo,0)

            self.directionCombo = QtGui.QComboBox(self)
            self.directionCombo.insertItem(0,"aligned")
            self.directionCombo.insertItem(1,"opposed")
            d = self.constraintObject.directionConstraint # not every constraint has a direction
            #
            # for compat with old A2plus assemblies
            if d == "none":
                self.directionCombo.insertItem(2,"none")
            #
            if d == "aligned":
                self.directionCombo.setCurrentIndex(0)
            elif d == "opposed":
                self.directionCombo.setCurrentIndex(1)
            elif d == "none": # will only occur with old A2plus assemblies
                self.directionCombo.setCurrentIndex(2)
            #
            self.directionCombo.setFixedHeight(32)
            self.directionCombo.currentIndexChanged[int].connect(self.flipDirection2)
            self.mainLayout.addWidget(self.directionCombo,self.lineNo,1)

            self.flipDirectionButton = QtGui.QPushButton(self)
            self.flipDirectionButton.setIcon(QtGui.QIcon(':/icons/a2p_FlipConstraint.svg'))
            self.flipDirectionButton.setText("Flip direction")
            self.flipDirectionButton.setFixedHeight(32)
            QtCore.QObject.connect(self.flipDirectionButton, QtCore.SIGNAL("clicked()"), self.flipDirection)
            self.mainLayout.addWidget(self.flipDirectionButton,self.lineNo,2)

            self.lineNo += 1

        #==============================
        if hasattr(self.constraintObject,"offset"):
            offs = self.constraintObject.offset
            lbl4 = QtGui.QLabel(self)
            lbl4.setText("Offset")
            lbl4.setFixedHeight(32)
            self.mainLayout.addWidget(lbl4,self.lineNo,0)

            self.offsetEdit = QtGui.QDoubleSpinBox(self)

            # get the length unit as string
            self.offsetEdit.setSuffix(" " + str(FreeCAD.Units.Quantity(1, FreeCAD.Units.Length))[3:])
            # the maximum is by default 99.99 and we can allow more
            self.offsetEdit.setMaximum(1e7) # allow up to 1 km
            # set minimum to negative of maximum
            self.offsetEdit.setMinimum(-1*self.offsetEdit.maximum())

            # use the number of decimals defined by thew user in FC
            params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Units")
            self.offsetEdit.setDecimals(params.GetInt('Decimals'))

            userPreferred = Units.Quantity(offs).getUserPreferred()[0] #offs is string with value and unit
            user_qty, user_unit = userPreferred.split(' ')
            user_qty = float(user_qty.replace(",","."))

            #self.offsetEdit.setValue(offs.Value)
            #self.offsetEdit.setSuffix(" " + str(FreeCAD.Units.Quantity(1, FreeCAD.Units.Length))[3:])
            self.offsetEdit.setSuffix(" " + user_unit)
            self.offsetEdit.setValue(user_qty)
            self.recentUnit = user_unit

            self.offsetEdit.setFixedHeight(32)
            QtCore.QObject.connect(self.offsetEdit, QtCore.SIGNAL("valueChanged(double)"), self.handleOffsetChanged)
            self.mainLayout.addWidget(self.offsetEdit,self.lineNo,1)

            self.offsetSetZeroButton = QtGui.QPushButton(self)
            self.offsetSetZeroButton.setText("Set Zero")
            self.offsetSetZeroButton.setFixedHeight(32)
            QtCore.QObject.connect(self.offsetSetZeroButton, QtCore.SIGNAL("clicked()"), self.setOffsetZero)
            self.mainLayout.addWidget(self.offsetSetZeroButton,self.lineNo,2)

            self.flipOffsetSignButton = QtGui.QPushButton(self)
            self.flipOffsetSignButton.setText("Flip sign")
            self.flipOffsetSignButton.setFixedHeight(32)
            QtCore.QObject.connect(self.flipOffsetSignButton, QtCore.SIGNAL("clicked()"), self.flipOffsetSign)
            self.mainLayout.addWidget(self.flipOffsetSignButton,self.lineNo,3)

            self.lineNo += 1

        #==============================
        if hasattr(self.constraintObject,"angle"):
            angle = self.constraintObject.angle
            lbl5 = QtGui.QLabel(self)
            lbl5.setText("Angle")
            lbl5.setFixedHeight(32)
            self.mainLayout.addWidget(lbl5,self.lineNo,0)

            self.angleEdit = QtGui.QDoubleSpinBox(self)
            # get the angle unit as string
            self.angleEdit.setSuffix(" " + str(FreeCAD.Units.Quantity(1, FreeCAD.Units.Angle))[3:])

            if self.constraintObject.Type == "axisPlaneAngle":
                self.angleEdit.setMaximum(90.0)
                self.angleEdit.setMinimum(0.0)  # the solver treats negative values as positive
            else:
                self.angleEdit.setMaximum(180)
                self.angleEdit.setMinimum(0)    # the solver treats negative values as positive

            # use the number of decimals defined by the user in FC
            params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Units")
            self.angleEdit.setDecimals(params.GetInt('Decimals'))
            self.angleEdit.setValue(angle)
            self.angleEdit.setFixedHeight(32)
            self.angleEdit.setToolTip("Angle in the range 0 - 180 degrees")
            QtCore.QObject.connect(self.angleEdit, QtCore.SIGNAL("valueChanged(double)"), self.handleAngleChanged)
            self.mainLayout.addWidget(self.angleEdit,self.lineNo,1)

            self.roundAngleButton = QtGui.QPushButton(self)
            self.roundAngleButton.setText("Round")
            self.roundAngleButton.setFixedHeight(32)
            self.roundAngleButton.setToolTip("Round angle to multiples of 5")
            QtCore.QObject.connect(self.roundAngleButton, QtCore.SIGNAL("clicked()"), self.roundAngle)
            self.mainLayout.addWidget(self.roundAngleButton,self.lineNo,2)

            self.perpendicularAngleButton = QtGui.QPushButton(self)
            self.perpendicularAngleButton.setText("Perpendicular")
            self.perpendicularAngleButton.setFixedHeight(32)
            self.perpendicularAngleButton.setToolTip("Adds/deletes 90 degrees")
            QtCore.QObject.connect(self.perpendicularAngleButton, QtCore.SIGNAL("clicked()"), self.perpendicularAngle)
            self.mainLayout.addWidget(self.perpendicularAngleButton,self.lineNo,3)

            self.lineNo += 1

        #==============================
        if hasattr(self.constraintObject,"lockRotation"):
            lbl6 = QtGui.QLabel(self)
            lbl6.setText("Lock Rotation")
            lbl6.setFixedHeight(32)
            self.mainLayout.addWidget(lbl6,self.lineNo,0)

            self.lockRotationCombo = QtGui.QComboBox(self)
            self.lockRotationCombo.insertItem(0,"False")
            self.lockRotationCombo.insertItem(1,"True")
            if self.constraintObject.lockRotation: # not every constraint has a direction
                self.lockRotationCombo.setCurrentIndex(1)
            else:
                self.lockRotationCombo.setCurrentIndex(0)
            self.lockRotationCombo.setFixedHeight(32)
            self.mainLayout.addWidget(self.lockRotationCombo,self.lineNo,1)

            self.flipLockRotationButton = QtGui.QPushButton(self)
            self.flipLockRotationButton.setIcon(QtGui.QIcon(':/icons/a2p_LockRotation.svg'))
            self.flipLockRotationButton.setText("Toggle")
            self.flipLockRotationButton.setFixedHeight(32)
            QtCore.QObject.connect(self.flipLockRotationButton, QtCore.SIGNAL("clicked()"), self.flipLockRotation)
            self.mainLayout.addWidget(self.flipLockRotationButton,self.lineNo,2)

            self.lineNo += 1

        #==============================

        self.buttonPanel = QtGui.QWidget(self)
        self.buttonPanel.setFixedHeight(60)
        self.buttonPanel.setContentsMargins(4,4,4,4)
        self.buttonPanelLayout = QtGui.QHBoxLayout()

        self.deleteButton = QtGui.QPushButton(self.buttonPanel)
        self.deleteButton.setFixedHeight(32)
        self.deleteButton.setIcon(QtGui.QIcon(':/icons/a2p_DeleteConnections.svg')) #need new Icon
        self.deleteButton.setToolTip("Delete this constraint")
        self.deleteButton.setText("Delete this constraint")

        self.solveButton = QtGui.QPushButton(self.buttonPanel)
        self.solveButton.setFixedHeight(32)
        self.solveButton.setIcon(QtGui.QIcon(':/icons/a2p_Solver.svg'))
        self.solveButton.setToolTip("Solve constraints")
        self.solveButton.setText("Solve")

        self.acceptButton = QtGui.QPushButton(self.buttonPanel)
        self.acceptButton.setFixedHeight(32)
        self.acceptButton.setIcon(QtGui.QIcon(':/icons/a2p_CheckAssembly.svg')) #need new Icon
        self.acceptButton.setToolTip("Accept the settings")
        self.acceptButton.setText("Accept")
        #self.acceptButton.setDefault(True)

        self.buttonPanelLayout.addWidget(self.deleteButton)
        self.buttonPanelLayout.addWidget(self.solveButton)
        self.buttonPanelLayout.addWidget(self.acceptButton)
        self.buttonPanel.setLayout(self.buttonPanelLayout)

        self.mainLayout.addWidget(self.buttonPanel,self.lineNo,0,1,4)
        self.lineNo += 1

        #==============================
        self.setLayout(self.mainLayout)
        #self.updateGeometry()
        #self.neededHight = 50+(self.lineNo+1)*40
        #self.resize(self.neededHight,350)
        QtCore.QObject.connect(self.deleteButton, QtCore.SIGNAL("clicked()"), self.delete)
        QtCore.QObject.connect(self.solveButton, QtCore.SIGNAL("clicked()"), self.solve)
        QtCore.QObject.connect(self.acceptButton, QtCore.SIGNAL("clicked()"), self.accept)
Пример #4
0
def DVBalloonTest():
    path = os.path.dirname(os.path.abspath(__file__))
    print('TDBalloon path: ' + path)
    templateFileSpec = path + '/TestTemplate.svg'

    FreeCAD.newDocument("TDBalloon")
    FreeCAD.setActiveDocument("TDBalloon")
    FreeCAD.ActiveDocument = FreeCAD.getDocument("TDBalloon")

    #make source feature
    box = FreeCAD.ActiveDocument.addObject("Part::Box", "Box")
    sphere = FreeCAD.ActiveDocument.addObject("Part::Sphere", "Sphere")

    #make a page
    page = FreeCAD.ActiveDocument.addObject('TechDraw::DrawPage', 'Page')
    FreeCAD.ActiveDocument.addObject('TechDraw::DrawSVGTemplate', 'Template')
    FreeCAD.ActiveDocument.Template.Template = templateFileSpec
    FreeCAD.ActiveDocument.Page.Template = FreeCAD.ActiveDocument.Template
    page.Scale = 5.0
    #    page.ViewObject.show()   # unit tests run in console mode

    #make Views
    view1 = FreeCAD.ActiveDocument.addObject('TechDraw::DrawViewPart', 'View')
    FreeCAD.ActiveDocument.View.Source = [FreeCAD.ActiveDocument.Box]
    rc = page.addView(view1)
    view1.X = Units.Quantity(30.0, Units.Length)
    view1.Y = Units.Quantity(150.0, Units.Length)
    view2 = FreeCAD.activeDocument().addObject('TechDraw::DrawViewPart',
                                               'View001')
    FreeCAD.activeDocument().View001.Source = [FreeCAD.activeDocument().Sphere]
    rc = page.addView(view2)
    view2.X = Units.Quantity(220.0, Units.Length)
    view2.Y = Units.Quantity(150.0, Units.Length)
    FreeCAD.ActiveDocument.recompute()

    print("Place balloon")
    balloon1 = FreeCAD.ActiveDocument.addObject('TechDraw::DrawViewBalloon',
                                                'Balloon1')
    balloon1.SourceView = view1
    #    balloon1.OriginIsSet=1        ##OriginIsSet property removed March 2020
    balloon1.OriginX = view1.X + Units.Quantity(20.0, Units.Length)
    balloon1.OriginY = view1.Y + Units.Quantity(20.0, Units.Length)
    balloon1.Text = "1"
    balloon1.Y = balloon1.OriginX + Units.Quantity(20.0, Units.Length)
    balloon1.X = balloon1.OriginY + Units.Quantity(20.0, Units.Length)

    print("adding balloon1 to page")
    rc = page.addView(balloon1)

    balloon2 = FreeCAD.ActiveDocument.addObject('TechDraw::DrawViewBalloon',
                                                'Balloon2')
    balloon2.SourceView = view2
    #    balloon2.OriginIsSet=1
    balloon2.OriginX = view2.X + Units.Quantity(20.0, Units.Length)
    balloon2.OriginY = view2.Y + Units.Quantity(20.0, Units.Length)
    balloon2.Text = "2"
    balloon2.Y = balloon2.OriginX + Units.Quantity(20.0, Units.Length)
    balloon2.X = balloon2.OriginY + Units.Quantity(20.0, Units.Length)

    print("adding balloon2 to page")
    rc = page.addView(balloon2)

    FreeCAD.ActiveDocument.recompute()

    rc = False
    if ("Up-to-date" in balloon2.State) and ("Up-to-date" in balloon2.State):
        rc = True
    FreeCAD.closeDocument("TDBalloon")
    return rc
Пример #5
0
def getFromUi(value, unit, outputDim):
    quantity = Units.Quantity(str(value) + str(unit))
    return convert(quantity, outputDim)
Пример #6
0
    def testPrecedence(self):
        """ Precedence -- test precedence for relational operators and conditional operator. """
        sheet = self.doc.addObject('Spreadsheet::Sheet', 'Spreadsheet')
        sheet.set('A1', '=1 < 2 ? 3 : 4')
        sheet.set('A2', '=1 + 2 < 3 + 4 ? 5 + 6 : 7 + 8')
        sheet.set(
            'A3',
            '=1 + 2 * 1 < 3 + 4 ? 5 * 2 + 6 * 3 + 2 ^ 4 : 7 * 2 + 8 * 3 + 2 ^ 3'
        )
        sheet.set('A4', '=123')
        sheet.set('A5', '=123 + 321')
        sheet.set('A6', '=123 * 2 + 321')
        sheet.set('A7', '=123 * 2 + 333 / 3')
        sheet.set('A8', '=123 * (2 + 321)')
        sheet.set('A9', '=3 ^ 4')
        sheet.set('A10', '=3 ^ 4 * 2')
        sheet.set('A11', '=3 ^ (4 * 2)')
        sheet.set('A12', '=3 ^ 4 + 4')
        sheet.set('A13', '=1 + 4 / 2 + 5')
        sheet.set('A14', '=(3 + 6) / (1 + 2)')
        sheet.set('A15', '=1 * 2 / 3 * 4')
        sheet.set('A16', '=(1 * 2) / (3 * 4)')
        # Test associativity
        sheet.set(
            'A17', '=3 ^ 4 ^ 2'
        )  # exponentiation is left-associative; to follow excel, openoffice, matlab, octave
        sheet.set('A18', '=3 ^ (4 ^ 2)')  # exponentiation is left-associative
        sheet.set('A19', '=(3 ^ 4) ^ 2')  # exponentiation is left-associative
        sheet.set('A20', '=3 + 4 + 2')
        sheet.set('A21', '=3 + (4 + 2)')
        sheet.set('A22', '=(3 + 4) + 2')
        sheet.set('A23', '=3 - 4 - 2')
        sheet.set('A24', '=3 - (4 - 2)')
        sheet.set('A25', '=(3 - 4) - 2')
        sheet.set('A26', '=3 * 4 * 2')
        sheet.set('A27', '=3 * (4 * 2)')
        sheet.set('A28', '=(3 * 4) * 2')
        sheet.set('A29', '=3 / 4 / 2')
        sheet.set('A30', '=3 / (4 / 2)')
        sheet.set('A31', '=(3 / 4) / 2')
        sheet.set('A32', '=pi * 3')
        sheet.set('A33', '=A32 / 3')
        sheet.set('A34', '=1 < 2 ? <<A>> : <<B>>')
        sheet.set('A35', '=min(A32:A33)')
        sheet.set('A36', '=(1 < 2 ? 0 : 1) * 3')
        sheet.set('A37', '=8/(2^2*2)')
        sheet.set('A38', '=(2^2*2)/8')
        sheet.set('A39', '=2^(2*2)/8')
        sheet.set('A40', '=8/2^(2*2)')
        sheet.set('A41', '=-1')
        sheet.set('A42', '=-(1)')
        sheet.set('A43', '=-(1 + 1)')
        sheet.set('A44', '=-(1 - 1)')
        sheet.set('A45', '=-(-1 + 1)')
        sheet.set('A46', '=-(-1 + -1)')
        sheet.set('A47', '=+1')
        sheet.set('A48', '=+(1)')
        sheet.set('A49', '=+(1 + 1)')
        sheet.set('A50', '=+(1 - 1)')
        sheet.set('A51', '=+(-1 + 1)')
        sheet.set('A52', '=+(-1 + -1)')

        self.doc.addObject("Part::Cylinder", "Cylinder")
        self.doc.addObject("Part::Thickness", "Pipe")
        sheet.set('B1', '101')
        sheet.set('A53', '=-(-(B1-1)/2)')
        sheet.set('A54', '=-(Cylinder.Radius + Pipe.Value - 1"/2)')

        self.doc.recompute()
        self.assertEqual(sheet.getContents("A1"), "=1 < 2 ? 3 : 4")
        self.assertEqual(sheet.getContents("A2"),
                         "=1 + 2 < 3 + 4 ? 5 + 6 : 7 + 8")
        self.assertEqual(
            sheet.getContents("A3"),
            "=1 + 2 * 1 < 3 + 4 ? 5 * 2 + 6 * 3 + 2 ^ 4 : 7 * 2 + 8 * 3 + 2 ^ 3"
        )
        self.assertEqual(sheet.A1, 3)
        self.assertEqual(sheet.A2, 11)
        self.assertEqual(sheet.A3, 44)
        self.assertEqual(sheet.A4, 123)
        self.assertEqual(sheet.A5, 444)
        self.assertEqual(sheet.A6, 567)
        self.assertEqual(sheet.A7, 357)
        self.assertEqual(sheet.A8, 39729)
        self.assertEqual(sheet.A9, 81)
        self.assertEqual(sheet.A10, 162)
        self.assertEqual(sheet.A11, 6561)
        self.assertEqual(sheet.A12, 85)
        self.assertEqual(sheet.A13, 8)
        self.assertEqual(sheet.A14, 3)
        self.assertEqual(sheet.A15, 8.0 / 3)
        self.assertEqual(sheet.A16, 1.0 / 6)
        self.assertEqual(sheet.A17, 6561)
        self.assertEqual(sheet.A18, 43046721)
        self.assertEqual(sheet.A19, 6561)
        self.assertEqual(sheet.A20, 9)
        self.assertEqual(sheet.A21, 9)
        self.assertEqual(sheet.A22, 9)
        self.assertEqual(sheet.A23, -3)
        self.assertEqual(sheet.A24, 1)
        self.assertEqual(sheet.A25, -3)
        self.assertEqual(sheet.A26, 24)
        self.assertEqual(sheet.A27, 24)
        self.assertEqual(sheet.A28, 24)
        self.assertEqual(sheet.A29, 3.0 / 8)
        self.assertEqual(sheet.A30, 3.0 / 2)
        self.assertEqual(sheet.A31, 3.0 / 8)
        self.assertEqual(sheet.A37, 1)
        self.assertEqual(sheet.A38, 1)
        self.assertEqual(sheet.A39, 2)
        self.assertEqual(sheet.A40, 0.5)
        self.assertEqual(sheet.A41, -1)
        self.assertEqual(sheet.A42, -1)
        self.assertEqual(sheet.A43, -2)
        self.assertEqual(sheet.A44, 0)
        self.assertEqual(sheet.A45, 0)
        self.assertEqual(sheet.A46, 2)
        self.assertEqual(sheet.A47, 1)
        self.assertEqual(sheet.A48, 1)
        self.assertEqual(sheet.A49, 2)
        self.assertEqual(sheet.A50, 0)
        self.assertEqual(sheet.A51, 0)
        self.assertEqual(sheet.A52, -2)
        self.assertEqual(sheet.A53, 50)
        self.assertEqual(sheet.A54, Units.Quantity('9.7mm'))
        self.assertEqual(sheet.getContents('A1'), '=1 < 2 ? 3 : 4')
        self.assertEqual(sheet.getContents('A2'),
                         '=1 + 2 < 3 + 4 ? 5 + 6 : 7 + 8')
        self.assertEqual(
            sheet.getContents('A3'),
            '=1 + 2 * 1 < 3 + 4 ? 5 * 2 + 6 * 3 + 2 ^ 4 : 7 * 2 + 8 * 3 + 2 ^ 3'
        )
        self.assertEqual(sheet.getContents('A4'), '123')
        self.assertEqual(sheet.getContents('A5'), '=123 + 321')
        self.assertEqual(sheet.getContents('A6'), '=123 * 2 + 321')
        self.assertEqual(sheet.getContents('A7'), '=123 * 2 + 333 / 3')
        self.assertEqual(sheet.getContents('A8'), '=123 * (2 + 321)')
        self.assertEqual(sheet.getContents('A9'), '=3 ^ 4')
        self.assertEqual(sheet.getContents('A10'), '=3 ^ 4 * 2')
        self.assertEqual(sheet.getContents('A11'), '=3 ^ (4 * 2)')
        self.assertEqual(sheet.getContents('A12'), '=3 ^ 4 + 4')
        self.assertEqual(sheet.getContents('A13'), '=1 + 4 / 2 + 5')
        self.assertEqual(sheet.getContents('A14'), '=(3 + 6) / (1 + 2)')
        self.assertEqual(sheet.getContents('A15'), '=1 * 2 / 3 * 4')
        self.assertEqual(sheet.getContents('A16'), '=1 * 2 / (3 * 4)')
        self.assertEqual(sheet.getContents('A17'), '=3 ^ 4 ^ 2')
        self.assertEqual(sheet.getContents('A18'), '=3 ^ (4 ^ 2)')
        self.assertEqual(sheet.getContents('A19'), '=3 ^ 4 ^ 2')
        self.assertEqual(sheet.getContents('A20'), '=3 + 4 + 2')
        self.assertEqual(sheet.getContents('A21'), '=3 + 4 + 2')
        self.assertEqual(sheet.getContents('A22'), '=3 + 4 + 2')
        self.assertEqual(sheet.getContents('A23'), '=3 - 4 - 2')
        self.assertEqual(sheet.getContents('A24'), '=3 - (4 - 2)')
        self.assertEqual(sheet.getContents('A25'), '=3 - 4 - 2')
        self.assertEqual(sheet.getContents('A26'), '=3 * 4 * 2')
        self.assertEqual(sheet.getContents('A27'), '=3 * 4 * 2')
        self.assertEqual(sheet.getContents('A28'), '=3 * 4 * 2')
        self.assertEqual(sheet.getContents('A29'), '=3 / 4 / 2')
        self.assertEqual(sheet.getContents('A30'), '=3 / (4 / 2)')
        self.assertEqual(sheet.getContents('A31'), '=3 / 4 / 2')
        self.assertEqual(sheet.getContents('A32'), '=pi * 3')
        self.assertEqual(sheet.getContents('A33'), '=A32 / 3')
        self.assertEqual(sheet.getContents('A34'), '=1 < 2 ? <<A>> : <<B>>')
        self.assertEqual(sheet.getContents('A35'), '=min(A32:A33)')
        self.assertEqual(sheet.getContents('A36'), '=(1 < 2 ? 0 : 1) * 3')
        self.assertEqual(sheet.getContents('A37'), '=8 / (2 ^ 2 * 2)')
        self.assertEqual(sheet.getContents('A38'), '=2 ^ 2 * 2 / 8')
        self.assertEqual(sheet.getContents('A39'), '=2 ^ (2 * 2) / 8')
        self.assertEqual(sheet.getContents('A40'), '=8 / 2 ^ (2 * 2)')
        self.assertEqual(sheet.getContents('A41'), '=-1')
        self.assertEqual(sheet.getContents('A42'), '=-1')
        self.assertEqual(sheet.getContents('A43'), '=-(1 + 1)')
        self.assertEqual(sheet.getContents('A44'), '=-(1 - 1)')
        self.assertEqual(sheet.getContents('A45'), '=-(-1 + 1)')
        self.assertEqual(sheet.getContents('A46'), '=-(-1 + -1)')
        self.assertEqual(sheet.getContents('A47'), '=+1')
        self.assertEqual(sheet.getContents('A48'), '=+1')
        self.assertEqual(sheet.getContents('A49'), '=+(1 + 1)')
        self.assertEqual(sheet.getContents('A50'), '=+(1 - 1)')
        self.assertEqual(sheet.getContents('A51'), '=+(-1 + 1)')
        self.assertEqual(sheet.getContents('A52'), '=+(-1 + -1)')
Пример #7
0
    def testAggregates(self):
        """ Test all aggregate functions """
        sheet = self.doc.addObject('Spreadsheet::Sheet', 'Spreadsheet')
        sheet = self.doc.addObject('Spreadsheet::Sheet', 'Spreadsheet')
        sheet.set('B13', '4')
        sheet.set('B14', '5')
        sheet.set('B15', '6')
        sheet.set('C13', '4mm')
        sheet.set('C14', '5mm')
        sheet.set('C15', '6mm')
        sheet.set('C16', '6')

        sheet.set('A1', '=sum(1)')
        sheet.set('A2', '=sum(1;2)')
        sheet.set('A3', '=sum(1;2;3)')
        sheet.set('A4', '=sum(1;2;3;B13)')
        sheet.set('A5', '=sum(1;2;3;B13:B15)')

        sheet.set('B1', '=min(1)')
        sheet.set('B2', '=min(1;2)')
        sheet.set('B3', '=min(1;2;3)')
        sheet.set('B4', '=min(1;2;3;B13)')
        sheet.set('B5', '=min(1;2;3;B13:B15)')

        sheet.set('C1', '=max(1)')
        sheet.set('C2', '=max(1;2)')
        sheet.set('C3', '=max(1;2;3)')
        sheet.set('C4', '=max(1;2;3;B13)')
        sheet.set('C5', '=max(1;2;3;B13:B15)')

        sheet.set('D1', '=stddev(1)')
        sheet.set('D2', '=stddev(1;2)')
        sheet.set('D3', '=stddev(1;2;3)')
        sheet.set('D4', '=stddev(1;2;3;B13)')
        sheet.set('D5', '=stddev(1;2;3;B13:B15)')

        sheet.set('E1', '=count(1)')
        sheet.set('E2', '=count(1;2)')
        sheet.set('E3', '=count(1;2;3)')
        sheet.set('E4', '=count(1;2;3;B13)')
        sheet.set('E5', '=count(1;2;3;B13:B15)')

        sheet.set('F1', '=average(1)')
        sheet.set('F2', '=average(1;2)')
        sheet.set('F3', '=average(1;2;3)')
        sheet.set('F4', '=average(1;2;3;B13)')
        sheet.set('F5', '=average(1;2;3;B13:B15)')

        sheet.set('G1', '=average(C13:C15)')
        sheet.set('G2', '=min(C13:C15)')
        sheet.set('G3', '=max(C13:C15)')
        sheet.set('G4', '=count(C13:C15)')
        sheet.set('G5', '=stddev(C13:C15)')
        sheet.set('G6', '=sum(C13:C15)')

        sheet.set('H1', '=average(C13:C16)')
        sheet.set('H2', '=min(C13:C16)')
        sheet.set('H3', '=max(C13:C16)')
        sheet.set('H4', '=count(C13:C16)')
        sheet.set('H5', '=stddev(C13:C16)')
        sheet.set('H6', '=sum(C13:C16)')

        self.doc.recompute()
        self.assertEqual(sheet.A1, 1)
        self.assertEqual(sheet.A2, 3)
        self.assertEqual(sheet.A3, 6)
        self.assertEqual(sheet.A4, 10)
        self.assertEqual(sheet.A5, 21)

        self.assertEqual(sheet.B1, 1)
        self.assertEqual(sheet.B2, 1)
        self.assertEqual(sheet.B3, 1)
        self.assertEqual(sheet.B4, 1)
        self.assertEqual(sheet.B5, 1)

        self.assertEqual(sheet.C1, 1)
        self.assertEqual(sheet.C2, 2)
        self.assertEqual(sheet.C3, 3)
        self.assertEqual(sheet.C4, 4)
        self.assertEqual(sheet.C5, 6)

        self.assertEqual(
            sheet.D1,
            u'ERR: Invalid number of entries: at least two required.')
        self.assertEqual(sheet.D2, 0.7071067811865476)
        self.assertEqual(sheet.D3, 1.0)
        self.assertEqual(sheet.D4, 1.2909944487358056)
        self.assertEqual(sheet.D5, 1.8708286933869707)

        self.assertEqual(sheet.E1, 1)
        self.assertEqual(sheet.E2, 2)
        self.assertEqual(sheet.E3, 3)
        self.assertEqual(sheet.E4, 4)
        self.assertEqual(sheet.E5, 6)

        self.assertEqual(sheet.F1, 1)
        self.assertEqual(sheet.F2, (1.0 + 2.0) / 2.0)
        self.assertEqual(sheet.F3, (1.0 + 2 + 3) / 3)
        self.assertEqual(sheet.F4, (1.0 + 2 + 3 + 4) / 4)
        self.assertEqual(sheet.F5, (1.0 + 2 + 3 + 4 + 5 + 6) / 6)

        self.assertEqual(sheet.G1, Units.Quantity('5 mm'))
        self.assertEqual(sheet.G2, Units.Quantity('4 mm'))
        self.assertEqual(sheet.G3, Units.Quantity('6 mm'))
        self.assertEqual(sheet.G4, 3)
        self.assertEqual(sheet.G5, Units.Quantity('1 mm'))
        self.assertEqual(sheet.G6, Units.Quantity('15 mm'))

        self.assertEqual(
            sheet.H1,
            u'ERR: Quantity::operator +=(): Unit mismatch in plus operation')
        self.assertEqual(
            sheet.H2,
            u'ERR: Quantity::operator <(): quantities need to have same unit to compare'
        )
        self.assertEqual(
            sheet.H3,
            u'ERR: Quantity::operator >(): quantities need to have same unit to compare'
        )
        self.assertEqual(sheet.H4, 4)
        self.assertEqual(
            sheet.H5,
            u'ERR: Quantity::operator +(): Unit mismatch in minus operation')
        self.assertEqual(
            sheet.H6,
            u'ERR: Quantity::operator +=(): Unit mismatch in plus operation')
Пример #8
0
    def __init__(self):
        self.name = "Orthogonal array"
        _log(_tr("Task panel:") + " {}".format(_tr(self.name)))

        # The .ui file must be loaded into an attribute
        # called `self.form` so that it is displayed in the task panel.
        ui_file = ":/ui/TaskPanel_OrthoArray.ui"
        self.form = Gui.PySideUic.loadUi(ui_file)

        icon_name = "Draft_Array"
        svg = ":/icons/" + icon_name
        pix = QtGui.QPixmap(svg)
        icon = QtGui.QIcon.fromTheme(icon_name, QtGui.QIcon(svg))
        self.form.setWindowIcon(icon)
        self.form.setWindowTitle(_tr(self.name))

        self.form.label_icon.setPixmap(pix.scaled(32, 32))

        # -------------------------------------------------------------------
        # Default values for the internal function,
        # and for the task panel interface
        start_x = U.Quantity(100.0, App.Units.Length)
        start_y = start_x
        start_z = start_x
        length_unit = start_x.getUserPreferred()[2]

        self.v_x = App.Vector(start_x.Value, 0, 0)
        self.v_y = App.Vector(0, start_y.Value, 0)
        self.v_z = App.Vector(0, 0, start_z.Value)

        self.form.input_X_x.setProperty('rawValue', self.v_x.x)
        self.form.input_X_x.setProperty('unit', length_unit)
        self.form.input_X_y.setProperty('rawValue', self.v_x.y)
        self.form.input_X_y.setProperty('unit', length_unit)
        self.form.input_X_z.setProperty('rawValue', self.v_x.z)
        self.form.input_X_z.setProperty('unit', length_unit)

        self.form.input_Y_x.setProperty('rawValue', self.v_y.x)
        self.form.input_Y_x.setProperty('unit', length_unit)
        self.form.input_Y_y.setProperty('rawValue', self.v_y.y)
        self.form.input_Y_y.setProperty('unit', length_unit)
        self.form.input_Y_z.setProperty('rawValue', self.v_y.z)
        self.form.input_Y_z.setProperty('unit', length_unit)

        self.form.input_Z_x.setProperty('rawValue', self.v_z.x)
        self.form.input_Z_x.setProperty('unit', length_unit)
        self.form.input_Z_y.setProperty('rawValue', self.v_z.y)
        self.form.input_Z_y.setProperty('unit', length_unit)
        self.form.input_Z_z.setProperty('rawValue', self.v_z.z)
        self.form.input_Z_z.setProperty('unit', length_unit)

        self.n_x = 2
        self.n_y = 2
        self.n_z = 1

        self.form.spinbox_n_X.setValue(self.n_x)
        self.form.spinbox_n_Y.setValue(self.n_y)
        self.form.spinbox_n_Z.setValue(self.n_z)

        self.fuse = utils.get_param("Draft_array_fuse", False)
        self.use_link = utils.get_param("Draft_array_Link", True)

        self.form.checkbox_fuse.setChecked(self.fuse)
        self.form.checkbox_link.setChecked(self.use_link)
        # -------------------------------------------------------------------

        # Some objects need to be selected before we can execute the function.
        self.selection = None

        # This is used to test the input of the internal function.
        # It should be changed to True before we can execute the function.
        self.valid_input = False

        self.set_widget_callbacks()

        self.tr_true = QT_TRANSLATE_NOOP("Draft", "True")
        self.tr_false = QT_TRANSLATE_NOOP("Draft", "False")
Пример #9
0
def parse(pathobj):
    global DRILL_RETRACT_MODE
    global MOTION_MODE
    global CURRENT_X
    global CURRENT_Y
    global CURRENT_Z

    out = ''
    lastcommand = None
    precision_string = '.' + str(PRECISION) + 'f'

    params = [
        'X', 'Y', 'Z', 'A', 'B', 'C', 'U', 'V', 'W', 'I', 'J', 'K', 'F', 'S',
        'T', 'Q', 'R', 'L', 'P'
    ]

    if hasattr(pathobj, 'Group'):  # We have a compound or project.
        if OUTPUT_COMMENTS:
            out += linenumber() + '(Compound: ' + pathobj.Label + ')\n'
        for p in pathobj.Group:
            out += parse(p)
        return out

    else:  # Parsing simple path
        # groups might contain non-path things like stock.
        if not hasattr(pathobj, 'Path'):
            return out

        if OUTPUT_COMMENTS and OUTPUT_PATH:
            out += linenumber() + '(Path: ' + pathobj.Label + ')\n'

        for c in pathobj.Path.Commands:
            outlist = []
            command = c.Name
            outlist.append(command)
            # Debug:
            # print('pathobj.Path.Commands:', c)

            # If modal is True, delete duplicate commands:
            if MODAL:
                if command == lastcommand:
                    outlist.pop(0)

            # Add the remaining parameters in order:
            for param in params:
                if param in c.Parameters:
                    if param == 'F':
                        if command not in RAPID_MOVES:
                            feedRate = Units.Quantity(c.Parameters['F'],
                                                      FreeCAD.Units.Velocity)
                            if feedRate.getValueAs(UNIT_FEED_FORMAT) > 0.0:
                                outlist.append(param + format(
                                    float(feedRate.getValueAs(
                                        UNIT_FEED_FORMAT)), precision_string))
                    elif param in ['T', 'H', 'D', 'S', 'P', 'L']:
                        outlist.append(param + str(c.Parameters[param]))
                    elif param in ['A', 'B', 'C']:
                        outlist.append(
                            param +
                            format(c.Parameters[param], precision_string))
                    # [X, Y, Z, U, V, W, I, J, K, R, Q]
                    else:
                        pos = Units.Quantity(c.Parameters[param],
                                             FreeCAD.Units.Length)
                        outlist.append(
                            param + format(float(pos.getValueAs(UNIT_FORMAT)),
                                           precision_string))

            # Store the latest command:
            lastcommand = command

            # Capture the current position for subsequent calculations:
            if command in MOTION_COMMANDS:
                if 'X' in c.Parameters:
                    CURRENT_X = Units.Quantity(c.Parameters['X'],
                                               FreeCAD.Units.Length)
                if 'Y' in c.Parameters:
                    CURRENT_Y = Units.Quantity(c.Parameters['Y'],
                                               FreeCAD.Units.Length)
                if 'Z' in c.Parameters:
                    CURRENT_Z = Units.Quantity(c.Parameters['Z'],
                                               FreeCAD.Units.Length)

            if command in ('G98', 'G99'):
                DRILL_RETRACT_MODE = command

            if TRANSLATE_DRILL_CYCLES:
                if command in ('G81', 'G82', 'G83'):
                    out += drill_translate(outlist, command, c.Parameters)
                    # Erase the line just translated:
                    outlist = []

            if SPINDLE_WAIT > 0:
                if command in ('M3', 'M03', 'M4', 'M04'):
                    out += linenumber() + format_outlist(outlist) + '\n'
                    # Marlin: P for milliseconds, S for seconds, change P to S
                    out += linenumber()
                    out += format_outlist(['G4', 'S%s' % SPINDLE_WAIT])
                    out += '\n'
                    outlist = []

            # Check for Tool Change:
            if command in ('M6', 'M06'):
                if OUTPUT_COMMENTS:
                    out += linenumber() + '(Begin toolchange)\n'
                if OUTPUT_TOOL_CHANGE:
                    for line in TOOL_CHANGE.splitlines(True):
                        out += linenumber() + line
                if not OUTPUT_TOOL_CHANGE and OUTPUT_COMMENTS:
                    outlist[0] = '(' + outlist[0]
                    outlist[-1] = outlist[-1] + ')'
                if not OUTPUT_TOOL_CHANGE and not OUTPUT_COMMENTS:
                    outlist = []

            if command == 'message':
                if OUTPUT_COMMENTS:
                    outlist.pop(0)  # remove the command
                else:
                    out = []

            if command in SUPPRESS_COMMANDS:
                outlist[0] = '(' + outlist[0]
                outlist[-1] = outlist[-1] + ')'

            # Remove embedded comments:
            if not OUTPUT_COMMENTS:
                tmplist = []
                list_index = 0
                while list_index < len(outlist):
                    left_index = outlist[list_index].find('(')
                    if left_index == -1:  # Not a comment
                        tmplist.append(outlist[list_index])
                    else:  # This line contains a comment, and possibly more
                        right_index = outlist[list_index].find(')')
                        comment_area = outlist[list_index][
                            left_index:right_index + 1]
                        line_minus_comment = outlist[list_index].replace(
                            comment_area, '').strip()
                        if line_minus_comment:
                            # Line contained more than just a comment
                            tmplist.append(line_minus_comment)
                    list_index += 1
                # Done removing comments
                outlist = tmplist

            # Prepend a line number and append a newline
            if len(outlist) >= 1:
                out += linenumber() + format_outlist(outlist) + '\n'

    return out
Пример #10
0
 def check_prerequisites(self):
     from FreeCAD import Units
     message = ""
     # analysis
     if not self.analysis:
         message += "No active Analysis\n"
     if self.analysis_type not in self.known_analysis_types:
         message += "Unknown analysis type: {}\n".format(self.analysis_type)
     if not self.working_dir:
         message += "Working directory not set\n"
     import os
     if not (os.path.isdir(self.working_dir)):
         message += "Working directory \'{}\' doesn't exist.".format(
             self.working_dir)
     # solver
     if not self.solver:
         message += "No solver object defined in the analysis\n"
     else:
         if self.analysis_type == "frequency":
             if not hasattr(self.solver, "EigenmodeHighLimit"):
                 message += "Frequency analysis: Solver has no EigenmodeHighLimit.\n"
             elif not hasattr(self.solver, "EigenmodeLowLimit"):
                 message += "Frequency analysis: Solver has no EigenmodeLowLimit.\n"
             elif not hasattr(self.solver, "EigenmodesCount"):
                 message += "Frequency analysis: Solver has no EigenmodesCount.\n"
         if hasattr(self.solver, "MaterialNonlinearity"
                    ) and self.solver.MaterialNonlinearity == "nonlinear":
             if not self.materials_nonlinear:
                 message += "Solver is set to nonlinear materials, but there is no nonlinear material in the analysis.\n"
             if self.solver.SolverType == 'FemSolverCalculix' and self.solver.GeometricalNonlinearity != "nonlinear":
                 # nonlinear geometry --> should be set https://forum.freecadweb.org/viewtopic.php?f=18&t=23101&p=180489#p180489
                 message += "Solver CalculiX triggers nonlinear geometry for nonlinear material, thus it should to be set too.\n"
     # mesh
     if not self.mesh:
         message += "No mesh object defined in the analysis\n"
     if self.mesh:
         if self.mesh.FemMesh.VolumeCount == 0 and self.mesh.FemMesh.FaceCount > 0 and not self.shell_thicknesses:
             message += "FEM mesh has no volume elements, either define a shell thicknesses or provide a FEM mesh with volume elements.\n"
         if self.mesh.FemMesh.VolumeCount == 0 and self.mesh.FemMesh.FaceCount == 0 and self.mesh.FemMesh.EdgeCount > 0 and not self.beam_sections and not self.fluid_sections:
             message += "FEM mesh has no volume and no shell elements, either define a beam/fluid section or provide a FEM mesh with volume elements.\n"
         if self.mesh.FemMesh.VolumeCount == 0 and self.mesh.FemMesh.FaceCount == 0 and self.mesh.FemMesh.EdgeCount == 0:
             message += "FEM mesh has neither volume nor shell or edge elements. Provide a FEM mesh with elements!\n"
     # material linear and nonlinear
     if not self.materials_linear:
         message += "No material object defined in the analysis\n"
     has_no_references = False
     for m in self.materials_linear:
         if len(m['Object'].References) == 0:
             if has_no_references is True:
                 message += "More than one material has an empty references list (Only one empty references list is allowed!).\n"
             has_no_references = True
     mat_ref_shty = ''
     for m in self.materials_linear:
         ref_shty = get_refshape_type(m['Object'])
         if not mat_ref_shty:
             mat_ref_shty = ref_shty
         if mat_ref_shty and ref_shty and ref_shty != mat_ref_shty:  # mat_ref_shty could be empty in one material, only the not empty ones should have the same shape type
             message += 'Some material objects do not have the same reference shape type (all material objects must have the same reference shape type, at the moment).\n'
     for m in self.materials_linear:
         mat_map = m['Object'].Material
         mat_obj = m['Object']
         if mat_obj.Category == 'Solid':
             if 'YoungsModulus' in mat_map:
                 # print(Units.Quantity(mat_map['YoungsModulus']).Value)
                 if not Units.Quantity(mat_map['YoungsModulus']).Value:
                     message += "Value of YoungsModulus is set to 0.0.\n"
             else:
                 message += "No YoungsModulus defined for at least one material.\n"
             if 'PoissonRatio' not in mat_map:
                 message += "No PoissonRatio defined for at least one material.\n"  # PoissonRatio is allowed to be 0.0 (in ccx), but it should be set anyway.
         if self.analysis_type == "frequency" or self.selfweight_constraints:
             if 'Density' not in mat_map:
                 message += "No Density defined for at least one material.\n"
         if self.analysis_type == "thermomech":
             if 'ThermalConductivity' in mat_map:
                 if not Units.Quantity(
                         mat_map['ThermalConductivity']).Value:
                     message += "Value of ThermalConductivity is set to 0.0.\n"
             else:
                 message += "Thermomechanical analysis: No ThermalConductivity defined for at least one material.\n"
             if 'ThermalExpansionCoefficient' not in mat_map and mat_obj.Category == 'Solid':
                 message += "Thermomechanical analysis: No ThermalExpansionCoefficient defined for at least one material.\n"  # allowed to be 0.0 (in ccx)
             if 'SpecificHeat' not in mat_map:
                 message += "Thermomechanical analysis: No SpecificHeat defined for at least one material.\n"  # allowed to be 0.0 (in ccx)
     for m in self.materials_linear:
         has_nonlinear_material = False
         for nlm in self.materials_nonlinear:
             if nlm['Object'].LinearBaseMaterial == m['Object']:
                 if has_nonlinear_material is False:
                     has_nonlinear_material = True
                 else:
                     message += "At least two nonlinear materials use the same linear base material. Only one nonlinear material for each linear material allowed.\n"
     # which analysis needs which constraints
     # no check in the regard of loads existence (constraint force, pressure, self weight) is done because an analysis without loads at all is an valid analysis too
     if self.analysis_type == "static":
         if not (self.fixed_constraints or self.displacement_constraints):
             message += "Static analysis: Neither constraint fixed nor constraint displacement defined.\n"
     if self.analysis_type == "thermomech":
         if not self.initialtemperature_constraints:
             if not self.fluid_sections:
                 message += "Thermomechanical analysis: No initial temperature defined.\n"
         if len(self.initialtemperature_constraints) > 1:
             message += "Thermomechanical analysis: Only one initial temperature is allowed.\n"
     # constraints
     # fixed
     if self.fixed_constraints:
         for c in self.fixed_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint fixed has an empty reference.\n"
     # displacement
     if self.displacement_constraints:
         for di in self.displacement_constraints:
             if len(di['Object'].References) == 0:
                 message += "At least one constraint displacement has an empty reference.\n"
     # plane rotation
     if self.planerotation_constraints:
         for c in self.planerotation_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint plane rotation has an empty reference.\n"
     # contact
     if self.contact_constraints:
         for c in self.contact_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint contact has an empty reference.\n"
     # transform
     if self.transform_constraints:
         for c in self.transform_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint transform has an empty reference.\n"
     # pressure
     if self.pressure_constraints:
         for c in self.pressure_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint pressure has an empty reference.\n"
     # force
     if self.force_constraints:
         for c in self.force_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint force has an empty reference.\n"
     # temperature
     if self.temperature_constraints:
         for c in self.temperature_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint temperature has an empty reference.\n"
     # heat flux
     if self.heatflux_constraints:
         for c in self.heatflux_constraints:
             if len(c['Object'].References) == 0:
                 message += "At least one constraint heat flux has an empty reference.\n"
     # beam section
     if self.beam_sections:
         if self.shell_thicknesses:
             # this needs to be checked only once either here or in shell_thicknesses
             message += "Beam Sections and shell thicknesses in one analysis is not supported at the moment.\n"
         if self.fluid_sections:
             # this needs to be checked only once either here or in shell_thicknesses
             message += "Beam Sections and Fluid Sections in one analysis is not supported at the moment.\n"
         has_no_references = False
         for b in self.beam_sections:
             if len(b['Object'].References) == 0:
                 if has_no_references is True:
                     message += "More than one beam section has an empty references list (Only one empty references list is allowed!).\n"
                 has_no_references = True
         if self.mesh:
             if self.mesh.FemMesh.FaceCount > 0 or self.mesh.FemMesh.VolumeCount > 0:
                 message += "Beam sections defined but FEM mesh has volume or shell elements.\n"
             if self.mesh.FemMesh.EdgeCount == 0:
                 message += "Beam sections defined but FEM mesh has no edge elements.\n"
     # shell thickness
     if self.shell_thicknesses:
         has_no_references = False
         for s in self.shell_thicknesses:
             if len(s['Object'].References) == 0:
                 if has_no_references is True:
                     message += "More than one shell thickness has an empty references list (Only one empty references list is allowed!).\n"
                 has_no_references = True
         if self.mesh:
             if self.mesh.FemMesh.VolumeCount > 0:
                 message += "Shell thicknesses defined but FEM mesh has volume elements.\n"
             if self.mesh.FemMesh.FaceCount == 0:
                 message += "Shell thicknesses defined but FEM mesh has no shell elements.\n"
     # fluid section
     if self.fluid_sections:
         if not self.selfweight_constraints:
             message += "A fluid network analysis requires self weight constraint to be applied"
         if self.analysis_type != "thermomech":
             message += "A fluid network analysis can only be done in a thermomech analysis"
         has_no_references = False
         for f in self.fluid_sections:
             if len(f['Object'].References) == 0:
                 if has_no_references is True:
                     message += "More than one fluid section has an empty references list (Only one empty references list is allowed!).\n"
                 has_no_references = True
         if self.mesh:
             if self.mesh.FemMesh.FaceCount > 0 or self.mesh.FemMesh.VolumeCount > 0:
                 message += "Fluid sections defined but FEM mesh has volume or shell elements.\n"
             if self.mesh.FemMesh.EdgeCount == 0:
                 message += "Fluid sections defined but FEM mesh has no edge elements.\n"
     return message
Пример #11
0
    def onChanged(self, vobj, prop):
        if prop in ["Text", "Decimals", "ShowUnit"]:
            if hasattr(self, "text1") and hasattr(self, "text2") and hasattr(
                    vobj, "Text"):
                self.text1.string.deleteValues(0)
                self.text2.string.deleteValues(0)
                text1 = []
                text2 = []
                first = True
                for t in vobj.Text:
                    if t:
                        if hasattr(vobj.Object, "Area"):
                            from FreeCAD import Units
                            q = Units.Quantity(vobj.Object.Area,
                                               Units.Area).getUserPreferred()
                            qt = vobj.Object.Area / q[1]
                            if hasattr(vobj, "Decimals"):
                                if vobj.Decimals == 0:
                                    qt = str(int(qt))
                                else:
                                    f = "%." + str(abs(vobj.Decimals)) + "f"
                                    qt = f % qt
                            else:
                                qt = str(qt)
                            if hasattr(vobj, "ShowUnit"):
                                if vobj.ShowUnit:
                                    qt = qt + q[2].replace(
                                        "^2", u"\xb2")  # square symbol
                            t = t.replace("$area", qt)
                        t = t.replace("$label", vobj.Object.Label)
                        if hasattr(vobj.Object, "Tag"):
                            t = t.replace("$tag", vobj.Object.Tag)
                        if hasattr(vobj.Object, "FinishFloor"):
                            t = t.replace("$floor", vobj.Object.FinishFloor)
                        if hasattr(vobj.Object, "FinishWalls"):
                            t = t.replace("$walls", vobj.Object.FinishWalls)
                        if hasattr(vobj.Object, "FinishCeiling"):
                            t = t.replace("$ceiling",
                                          vobj.Object.FinishCeiling)
                        if first:
                            text1.append(t.encode("utf8"))
                        else:
                            text2.append(t.encode("utf8"))
                    first = False
                if text1:
                    self.text1.string.setValues(text1)
                if text2:
                    self.text2.string.setValues(text2)

        elif prop == "FontName":
            if hasattr(self, "font") and hasattr(vobj, "FontName"):
                self.font.name = str(vobj.FontName)

        elif (prop == "FontSize"):
            if hasattr(self, "font") and hasattr(vobj, "FontSize"):
                self.font.size = vobj.FontSize.Value

        elif (prop == "FirstLine"):
            if hasattr(self, "header") and hasattr(
                    vobj, "FontSize") and hasattr(vobj, "FirstLine"):
                scale = vobj.FirstLine.Value / vobj.FontSize.Value
                self.header.scaleFactor.setValue([scale, scale, scale])

        elif prop == "TextColor":
            if hasattr(self, "color") and hasattr(vobj, "TextColor"):
                c = vobj.TextColor
                self.color.rgb.setValue(c[0], c[1], c[2])

        elif prop == "TextPosition":
            if hasattr(self, "coords") and hasattr(self, "header") and hasattr(
                    vobj, "TextPosition") and hasattr(vobj, "FirstLine"):
                pos = self.getTextPosition(vobj)
                self.coords.translation.setValue([pos.x, pos.y, pos.z])
                up = vobj.FirstLine.Value * vobj.LineSpacing
                self.header.translation.setValue([0, up, 0])

        elif prop == "LineSpacing":
            if hasattr(self, "text1") and hasattr(self, "text2") and hasattr(
                    vobj, "LineSpacing"):
                self.text1.spacing = vobj.LineSpacing
                self.text2.spacing = vobj.LineSpacing
                self.onChanged(vobj, "TextPosition")

        elif prop == "TextAlign":
            if hasattr(self, "text1") and hasattr(self, "text2") and hasattr(
                    vobj, "TextAlign"):
                from pivy import coin
                if vobj.TextAlign == "Center":
                    self.text1.justification = coin.SoAsciiText.CENTER
                    self.text2.justification = coin.SoAsciiText.CENTER
                elif vobj.TextAlign == "Right":
                    self.text1.justification = coin.SoAsciiText.RIGHT
                    self.text2.justification = coin.SoAsciiText.RIGHT
                else:
                    self.text1.justification = coin.SoAsciiText.LEFT
                    self.text2.justification = coin.SoAsciiText.LEFT
Пример #12
0
def parse(pathobj):
    global PRECISION
    global UNIT_FORMAT
    global UNIT_SPEED_FORMAT

    out = ""
    lastcommand = None

    precision_string = "." + str(PRECISION) + "f"

    # params = ['X','Y','Z','A','B','I','J','K','F','S'] #This list control the order of parameters
    params = ["X", "Y", "Z", "A", "B", "I", "J", "F", "S", "T", "Q", "R", "L"]

    if hasattr(pathobj, "Group"):  # We have a compound or project.
        if OUTPUT_COMMENTS:
            out += linenumber() + "(compound: " + pathobj.Label + ")\n"
        for p in pathobj.Group:
            out += parse(p)
        return out
    else:  # parsing simple path

        if not hasattr(
                pathobj,
                "Path"):  # groups might contain non-path things like stock.
            return out

        if OUTPUT_COMMENTS:
            out += linenumber() + "(Path: " + pathobj.Label + ")\n"

        for c in pathobj.Path.Commands:
            outstring = []
            command = c.Name
            outstring.append(command)
            # if modal: only print the command if it is not the same as the last one
            if MODAL is True:
                if command == lastcommand:
                    outstring.pop(0)

            # Now add the remaining parameters in order
            for param in params:
                if param in c.Parameters:
                    if param == "F":
                        speed = Units.Quantity(c.Parameters["F"],
                                               FreeCAD.Units.Velocity)
                        if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0:
                            outstring.append(param + format(
                                float(speed.getValueAs(UNIT_SPEED_FORMAT)),
                                precision_string,
                            ))
                    elif param == "S":
                        outstring.append(
                            param +
                            format(c.Parameters[param], precision_string))
                    elif param == "T":
                        outstring.append(
                            param +
                            format(c.Parameters["T"], precision_string))
                    else:
                        pos = Units.Quantity(c.Parameters[param],
                                             FreeCAD.Units.Length)
                        outstring.append(
                            param + format(float(pos.getValueAs(UNIT_FORMAT)),
                                           precision_string))

            # store the latest command
            lastcommand = command

            # Check for Tool Change:
            if command == "M6":
                if OUTPUT_COMMENTS:
                    out += linenumber() + "(begin toolchange)\n"
                for line in TOOL_CHANGE.splitlines(True):
                    out += linenumber() + line

            if command == "message":
                if OUTPUT_COMMENTS is False:
                    out = []
                else:
                    outstring.pop(0)  # remove the command

            # prepend a line number and append a newline
            if len(outstring) >= 1:
                if OUTPUT_LINE_NUMBERS:
                    outstring.insert(0, (linenumber()))

                # append the line to the final output
                for w in outstring:
                    out += w + COMMAND_SPACE
                out = out.strip() + "\n"

        return out
Пример #13
0
    def writeMeshCase(self):
        """ Collect case settings, and finally build a runnable case. """
        CfdTools.cfdMessage(
            "Populating mesh dictionaries in folder {}\n".format(
                self.meshCaseDir))

        if self.mesh_obj.MeshUtility == "cfMesh":
            self.cf_settings['ClMax'] = self.clmax * self.scale

            if len(self.cf_settings['BoundaryLayers']) > 0:
                self.cf_settings['BoundaryLayerPresent'] = True
            else:
                self.cf_settings['BoundaryLayerPresent'] = False
            if len(self.cf_settings["InternalRegions"]) > 0:
                self.cf_settings['InternalRefinementRegionsPresent'] = True
            else:
                self.cf_settings['InternalRefinementRegionsPresent'] = False

        elif self.mesh_obj.MeshUtility == "snappyHexMesh":
            bound_box = self.part_obj.Shape.BoundBox
            bC = 5  # Number of background mesh buffer cells
            x_min = (bound_box.XMin - bC * self.clmax) * self.scale
            x_max = (bound_box.XMax + bC * self.clmax) * self.scale
            y_min = (bound_box.YMin - bC * self.clmax) * self.scale
            y_max = (bound_box.YMax + bC * self.clmax) * self.scale
            z_min = (bound_box.ZMin - bC * self.clmax) * self.scale
            z_max = (bound_box.ZMax + bC * self.clmax) * self.scale
            cells_x = int(math.ceil(bound_box.XLength / self.clmax) + 2 * bC)
            cells_y = int(math.ceil(bound_box.YLength / self.clmax) + 2 * bC)
            cells_z = int(math.ceil(bound_box.ZLength / self.clmax) + 2 * bC)

            snappy_settings = self.snappy_settings
            snappy_settings['BlockMesh'] = {
                "xMin": x_min,
                "xMax": x_max,
                "yMin": y_min,
                "yMax": y_max,
                "zMin": z_min,
                "zMax": z_max,
                "cellsX": cells_x,
                "cellsY": cells_y,
                "cellsZ": cells_z
            }

            inside_x = Units.Quantity(
                self.mesh_obj.PointInMesh.get('x')).Value * self.scale
            inside_y = Units.Quantity(
                self.mesh_obj.PointInMesh.get('y')).Value * self.scale
            inside_z = Units.Quantity(
                self.mesh_obj.PointInMesh.get('z')).Value * self.scale

            shape_face_names_list = []
            for i in self.mesh_obj.ShapeFaceNames:
                shape_face_names_list.append(i)
            snappy_settings['ShapeFaceNames'] = tuple(shape_face_names_list)
            snappy_settings[
                'EdgeRefinementLevel'] = CfdTools.relLenToRefinementLevel(
                    self.mesh_obj.EdgeRefinement)
            snappy_settings['PointInMesh'] = {
                "x": inside_x,
                "y": inside_y,
                "z": inside_z
            }
            snappy_settings[
                'CellsBetweenLevels'] = self.mesh_obj.CellsBetweenLevels

            if len(self.snappy_settings["InternalRegions"]) > 0:
                self.snappy_settings['InternalRefinementRegionsPresent'] = True
            else:
                self.snappy_settings[
                    'InternalRefinementRegionsPresent'] = False
        elif self.mesh_obj.MeshUtility == "gmsh":
            if platform.system() == "Windows":
                exe = os.path.join(FreeCAD.getHomePath(), 'bin', 'gmsh.exe')
            else:
                exe = subprocess.check_output(
                    ["which", "gmsh"], universal_newlines=True).rstrip('\n')
            self.gmsh_settings['Executable'] = CfdTools.translatePath(exe)
            self.gmsh_settings['ShapeFile'] = self.temp_file_shape
            self.gmsh_settings['HasLengthMap'] = False
            if self.ele_length_map:
                self.gmsh_settings['HasLengthMap'] = True
                self.gmsh_settings['LengthMap'] = self.ele_length_map
                self.gmsh_settings['NodeMap'] = {}
                for e in self.ele_length_map:
                    ele_nodes = (''.join(
                        (str(n + 1) + ', ')
                        for n in self.ele_node_map[e])).rstrip(', ')
                    self.gmsh_settings['NodeMap'][e] = ele_nodes
            self.gmsh_settings['ClMax'] = self.clmax
            self.gmsh_settings['ClMin'] = self.clmin
            sols = (''.join(
                (str(n + 1) + ', ')
                for n in range(len(self.mesh_obj.Part.Shape.Solids)))
                    ).rstrip(', ')
            self.gmsh_settings['Solids'] = sols
            self.gmsh_settings['BoundaryFaceMap'] = {}
            # Write one boundary per face
            for i in range(len(self.mesh_obj.Part.Shape.Faces)):
                self.gmsh_settings['BoundaryFaceMap']['face' + str(i)] = i + 1
            self.gmsh_settings['MeshFile'] = self.temp_file_mesh

        # Perform initialisation here rather than __init__ in case of path changes
        self.template_path = os.path.join(CfdTools.get_module_path(), "data",
                                          "defaultsMesh")

        mesh_region_present = False
        if self.mesh_obj.MeshUtility == "cfMesh" and len(self.cf_settings['MeshRegions']) > 0 or \
           self.mesh_obj.MeshUtility == "snappyHexMesh" and len(self.snappy_settings['MeshRegions']) > 0:
            mesh_region_present = True

        self.settings = {
            'Name': self.part_obj.Name,
            'MeshPath': self.meshCaseDir,
            'FoamRuntime': CfdTools.getFoamRuntime(),
            'MeshUtility': self.mesh_obj.MeshUtility,
            'MeshRegionPresent': mesh_region_present,
            'CfSettings': self.cf_settings,
            'SnappySettings': self.snappy_settings,
            'GmshSettings': self.gmsh_settings,
            'TwoDSettings': self.two_d_settings
        }
        if CfdTools.getFoamRuntime() != 'WindowsDocker':
            self.settings['TranslatedFoamPath'] = CfdTools.translatePath(
                CfdTools.getFoamDir())

        if self.mesh_obj.NumberOfProcesses <= 1:
            self.mesh_obj.NumberOfProcesses = 1
            self.settings['ParallelMesh'] = False
        else:
            self.settings['ParallelMesh'] = True
        self.settings['NumberOfProcesses'] = self.mesh_obj.NumberOfProcesses
        self.settings['NumberOfThreads'] = self.mesh_obj.NumberOfThreads

        TemplateBuilder.TemplateBuilder(self.meshCaseDir, self.template_path,
                                        self.settings)

        # Update Allmesh permission - will fail silently on Windows
        fname = os.path.join(self.meshCaseDir, "Allmesh")
        import stat
        s = os.stat(fname)
        os.chmod(fname, s.st_mode | stat.S_IEXEC)

        CfdTools.cfdMessage(
            "Successfully wrote meshCase to folder {}\n".format(
                self.meshCaseDir))
Пример #14
0
    def processRefinements(self):
        """ Process mesh refinements """

        mr_objs = CfdTools.getMeshRefinementObjs(self.mesh_obj)

        if self.mesh_obj.MeshUtility == "gmsh":
            # mesh regions
            self.ele_length_map = {}  # { 'ElementString' : element length }
            self.ele_node_map = {}  # { 'ElementString' : [element nodes] }
            if not mr_objs:
                print('  No mesh refinements')
            else:
                print('  Mesh refinements found - getting elements')
                if self.part_obj.Shape.ShapeType == 'Compound':
                    # see http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467 and http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&p=149520#p149520
                    err = "GMSH could return unexpected meshes for a boolean split tools Compound. It is strongly recommended to extract the shape to mesh from the Compound and use this one."
                    FreeCAD.Console.PrintError(err + "\n")
                for mr_obj in mr_objs:
                    if mr_obj.RelativeLength:
                        if mr_obj.References:
                            for sub in mr_obj.References:
                                # Check if the shape of the mesh region is an element of the Part to mesh;
                                # if not try to find the element in the shape to mesh
                                search_ele_in_shape_to_mesh = False
                                ref = FreeCAD.ActiveDocument.getObject(sub[0])
                                if not self.part_obj.Shape.isSame(ref.Shape):
                                    search_ele_in_shape_to_mesh = True
                                elems = sub[1]
                                if search_ele_in_shape_to_mesh:
                                    # Try to find the element in the Shape to mesh
                                    ele_shape = FemGeomTools.get_element(
                                        ref, elems
                                    )  # the method getElement(element) does not return Solid elements
                                    found_element = CfdTools.findElementInShape(
                                        self.part_obj.Shape, ele_shape)
                                    if found_element:
                                        elems = found_element
                                    else:
                                        FreeCAD.Console.PrintError(
                                            "One element of the meshregion " +
                                            mr_obj.Name +
                                            " could not be found in the Part to mesh. It will be ignored.\n"
                                        )
                                        elems = None
                                if elems:
                                    if elems not in self.ele_length_map:
                                        # self.ele_length_map[elems] = Units.Quantity(mr_obj.CharacteristicLength).Value
                                        mr_rellen = mr_obj.RelativeLength
                                        if mr_rellen > 1.0:
                                            mr_rellen = 1.0
                                            FreeCAD.Console.PrintError(
                                                "The meshregion: " +
                                                mr_obj.Name +
                                                " should not use a relative length greater than unity.\n"
                                            )
                                        elif mr_rellen < 0.01:
                                            mr_rellen = 0.01  # Relative length should not be less than 1/100 of base length
                                            FreeCAD.Console.PrintError(
                                                "The meshregion: " +
                                                mr_obj.Name +
                                                " should not use a relative length smaller than 0.01.\n"
                                            )
                                        self.ele_length_map[
                                            elems] = mr_rellen * self.clmax
                                    else:
                                        FreeCAD.Console.PrintError(
                                            "The element " + elems +
                                            " of the mesh refinement " +
                                            mr_obj.Name +
                                            " has been added to another mesh refinement.\n"
                                        )
                        else:
                            FreeCAD.Console.PrintError(
                                "The meshregion: " + mr_obj.Name +
                                " is not used to create the mesh because the reference list is empty.\n"
                            )
                    else:
                        FreeCAD.Console.PrintError(
                            "The meshregion: " + mr_obj.Name +
                            " is not used to create the mesh because the CharacteristicLength is 0.0 mm.\n"
                        )
                for eleml in self.ele_length_map:
                    ele_shape = FemGeomTools.get_element(
                        self.part_obj, eleml
                    )  # the method getElement(element) does not return Solid elements
                    ele_vertexes = FemGeomTools.get_vertexes_by_element(
                        self.part_obj.Shape, ele_shape)
                    self.ele_node_map[eleml] = ele_vertexes

        else:
            cf_settings = self.cf_settings
            cf_settings['MeshRegions'] = {}
            cf_settings['BoundaryLayers'] = {}
            cf_settings['InternalRegions'] = {}
            snappy_settings = self.snappy_settings
            snappy_settings['MeshRegions'] = {}
            snappy_settings['InternalRegions'] = {}

            from collections import defaultdict
            ele_meshpatch_map = defaultdict(list)
            if not mr_objs:
                print('  No mesh refinement')
            else:
                print('  Mesh refinements - getting the elements')
                if "Boolean" in self.part_obj.Name:
                    err = "Cartesian meshes should not be generated for boolean split compounds."
                    FreeCAD.Console.PrintError(err + "\n")

                # Make list of list of all references for their corresponding mesh object
                bl_matched_faces = []
                if self.mesh_obj.MeshUtility == 'cfMesh':
                    CfdTools.cfdMessage("Matching refinement regions")

                    region_face_list = []
                    for mr_id, mr_obj in enumerate(mr_objs):
                        if mr_obj.NumberLayers > 1 and not mr_obj.Internal:
                            refs = mr_obj.References
                            for r in refs:
                                obj = FreeCAD.ActiveDocument.getObject(r[0])
                                if not obj:
                                    raise RuntimeError(
                                        "Referenced object '{}' not found - object may "
                                        "have been deleted".format(r[0]))
                                try:
                                    f = obj.Shape.getElement(r[1])
                                except Part.OCCError:
                                    raise RuntimeError(
                                        "Referenced face '{}:{}' not found - face may "
                                        "have been deleted".format(r[0], r[1]))
                                region_face_list.append((f, mr_id))

                    # Make list of all faces in meshed shape with original index
                    mesh_face_list = \
                        list(zip(self.mesh_obj.Part.Shape.Faces, range(len(self.mesh_obj.Part.Shape.Faces))))

                    # Match them up
                    bl_matched_faces = CfdTools.matchFaces(
                        region_face_list, mesh_face_list)

                for mr_id, mr_obj in enumerate(mr_objs):
                    Internal = mr_obj.Internal

                    if mr_obj.RelativeLength:
                        # Store parameters per region
                        mr_rellen = mr_obj.RelativeLength
                        if mr_rellen > 1.0:
                            mr_rellen = 1.0
                            FreeCAD.Console.PrintError(
                                "The meshregion: {} should not use a relative length greater "
                                "than unity.\n".format(mr_obj.Name))
                        elif mr_rellen < 0.001:
                            mr_rellen = 0.001  # Relative length should not be less than 0.1% of base length
                            FreeCAD.Console.PrintError(
                                "The meshregion: {} should not use a relative length smaller "
                                "than 0.001.\n".format(mr_obj.Name))

                        if not (self.mesh_obj.MeshUtility == 'snappyHexMesh'
                                and mr_obj.Baffle):
                            fid = open(
                                os.path.join(self.triSurfaceDir,
                                             mr_obj.Name + '.stl'), 'w')

                        snappy_mesh_region_list = []
                        patch_list = []
                        for (si, sub) in enumerate(mr_obj.References):
                            shape = FreeCAD.ActiveDocument.getObject(
                                sub[0]).Shape
                            elem = sub[1]

                            if self.mesh_obj.MeshUtility == 'snappyHexMesh' and mr_obj.Baffle:
                                # Save baffle references or faces individually
                                baffle = "{}{}{}".format(
                                    mr_obj.Name, sub[0], elem)
                                fid = open(
                                    os.path.join(self.triSurfaceDir,
                                                 baffle + ".stl"), 'w')
                                snappy_mesh_region_list.append(baffle)

                            if elem.startswith(
                                    'Solid'
                            ):  # getElement doesn't work with solids for some reason
                                elt = shape.Solids[int(elem.lstrip('Solid')) -
                                                   1]
                            else:
                                elt = shape.getElement(elem)
                            if elt.ShapeType == 'Face' or elt.ShapeType == 'Solid':
                                CfdTools.cfdMessage(
                                    "Triangulating part: {}:{} ...".format(
                                        FreeCAD.ActiveDocument.getObject(
                                            sub[0]).Label, sub[1]))
                                facemesh = MeshPart.meshFromShape(
                                    elt,
                                    LinearDeflection=self.mesh_obj.
                                    STLLinearDeflection)

                                CfdTools.cfdMessage(" writing to file\n")
                                fid.write("solid {}{}{}\n".format(
                                    mr_obj.Name, sub[0], elem))
                                for face in facemesh.Facets:
                                    fid.write(" facet normal 0 0 0\n")
                                    fid.write("  outer loop\n")
                                    for i in range(3):
                                        p = [
                                            i * self.scale
                                            for i in face.Points[i]
                                        ]
                                        fid.write(
                                            "    vertex {} {} {}\n".format(
                                                p[0], p[1], p[2]))
                                    fid.write("  endloop\n")
                                    fid.write(" endfacet\n")
                                fid.write("endsolid {}{}{}\n".format(
                                    mr_obj.Name, sub[0], elem))

                            if self.mesh_obj.MeshUtility == 'snappyHexMesh' and mr_obj.Baffle:
                                fid.close()

                        if not (self.mesh_obj.MeshUtility == 'snappyHexMesh'
                                and mr_obj.Baffle):
                            fid.close()

                        if self.mesh_obj.MeshUtility == 'cfMesh' and mr_obj.NumberLayers > 1 and not Internal:
                            for mf in bl_matched_faces:
                                if mr_id == mf[0]:
                                    sfN = self.mesh_obj.ShapeFaceNames[mf[1]]
                                    ele_meshpatch_map[mr_obj.Name].append(sfN)
                                    patch_list.append(sfN)

                                    # Limit expansion ratio to greater than 1.0 and less than 1.2
                                    expratio = mr_obj.ExpansionRatio
                                    expratio = min(1.2, max(1.0, expratio))

                                    cf_settings['BoundaryLayers'][
                                        self.mesh_obj.
                                        ShapeFaceNames[mf[1]]] = {
                                            'NumberLayers':
                                            mr_obj.NumberLayers,
                                            'ExpansionRatio':
                                            expratio,
                                            'FirstLayerHeight':
                                            self.scale * Units.Quantity(
                                                mr_obj.FirstLayerHeight).Value
                                        }

                        if self.mesh_obj.MeshUtility == 'cfMesh':
                            if not Internal:
                                cf_settings['MeshRegions'][mr_obj.Name] = {
                                    'RelativeLength':
                                    mr_rellen * self.clmax * self.scale,
                                    'RefinementThickness':
                                    self.scale * Units.Quantity(
                                        mr_obj.RefinementThickness).Value,
                                }
                            else:
                                cf_settings['InternalRegions'][mr_obj.Name] = {
                                    'RelativeLength':
                                    mr_rellen * self.clmax * self.scale
                                }

                        elif self.mesh_obj.MeshUtility == 'snappyHexMesh':
                            refinement_level = CfdTools.relLenToRefinementLevel(
                                mr_obj.RelativeLength)
                            if not Internal:
                                if not mr_obj.Baffle:
                                    snappy_mesh_region_list.append(mr_obj.Name)
                                edge_level = CfdTools.relLenToRefinementLevel(
                                    mr_obj.RegionEdgeRefinement)
                                for rL in range(len(snappy_mesh_region_list)):
                                    mrName = mr_obj.Name + snappy_mesh_region_list[
                                        rL]
                                    snappy_settings['MeshRegions'][mrName] = {
                                        'RegionName':
                                        snappy_mesh_region_list[rL],
                                        'RefinementLevel':
                                        refinement_level,
                                        'EdgeRefinementLevel':
                                        edge_level,
                                        'MaxRefinementLevel':
                                        max(refinement_level, edge_level),
                                        'Baffle':
                                        mr_obj.Baffle
                                    }
                            else:
                                snappy_settings['InternalRegions'][
                                    mr_obj.Name] = {
                                        'RefinementLevel': refinement_level
                                    }

                    else:
                        FreeCAD.Console.PrintError(
                            "The meshregion: " + mr_obj.Name +
                            " is not used to create the mesh because the "
                            "CharacteristicLength is 0.0 mm or the reference list is empty.\n"
                        )
Пример #15
0
 def getClmax(self):
     return Units.Quantity(self.clmax, Units.Length)
Пример #16
0
    def get_boundary_layer_data(self):
        # mesh boundary layer
        # currently only one boundary layer setting object is allowed
        # but multiple boundary can be selected
        # Mesh.CharacteristicLengthMin, must be zero
        # or a value less than first inflation layer height
        if not self.mesh_obj.MeshBoundaryLayerList:
            # print("  No mesh boundary layer setting document object.")
            pass
        else:
            Console.PrintMessage("  Mesh boundary layers, we need to get the elements.\n")
            if self.part_obj.Shape.ShapeType == "Compound":
                # see http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467 and
                # http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&p=149520#p149520
                err = (
                    "Gmsh could return unexpected meshes for a boolean split tools Compound. "
                    "It is strongly recommended to extract the shape to mesh "
                    "from the Compound and use this one."
                )
                Console.PrintError(err + "\n")
            for mr_obj in self.mesh_obj.MeshBoundaryLayerList:
                if mr_obj.MinimumThickness and Units.Quantity(mr_obj.MinimumThickness).Value > 0:
                    if mr_obj.References:
                        belem_list = []
                        for sub in mr_obj.References:
                            # print(sub[0])  # Part the elements belongs to
                            # check if the shape of the mesh boundary_layer is an
                            # element of the Part to mesh
                            # if not try to find the element in the shape to mesh
                            search_ele_in_shape_to_mesh = False
                            if not self.part_obj.Shape.isSame(sub[0].Shape):
                                Console.PrintLog(
                                    "  One element of the mesh boundary layer {} is "
                                    "not an element of the Part to mesh.\n"
                                    "But we are going to try to find it in "
                                    "the Shape to mesh :-)\n"
                                    .format(mr_obj.Name)
                                )
                                search_ele_in_shape_to_mesh = True
                            for elems in sub[1]:
                                # print(elems)  # elems --> element
                                if search_ele_in_shape_to_mesh:
                                    # we try to find the element it in the Shape to mesh
                                    # and use the found element as elems
                                    # the method getElement(element) does not return Solid elements
                                    ele_shape = geomtools.get_element(sub[0], elems)
                                    found_element = geomtools.find_element_in_shape(
                                        self.part_obj.Shape,
                                        ele_shape
                                    )
                                    if found_element:  # also
                                        elems = found_element
                                    else:
                                        Console.PrintError(
                                            "One element of the mesh boundary layer {} could "
                                            "not be found in the Part to mesh. "
                                            "It will be ignored.\n"
                                            .format(mr_obj.Name)
                                        )
                                # print(elems)  # element
                                if elems not in self.bl_boundary_list:
                                    # fetch settings in DocumentObject
                                    # fan setting is not implemented
                                    belem_list.append(elems)
                                    self.bl_boundary_list.append(elems)
                                else:
                                    Console.PrintError(
                                        "The element {} of the mesh boundary "
                                        "layer {} has been added "
                                        "to another mesh boundary layer.\n"
                                        .format(elems, mr_obj.Name)
                                    )
                        setting = {}
                        setting["hwall_n"] = Units.Quantity(mr_obj.MinimumThickness).Value
                        setting["ratio"] = mr_obj.GrowthRate
                        setting["thickness"] = sum([
                            setting["hwall_n"] * setting["ratio"] ** i for i in range(
                                mr_obj.NumberOfLayers
                            )
                        ])
                        # setting["hwall_n"] * 5 # tangential cell dimension
                        setting["hwall_t"] = setting["thickness"]

                        # hfar: cell dimension outside boundary
                        # should be set later if some character length is set
                        if self.clmax > setting["thickness"] * 0.8 \
                                and self.clmax < setting["thickness"] * 1.6:
                            setting["hfar"] = self.clmax
                        else:
                            # set a value for safety, it may works as background mesh cell size
                            setting["hfar"] = setting["thickness"]
                        # from face name -> face id is done in geo file write up
                        # TODO: fan angle setup is not implemented yet
                        if self.dimension == "2":
                            setting["EdgesList"] = belem_list
                        elif self.dimension == "3":
                            setting["FacesList"] = belem_list
                        else:
                            Console.PrintError(
                                "boundary layer is only supported for 2D and 3D mesh.\n"
                            )
                        self.bl_setting_list.append(setting)
                    else:
                        Console.PrintError(
                            "The mesh boundary layer: {} is not used to create "
                            "the mesh because the reference list is empty.\n"
                            .format(mr_obj.Name)
                        )
                else:
                    Console.PrintError(
                        "The mesh boundary layer: {} is not used to create "
                        "the mesh because the min thickness is 0.0 mm.\n"
                        .format(mr_obj.Name)
                    )
            Console.PrintMessage("  {}\n".format(self.bl_setting_list))
Пример #17
0
    def __init__(self, gmsh_mesh_obj, analysis=None):

        # mesh obj
        self.mesh_obj = gmsh_mesh_obj

        # analysis
        if analysis:
            self.analysis = analysis
        else:
            self.analysis = None

        # part to mesh
        self.part_obj = self.mesh_obj.Part

        # clmax, CharacteristicLengthMax: float, 0.0 = 1e+22
        self.clmax = Units.Quantity(self.mesh_obj.CharacteristicLengthMax).Value
        if self.clmax == 0.0:
            self.clmax = 1e+22

        # clmin, CharacteristicLengthMin: float
        self.clmin = Units.Quantity(self.mesh_obj.CharacteristicLengthMin).Value

        # geotol, GeometryTolerance: float, 0.0 = 1e-08
        self.geotol = self.mesh_obj.GeometryTolerance
        if self.geotol == 0.0:
            self.geotol = 1e-08

        # order
        # known_element_orders = ["1st", "2nd"]
        self.order = self.mesh_obj.ElementOrder
        if self.order == "1st":
            self.order = "1"
        elif self.order == "2nd":
            self.order = "2"
        else:
            Console.PrintError("Error in order\n")

        # dimension
        self.dimension = self.mesh_obj.ElementDimension

        # Algorithm2D
        algo2D = self.mesh_obj.Algorithm2D
        if algo2D == "Automatic":
            self.algorithm2D = "2"
        elif algo2D == "MeshAdapt":
            self.algorithm2D = "1"
        elif algo2D == "Delaunay":
            self.algorithm2D = "5"
        elif algo2D == "Frontal":
            self.algorithm2D = "6"
        elif algo2D == "BAMG":
            self.algorithm2D = "7"
        elif algo2D == "DelQuad":
            self.algorithm2D = "8"
        else:
            self.algorithm2D = "2"

        # Algorithm3D
        algo3D = self.mesh_obj.Algorithm3D
        if algo3D == "Automatic":
            self.algorithm3D = "1"
        elif algo3D == "Delaunay":
            self.algorithm3D = "1"
        elif algo3D == "New Delaunay":
            self.algorithm3D = "2"
        elif algo3D == "Frontal":
            self.algorithm3D = "4"
        elif algo3D == "Frontal Delaunay":
            self.algorithm3D = "5"
        elif algo3D == "Frontal Hex":
            self.algorithm3D = "6"
        elif algo3D == "MMG3D":
            self.algorithm3D = "7"
        elif algo3D == "R-tree":
            self.algorithm3D = "9"
        else:
            self.algorithm3D = "1"

        # mesh groups
        if self.mesh_obj.GroupsOfNodes is True:
            self.group_nodes_export = True
        else:
            self.group_nodes_export = False
        self.group_elements = {}

        # mesh regions
        self.ele_length_map = {}  # { "ElementString" : element length }
        self.ele_node_map = {}  # { "ElementString" : [element nodes] }

        # mesh boundary layer
        self.bl_setting_list = []  # list of dict, each item map to MeshBoundaryLayer object
        self.bl_boundary_list = []  # to remove duplicated boundary edge or faces

        # other initializations
        self.temp_file_geometry = ""
        self.temp_file_mesh = ""
        self.temp_file_geo = ""
        self.mesh_name = ""
        self.gmsh_bin = ""
        self.error = False
Пример #18
0
def drill_translate(outlist, cmd, params):
    global DRILL_RETRACT_MODE
    global MOTION_MODE
    global CURRENT_X
    global CURRENT_Y
    global CURRENT_Z
    global UNITS
    global UNIT_FORMAT
    global UNIT_FEED_FORMAT

    class Drill:  # Using a class is necessary for the nested functions.
        gcode = ''

    strFormat = '.' + str(PRECISION) + 'f'

    if OUTPUT_COMMENTS:  # Comment the original command
        outlist[0] = '(' + outlist[0]
        outlist[-1] = outlist[-1] + ')'
        Drill.gcode += linenumber() + format_outlist(outlist) + '\n'

    # Cycle conversion only converts the cycles in the XY plane (G17).
    # --> ZX (G18) and YZ (G19) planes produce false gcode.
    drill_X = Units.Quantity(params['X'], FreeCAD.Units.Length)
    drill_Y = Units.Quantity(params['Y'], FreeCAD.Units.Length)
    drill_Z = Units.Quantity(params['Z'], FreeCAD.Units.Length)
    drill_R = Units.Quantity(params['R'], FreeCAD.Units.Length)
    drill_F = Units.Quantity(params['F'], FreeCAD.Units.Velocity)
    if cmd == 'G82':
        drill_DwellTime = params['P']
    elif cmd == 'G83':
        drill_Step = Units.Quantity(params['Q'], FreeCAD.Units.Length)

    # R less than Z is error
    if drill_R < drill_Z:
        Drill.gcode += linenumber() + '(drill cycle error: R less than Z )\n'
        return Drill.gcode

    # Z height to retract to when drill cycle is done:
    if DRILL_RETRACT_MODE == 'G98' and CURRENT_Z > drill_R:
        RETRACT_Z = CURRENT_Z
    else:
        RETRACT_Z = drill_R

    # Z motion nested functions:
    def rapid_Z_to(new_Z):
        Drill.gcode += linenumber() + 'G0 Z'
        Drill.gcode += format(float(new_Z.getValueAs(UNIT_FORMAT)),
                              strFormat) + '\n'

    def feed_Z_to(new_Z):
        Drill.gcode += linenumber() + 'G1 Z'
        Drill.gcode += format(float(new_Z.getValueAs(UNIT_FORMAT)),
                              strFormat) + ' F'
        Drill.gcode += format(float(drill_F.getValueAs(UNIT_FEED_FORMAT)),
                              '.2f') + '\n'

    # Make sure that Z is not below RETRACT_Z:
    if CURRENT_Z < RETRACT_Z:
        rapid_Z_to(RETRACT_Z)

    # Rapid to hole position XY:
    Drill.gcode += linenumber() + 'G0 X'
    Drill.gcode += format(float(drill_X.getValueAs(UNIT_FORMAT)),
                          strFormat) + ' Y'
    Drill.gcode += format(float(drill_Y.getValueAs(UNIT_FORMAT)),
                          strFormat) + '\n'

    # Rapid to R:
    rapid_Z_to(drill_R)

    # *************************************************************************
    # * Drill cycles:                                                         *
    # * G80 Cancel the drill cycle                                            *
    # * G81 Drill full depth in one pass                                      *
    # * G82 Drill full depth in one pass, and pause at the bottom             *
    # * G83 Drill in pecks, raising the drill to R height after each peck     *
    # * In preparation for a rapid to the next hole position:                 *
    # * G98 After the hole has been drilled, retract to the initial Z value   *
    # * G99 After the hole has been drilled, retract to R height              *
    # * Select G99 only if safe to move from hole to hole at the R height     *
    # *************************************************************************
    if cmd in ('G81', 'G82'):
        feed_Z_to(drill_Z)  # Drill hole in one step
        if cmd == 'G82':  # Dwell time delay at the bottom of the hole
            Drill.gcode += linenumber() + 'G4 S' + str(drill_DwellTime) + '\n'
            # Marlin uses P for milliseconds, S for seconds, change P to S

    elif cmd == 'G83':  # Peck drill cycle:
        chip_Space = drill_Step * 0.5
        next_Stop_Z = drill_R - drill_Step
        while next_Stop_Z >= drill_Z:
            feed_Z_to(next_Stop_Z)  # Drill one peck of depth

            # Set next depth, next_Stop_Z is still at the current hole depth
            if (next_Stop_Z - drill_Step) >= drill_Z:
                # Rapid up to clear chips:
                rapid_Z_to(drill_R)
                # Rapid down to just above last peck depth:
                rapid_Z_to(next_Stop_Z + chip_Space)
                # Update next_Stop_Z to next depth:
                next_Stop_Z -= drill_Step
            elif next_Stop_Z == drill_Z:
                break  # Done
            else:  # More to drill, but less than drill_Step
                # Rapid up to clear chips:
                rapid_Z_to(drill_R)
                # Rapid down to just above last peck depth:
                rapid_Z_to(next_Stop_Z + chip_Space)
                # Dril remainder of the hole depth:
                feed_Z_to(drill_Z)
                break  # Done
    rapid_Z_to(RETRACT_Z)  # Done, retract the drill

    return Drill.gcode
Пример #19
0
    def testFunctions(self):
        """ Test all built-in simple functions """
        doc = FreeCAD.newDocument()
        sheet = self.doc.addObject('Spreadsheet::Sheet', 'Spreadsheet')
        sheet.set('A1', '=cos(60)')  # Cos
        sheet.set('B1', '=cos(60deg)')
        sheet.set('C1', '=cos(pi / 2 * 1rad)')
        sheet.set('A2', '=sin(30)')  # Sin
        sheet.set('B2', '=sin(30deg)')
        sheet.set('C2', '=sin(pi / 6 * 1rad)')
        sheet.set('A3', '=tan(45)')  # Tan
        sheet.set('B3', '=tan(45deg)')
        sheet.set('C3', '=tan(pi / 4 * 1rad)')
        sheet.set('A4', '=abs(3)')  # Abs
        sheet.set('B4', '=abs(-3)')
        sheet.set('C4', '=abs(-3mm)')
        sheet.set('A5', '=exp(3)')  # Exp
        sheet.set('B5', '=exp(-3)')
        sheet.set('C5', '=exp(-3mm)')
        sheet.set('A6', '=log(3)')  # Log
        sheet.set('B6', '=log(-3)')
        sheet.set('C6', '=log(-3mm)')
        sheet.set('A7', '=log10(10)')  # Log10
        sheet.set('B7', '=log10(-3)')
        sheet.set('C7', '=log10(-3mm)')
        sheet.set('A8', '=round(3.4)')  # Round
        sheet.set('B8', '=round(3.6)')
        sheet.set('C8', '=round(-3.4)')
        sheet.set('D8', '=round(-3.6)')
        sheet.set('E8', '=round(3.4mm)')
        sheet.set('F8', '=round(3.6mm)')
        sheet.set('G8', '=round(-3.4mm)')
        sheet.set('H8', '=round(-3.6mm)')
        sheet.set('A9', '=trunc(3.4)')  # Trunc
        sheet.set('B9', '=trunc(3.6)')
        sheet.set('C9', '=trunc(-3.4)')
        sheet.set('D9', '=trunc(-3.6)')
        sheet.set('E9', '=trunc(3.4mm)')
        sheet.set('F9', '=trunc(3.6mm)')
        sheet.set('G9', '=trunc(-3.4mm)')
        sheet.set('H9', '=trunc(-3.6mm)')
        sheet.set('A10', '=ceil(3.4)')  # Ceil
        sheet.set('B10', '=ceil(3.6)')
        sheet.set('C10', '=ceil(-3.4)')
        sheet.set('D10', '=ceil(-3.6)')
        sheet.set('E10', '=ceil(3.4mm)')
        sheet.set('F10', '=ceil(3.6mm)')
        sheet.set('G10', '=ceil(-3.4mm)')
        sheet.set('H10', '=ceil(-3.6mm)')
        sheet.set('A11', '=floor(3.4)')  # Floor
        sheet.set('B11', '=floor(3.6)')
        sheet.set('C11', '=floor(-3.4)')
        sheet.set('D11', '=floor(-3.6)')
        sheet.set('E11', '=floor(3.4mm)')
        sheet.set('F11', '=floor(3.6mm)')
        sheet.set('G11', '=floor(-3.4mm)')
        sheet.set('H11', '=floor(-3.6mm)')
        sheet.set('A12', '=asin(0.5)')  # Asin
        sheet.set('B12', '=asin(0.5mm)')
        sheet.set('A13', '=acos(0.5)')  # Acos
        sheet.set('B13', '=acos(0.5mm)')
        sheet.set('A14', '=atan(sqrt(3))')  # Atan
        sheet.set('B14', '=atan(0.5mm)')
        sheet.set('A15', '=sinh(0.5)')  # Sinh
        sheet.set('B15', '=sinh(0.5mm)')
        sheet.set('A16', '=cosh(0.5)')  # Cosh
        sheet.set('B16', '=cosh(0.5mm)')
        sheet.set('A17', '=tanh(0.5)')  # Tanh
        sheet.set('B17', '=tanh(0.5mm)')
        sheet.set('A18', '=sqrt(4)')  # Sqrt
        sheet.set('B18', '=sqrt(4mm^2)')
        sheet.set('A19', '=mod(7; 4)')  # Mod
        sheet.set('B19', '=mod(-7; 4)')
        sheet.set('C19', '=mod(7mm; 4)')
        sheet.set('D19', '=mod(7mm; 4mm)')
        sheet.set('A20', '=atan2(3; 3)')  # Atan2
        sheet.set('B20', '=atan2(-3; 3)')
        sheet.set('C20', '=atan2(3mm; 3)')
        sheet.set('D20', '=atan2(3mm; 3mm)')
        sheet.set('A21', '=pow(7; 4)')  # Pow
        sheet.set('B21', '=pow(-7; 4)')
        sheet.set('C21', '=pow(7mm; 4)')
        sheet.set('D21', '=pow(7mm; 4mm)')
        sheet.set('A23', '=hypot(3; 4)')  # Hypot
        sheet.set('B23', '=hypot(-3; 4)')
        sheet.set('C23', '=hypot(3mm; 4)')
        sheet.set('D23', '=hypot(3mm; 4mm)')
        sheet.set('A24', '=hypot(3; 4; 5)')  # Hypot
        sheet.set('B24', '=hypot(-3; 4; 5)')
        sheet.set('C24', '=hypot(3mm; 4; 5)')
        sheet.set('D24', '=hypot(3mm; 4mm; 5mm)')
        sheet.set('A26', '=cath(5; 3)')  # Cath
        sheet.set('B26', '=cath(-5; 3)')
        sheet.set('C26', '=cath(5mm; 3)')
        sheet.set('D26', '=cath(5mm; 3mm)')

        l = math.sqrt(5 * 5 + 4 * 4 + 3 * 3)
        sheet.set('A27', '=cath(%0.15f; 5; 4)' % l)  # Cath
        sheet.set('B27', '=cath(%0.15f; -5; 4)' % l)
        sheet.set('C27', '=cath(%0.15f mm; 5mm; 4)' % l)
        sheet.set('D27', '=cath(%0.15f mm; 5mm; 4mm)' % l)

        self.doc.recompute()
        self.assertMostlyEqual(sheet.A1, 0.5)  # Cos
        self.assertMostlyEqual(sheet.B1, 0.5)
        self.assertMostlyEqual(sheet.C1, 0)
        self.assertMostlyEqual(sheet.A2, 0.5)  # Sin
        self.assertMostlyEqual(sheet.B2, 0.5)
        self.assertMostlyEqual(sheet.C2, 0.5)
        self.assertMostlyEqual(sheet.A3, 1)  # Tan
        self.assertMostlyEqual(sheet.B3, 1)
        self.assertMostlyEqual(sheet.C3, 1)
        self.assertMostlyEqual(sheet.A4, 3)  # Abs
        self.assertMostlyEqual(sheet.B4, 3)
        self.assertMostlyEqual(sheet.C4, Units.Quantity('3 mm'))
        self.assertMostlyEqual(sheet.A5, math.exp(3))  # Exp
        self.assertMostlyEqual(sheet.B5, math.exp(-3))
        self.assertEqual(sheet.C5, u'ERR: Unit must be empty.')
        self.assertMostlyEqual(sheet.A6, math.log(3))  # Log
        self.assertTrue(math.isnan(sheet.B6))
        self.assertEqual(sheet.C6, u'ERR: Unit must be empty.')
        self.assertMostlyEqual(sheet.A7, math.log10(10))  # Log10
        self.assertTrue(math.isnan(sheet.B7))
        self.assertEqual(sheet.C7, u'ERR: Unit must be empty.')
        self.assertMostlyEqual(sheet.A8, 3)  # Round
        self.assertMostlyEqual(sheet.B8, 4)
        self.assertMostlyEqual(sheet.C8, -3)
        self.assertMostlyEqual(sheet.D8, -4)
        self.assertEqual(sheet.E8, Units.Quantity('3 mm'))
        self.assertEqual(sheet.F8, Units.Quantity('4 mm'))
        self.assertEqual(sheet.G8, Units.Quantity('-3 mm'))
        self.assertEqual(sheet.H8, Units.Quantity('-4 mm'))
        self.assertMostlyEqual(sheet.A9, 3)  # Trunc
        self.assertMostlyEqual(sheet.B9, 3)
        self.assertMostlyEqual(sheet.C9, -3)
        self.assertMostlyEqual(sheet.D9, -3)
        self.assertEqual(sheet.E9, Units.Quantity('3 mm'))
        self.assertEqual(sheet.F9, Units.Quantity('3 mm'))
        self.assertEqual(sheet.G9, Units.Quantity('-3 mm'))
        self.assertEqual(sheet.H9, Units.Quantity('-3 mm'))
        self.assertMostlyEqual(sheet.A10, 4)  # Ceil
        self.assertMostlyEqual(sheet.B10, 4)
        self.assertMostlyEqual(sheet.C10, -3)
        self.assertMostlyEqual(sheet.D10, -3)
        self.assertMostlyEqual(sheet.E10, Units.Quantity('4 mm'))
        self.assertMostlyEqual(sheet.F10, Units.Quantity('4 mm'))
        self.assertMostlyEqual(sheet.G10, Units.Quantity('-3 mm'))
        self.assertMostlyEqual(sheet.H10, Units.Quantity('-3 mm'))
        self.assertMostlyEqual(sheet.A11, 3)  # Floor
        self.assertMostlyEqual(sheet.B11, 3)
        self.assertMostlyEqual(sheet.C11, -4)
        self.assertMostlyEqual(sheet.D11, -4)
        self.assertMostlyEqual(sheet.E11, Units.Quantity('3 mm'))
        self.assertMostlyEqual(sheet.F11, Units.Quantity('3 mm'))
        self.assertMostlyEqual(sheet.G11, Units.Quantity('-4 mm'))
        self.assertMostlyEqual(sheet.H11, Units.Quantity('-4 mm'))
        self.assertMostlyEqual(sheet.A12, Units.Quantity('30 deg'))  # Asin
        self.assertEqual(sheet.B12, u'ERR: Unit must be empty.')
        self.assertMostlyEqual(sheet.A13, Units.Quantity('60 deg'))  # Acos
        self.assertEqual(sheet.B13, u'ERR: Unit must be empty.')
        self.assertMostlyEqual(sheet.A14, Units.Quantity('60 deg'))  # Atan
        self.assertEqual(sheet.B14, u'ERR: Unit must be empty.')
        self.assertMostlyEqual(sheet.A15, math.sinh(0.5))  # Sinh
        self.assertEqual(sheet.B15, u'ERR: Unit must be empty.')
        self.assertMostlyEqual(sheet.A16, math.cosh(0.5))  # Cosh
        self.assertEqual(sheet.B16, u'ERR: Unit must be empty.')
        self.assertMostlyEqual(sheet.A17, math.tanh(0.5))  # Tanh
        self.assertEqual(sheet.B17, u'ERR: Unit must be empty.')
        self.assertMostlyEqual(sheet.A18, 2)  # Sqrt
        self.assertMostlyEqual(sheet.B18, Units.Quantity('2 mm'))
        self.assertMostlyEqual(sheet.A19, 3)  # Mod
        self.assertMostlyEqual(sheet.B19, -3)
        self.assertMostlyEqual(sheet.C19, Units.Quantity('3 mm'))
        self.assertEqual(sheet.D19, 3)
        self.assertMostlyEqual(sheet.A20, Units.Quantity('45 deg'))  # Atan2
        self.assertMostlyEqual(sheet.B20, Units.Quantity('-45 deg'))
        self.assertEqual(sheet.C20, u'ERR: Units must be equal')
        self.assertMostlyEqual(sheet.D20, Units.Quantity('45 deg'))
        self.assertMostlyEqual(sheet.A21, 2401)  # Pow
        self.assertMostlyEqual(sheet.B21, 2401)
        self.assertMostlyEqual(sheet.C21, Units.Quantity('2401mm^4'))
        self.assertEqual(sheet.D21,
                         u'ERR: Exponent is not allowed to have a unit.')
        self.assertMostlyEqual(sheet.A23, 5)  # Hypot
        self.assertMostlyEqual(sheet.B23, 5)
        self.assertEqual(sheet.C23, u'ERR: Units must be equal')
        self.assertMostlyEqual(sheet.D23, Units.Quantity('5mm'))

        l = math.sqrt(3 * 3 + 4 * 4 + 5 * 5)
        self.assertMostlyEqual(sheet.A24, l)  # Hypot
        self.assertMostlyEqual(sheet.B24, l)
        self.assertEqual(sheet.C24, u'ERR: Units must be equal')
        self.assertMostlyEqual(sheet.D24,
                               Units.Quantity("7.07106781186548 mm"))
        self.assertMostlyEqual(sheet.A26, 4)  # Cath
        self.assertMostlyEqual(sheet.B26, 4)
        self.assertEqual(sheet.C26, u'ERR: Units must be equal')
        self.assertMostlyEqual(sheet.D26, Units.Quantity('4mm'))

        l = math.sqrt(5 * 5 + 4 * 4 + 3 * 3)
        l = math.sqrt(l * l - 5 * 5 - 4 * 4)
        self.assertMostlyEqual(sheet.A27, l)  # Cath
        self.assertMostlyEqual(sheet.B27, l)
        self.assertEqual(sheet.C27, u'ERR: Units must be equal')
        self.assertMostlyEqual(sheet.D27, Units.Quantity("3 mm"))
        FreeCAD.closeDocument(doc.Name)
Пример #20
0
def parse(pathobj):
    global PRECISION
    global MODAL
    global OUTPUT_DOUBLES
    global UNIT_FORMAT
    global UNIT_SPEED_FORMAT
    global POWER_ON_DELAY
    global PRE_FEED
    global POST_FEED

    out = ""
    lastcommand = None
    precision_string = '.' + str(PRECISION) + 'f'
    currLocation = {}  # keep track for no doubles
    RAPID_MOVES = ["G0", "G00"]
    FEED_MOVES = ["G1", "G01", "G2", "G02", "G3", "G03"]
    # the order of parameters
    params = [
        'X', 'Y', 'Z', 'A', 'B', 'C', 'I', 'J', 'F', 'S', 'T', 'Q', 'R', 'L',
        'H', 'D', 'P'
    ]
    firstmove = Path.Command("G0", {"X": -1, "Y": -1, "Z": -1, "F": 0.0})
    currLocation.update(firstmove.Parameters)  # set First location Parameters

    if hasattr(pathobj, "Group"):  # We have a compound or project.
        for p in pathobj.Group:
            out += parse(p)
        return out
    else:  # parsing simple path

        # groups might contain non-path things like stock.
        if not hasattr(pathobj, "Path"):
            return out

        for c in pathobj.Path.Commands:

            outstring = []
            command = c.Name

            controlstring = ""
            if command in FEED_MOVES and lastcommand in RAPID_MOVES:
                controlstring = PRE_FEED.format(POWER_ON_DELAY)
            elif command in RAPID_MOVES and lastcommand in FEED_MOVES:
                controlstring = POST_FEED
            if len(controlstring) > 0:
                out += controlstring

            outstring.append(command)

            # if modal: suppress the command if it is the same as the last one
            if MODAL is True:
                if command == lastcommand:
                    outstring.pop(0)

            if c.Name[0] == '(' and not OUTPUT_COMMENTS:  # command is a comment
                continue

            # Now add the remaining parameters in order
            for param in params:
                if param in c.Parameters:
                    if param == 'F' and (
                            currLocation[param] != c.Parameters[param]
                            or OUTPUT_DOUBLES):
                        if c.Name not in RAPID_MOVES:  # linuxcnc doesn't use rapid speeds
                            speed = Units.Quantity(c.Parameters['F'],
                                                   FreeCAD.Units.Velocity)
                            if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0:
                                outstring.append(param + format(
                                    float(speed.getValueAs(UNIT_SPEED_FORMAT)),
                                    precision_string))
                        else:
                            continue
                    elif param == 'T':
                        outstring.append(param + str(int(c.Parameters['T'])))
                    elif param == 'H':
                        outstring.append(param + str(int(c.Parameters['H'])))
                    elif param == 'D':
                        outstring.append(param + str(int(c.Parameters['D'])))
                    elif param == 'S':
                        outstring.append(param + str(int(c.Parameters['S'])))
                    else:
                        if (not OUTPUT_DOUBLES) and (
                                param
                                in currLocation) and (currLocation[param]
                                                      == c.Parameters[param]):
                            continue
                        else:
                            pos = Units.Quantity(c.Parameters[param],
                                                 FreeCAD.Units.Length)
                            outstring.append(
                                param +
                                format(float(pos.getValueAs(UNIT_FORMAT)),
                                       precision_string))

            # store the latest command
            lastcommand = command
            currLocation.update(c.Parameters)

            # Check for Tool Change:
            if command == 'M6':
                continue
                # if OUTPUT_COMMENTS:
                #     out += linenumber() + "(begin toolchange)\n"
                for line in TOOL_CHANGE.splitlines(True):
                    out += linenumber() + line

            if command == "message":
                if OUTPUT_COMMENTS is False:
                    out = []
                else:
                    outstring.pop(0)  # remove the command

            # prepend a line number and append a newline
            if len(outstring) >= 1:
                if OUTPUT_LINE_NUMBERS:
                    outstring.insert(0, (linenumber()))

                # append the line to the final output
                for w in outstring:
                    out += w + COMMAND_SPACE
                out = out.strip() + "\n"

        return out
Пример #21
0
 def testUnits(self):
     """ Units -- test unit calculations. """
     sheet = self.doc.addObject('Spreadsheet::Sheet', 'Spreadsheet')
     sheet.set('A1', '=2mm + 3mm')
     sheet.set('A2', '=2mm - 3mm')
     sheet.set('A3', '=2mm * 3mm')
     sheet.set('A4', '=4mm / 2mm')
     sheet.set('A5', '=(4mm)^2')
     sheet.set('A6', '=5(mm^2)')
     sheet.set('A7', '=5mm^2')  #  ^2 operates on whole number
     sheet.set('A8', '=5')
     sheet.set('A9', '=5*1/K')  # Currently fails
     sheet.set('A10', '=5 K^-1')  # Currently fails
     sheet.set('A11', '=9.8 m/s^2')  # Currently fails
     sheet.setDisplayUnit('A8', '1/K')
     self.doc.recompute()
     self.assertEqual(sheet.A1, Units.Quantity('5mm'))
     self.assertEqual(sheet.A2, Units.Quantity('-1 mm'))
     self.assertEqual(sheet.A3, Units.Quantity('6 mm^2'))
     self.assertEqual(sheet.A4, Units.Quantity('2'))
     self.assertEqual(sheet.A5, Units.Quantity('16 mm^2'))
     self.assertEqual(sheet.A6, Units.Quantity('5 mm^2'))
     self.assertEqual(sheet.A7, Units.Quantity('5 mm^2'))
     self.assertEqual(sheet.A8, Units.Quantity('5'))
     self.assertEqual(sheet.A9, Units.Quantity('5 K^-1'))
     self.assertEqual(sheet.A10, Units.Quantity('5 K^-1'))
     self.assertEqual(sheet.A11, Units.Quantity('9.8 m/s^2'))
Пример #22
0
def drill_translate(outstring, cmd, params):
  global DRILL_RETRACT_MODE
  global MOTION_MODE
  global CURRENT_X
  global CURRENT_Y
  global CURRENT_Z
  global UNITS
  global UNIT_FORMAT
  global UNIT_SPEED_FORMAT

  strFormat = '.' + str(PRECISION) + 'f'

  trBuff = ""

  if OUTPUT_COMMENTS:  # Comment the original command
    outstring[0] = "(" + outstring[0]
    outstring[-1] = outstring[-1] + ")"
    trBuff += linenumber() + format_outstring(outstring) + "\n"

  # cycle conversion
  # currently only cycles in XY are provided (G17)
  # other plains ZX (G18) and  YZ (G19) are not dealt with : Z drilling only.
  drill_X = Units.Quantity(params['X'], FreeCAD.Units.Length)
  drill_Y = Units.Quantity(params['Y'], FreeCAD.Units.Length)
  drill_Z = Units.Quantity(params['Z'], FreeCAD.Units.Length)
  RETRACT_Z = Units.Quantity(params['R'], FreeCAD.Units.Length)
  # R less than Z is error
  if RETRACT_Z < drill_Z :
    trBuff += linenumber() + "(drill cycle error: R less than Z )\n"
    return trBuff

  if MOTION_MODE == 'G91':   # G91 relative movements
    drill_X += CURRENT_X
    drill_Y += CURRENT_Y
    drill_Z += CURRENT_Z
    RETRACT_Z += CURRENT_Z

  if DRILL_RETRACT_MODE == 'G98' and CURRENT_Z >= RETRACT_Z:
    RETRACT_Z = CURRENT_Z

  # get the other parameters
  drill_feedrate = Units.Quantity(params['F'], FreeCAD.Units.Velocity)
  if cmd == 'G83':
    drill_Step = Units.Quantity(params['Q'], FreeCAD.Units.Length)
    a_bit = drill_Step  * 0.05    # NIST 3.5.16.4 G83 Cycle:  "current hole bottom, backed off a bit."
  elif cmd == 'G82':
    drill_DwellTime = params['P']

  # wrap this block to ensure machine MOTION_MODE is restored in case of error
  try:
    if MOTION_MODE == 'G91':
      trBuff += linenumber() + "G90\n"  # force absolute coordinates during cycles

    strG0_RETRACT_Z = 'G0 Z' + format(float(RETRACT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
    strF_Feedrate = ' F' + format(float(drill_feedrate.getValueAs(UNIT_SPEED_FORMAT)), '.2f') + "\n"
    print (strF_Feedrate)

    # preliminary mouvement(s)
    if CURRENT_Z < RETRACT_Z:
      trBuff += linenumber() + strG0_RETRACT_Z
    trBuff += linenumber() + 'G0 X' + format(float(drill_X.getValueAs(UNIT_FORMAT)), strFormat) + ' Y' + format(float(drill_Y.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
    if CURRENT_Z > RETRACT_Z:
      # NIST GCODE 3.5.16.1 Preliminary and In-Between Motion says G0 to RETRACT_Z. Here use G1 since retract height may be below surface !
      trBuff += linenumber() + 'G1 Z' + format(float(RETRACT_Z.getValueAs(UNIT_FORMAT)), strFormat) + strF_Feedrate
    last_Stop_Z = RETRACT_Z

    # drill moves
    if cmd in ('G81', 'G82'):
      trBuff += linenumber() + 'G1 Z' + format(float(drill_Z.getValueAs(UNIT_FORMAT)), strFormat) + strF_Feedrate
      # pause where applicable
      if cmd == 'G82':
        trBuff += linenumber() + 'G4 P' + str(drill_DwellTime) + "\n"
      trBuff += linenumber() + strG0_RETRACT_Z
    else:  # 'G83'
      if params['Q'] != 0 :
        while 1:
          if last_Stop_Z != RETRACT_Z :
            clearance_depth = last_Stop_Z + a_bit  # rapid move to just short of last drilling depth
            trBuff += linenumber() + 'G0 Z' + format(float(clearance_depth.getValueAs(UNIT_FORMAT)) , strFormat) + "\n"
          next_Stop_Z = last_Stop_Z - drill_Step
          if next_Stop_Z > drill_Z:
            trBuff += linenumber() + 'G1 Z' + format(float(next_Stop_Z.getValueAs(UNIT_FORMAT)), strFormat) + strF_Feedrate
            trBuff += linenumber() + strG0_RETRACT_Z
            last_Stop_Z = next_Stop_Z
          else:
            trBuff += linenumber() + 'G1 Z' + format(float(drill_Z.getValueAs(UNIT_FORMAT)), strFormat) + strF_Feedrate
            trBuff += linenumber() + strG0_RETRACT_Z
            break

  except Exception as e:
    pass

  if MOTION_MODE == 'G91':
    trBuff += linenumber() + 'G91'  # Restore if changed

  return trBuff
Пример #23
0
def parse(pathobj):
    out = ""
    lastcommand = None
    global SPINDLE_SPEED

    # params = ['X','Y','Z','A','B','I','J','K','F','S'] #This list control
    # the order of parameters
    # linuxcnc doesn't want K properties on XY plane  Arcs need work.
    params = ['X', 'Y', 'Z', 'A', 'B', 'I', 'J', 'F', 'S', 'T', 'Q', 'R', 'L']

    if hasattr(pathobj, "Group"):  # We have a compound or project.
        # if OUTPUT_COMMENTS:
        #     out += linenumber() + "(compound: " + pathobj.Label + ")\n"
        for p in pathobj.Group:
            out += parse(p)
        return out
    else:  # parsing simple path

        # groups might contain non-path things like stock.
        if not hasattr(pathobj, "Path"):
            return out

        # if OUTPUT_COMMENTS:
        #     out += linenumber() + "(" + pathobj.Label + ")\n"

        for c in pathobj.Path.Commands:
            outstring = []
            command = c.Name
            outstring.append(command)
            # if modal: only print the command if it is not the same as the
            # last one
            if MODAL is True:
                if command == lastcommand:
                    outstring.pop(0)

            # Now add the remaining parameters in order
            for param in params:
                if param in c.Parameters:
                    if param == 'F':
                        if c.Name not in ["G0", "G00"]: #linuxcnc doesn't use rapid speeds
                            speed = Units.Quantity(c.Parameters['F'], FreeCAD.Units.Velocity)
                            outstring.append(
                                param + format(float(speed.getValueAs(UNIT_FORMAT)), '.2f') )
                    elif param == 'T':
                        outstring.append(param + str(c.Parameters['T']))
                    elif param == 'S':
                        outstring.append(param + str(c.Parameters['S']))
                        SPINDLE_SPEED = c.Parameters['S']
                    else:
                        outstring.append(
                            param + format(c.Parameters[param], '.4f'))
            if command in ['G1', 'G01', 'G2', 'G02', 'G3', 'G03']:
                outstring.append('S' + str(SPINDLE_SPEED))

            # store the latest command
            lastcommand = command

            # Check for Tool Change:
            if command == 'M6':
                # if OUTPUT_COMMENTS:
                #     out += linenumber() + "(begin toolchange)\n"
                for line in TOOL_CHANGE.splitlines(True):
                    out += linenumber() + line

            if command == "message":
                if OUTPUT_COMMENTS is False:
                    out = []
                else:
                    outstring.pop(0)  # remove the command

            # prepend a line number and append a newline
            if len(outstring) >= 1:
                if OUTPUT_LINE_NUMBERS:
                    outstring.insert(0, (linenumber()))

                # append the line to the final output
                for w in outstring:
                    out += w + COMMAND_SPACE 
                out = out.strip() + "\n"

        return out
Пример #24
0
    def __init__(self, gmsh_mesh_obj, analysis=None):
        self.mesh_obj = gmsh_mesh_obj
        if analysis:
            self.analysis = analysis
        else:
            self.analysis = None

        # part to mesh
        self.part_obj = self.mesh_obj.Part

        # clmax, CharacteristicLengthMax: float, 0.0 = 1e+22
        self.clmax = Units.Quantity(
            self.mesh_obj.CharacteristicLengthMax).Value
        if self.clmax == 0.0:
            self.clmax = 1e+22

        # clmin, CharacteristicLengthMin: float
        self.clmin = Units.Quantity(
            self.mesh_obj.CharacteristicLengthMin).Value

        # geotol, GeometryTolerance: float, 0.0 = 1e-08
        self.geotol = self.mesh_obj.GeometryTolerance
        if self.geotol == 0.0:
            self.geotol = 1e-08

        # order
        # known_element_orders = ['1st', '2nd']
        self.order = self.mesh_obj.ElementOrder
        if self.order == '1st':
            self.order = '1'
        elif self.order == '2nd':
            self.order = '2'
        else:
            print('Error in order')

        # dimension
        self.dimension = self.mesh_obj.ElementDimension

        # Algorithm2D
        algo2D = self.mesh_obj.Algorithm2D
        if algo2D == 'Automatic':
            self.algorithm2D = '2'
        elif algo2D == 'MeshAdapt':
            self.algorithm2D = '1'
        elif algo2D == 'Delaunay':
            self.algorithm2D = '5'
        elif algo2D == 'Frontal':
            self.algorithm2D = '6'
        elif algo2D == 'BAMG':
            self.algorithm2D = '7'
        elif algo2D == 'DelQuad':
            self.algorithm2D = '8'
        else:
            self.algorithm2D = '2'

        # Algorithm3D
        algo3D = self.mesh_obj.Algorithm3D
        if algo3D == 'Automatic':
            self.algorithm3D = '1'
        elif algo3D == 'Delaunay':
            self.algorithm3D = '1'
        elif algo3D == 'New Delaunay':
            self.algorithm3D = '2'
        elif algo3D == 'Frontal':
            self.algorithm3D = '4'
        elif algo3D == 'Frontal Delaunay':
            self.algorithm3D = '5'
        elif algo3D == 'Frontal Hex':
            self.algorithm3D = '6'
        elif algo3D == 'MMG3D':
            self.algorithm3D = '7'
        elif algo3D == 'R-tree':
            self.algorithm3D = '9'
        else:
            self.algorithm3D = '1'

        # mesh groups
        if self.mesh_obj.GroupsOfNodes is True:
            self.group_nodes_export = True
        else:
            self.group_nodes_export = False
        self.group_elements = {}

        # mesh regions
        self.ele_length_map = {}  # { 'ElementString' : element length }
        self.ele_node_map = {}  # { 'ElementString' : [element nodes] }

        # mesh boundary layer
        self.bl_setting_list = [
        ]  # list of dict, each item map to MeshBoundaryLayer object
        self.bl_boundary_list = [
        ]  # to remove duplicated boundary edge or faces

        # other initializations
        self.temp_file_geometry = ''
        self.temp_file_mesh = ''
        self.temp_file_geo = ''
        self.mesh_name = ''
        self.gmsh_bin = ''
        self.error = False
Пример #25
0
def convert(quantityStr, unit):
    quantity = Units.Quantity(quantityStr)
    for key, setting in UNITS.items():
        unit = unit.replace(key, setting)
    return float(quantity.getValueAs(unit))
Пример #26
0
def parse(pathobj):

    global DRILL_RETRACT_MODE
    global MOTION_MODE
    global CURRENT_X
    global CURRENT_Y
    global CURRENT_Z

    out = ""
    lastcommand = None
    precision_string = '.' + str(PRECISION) + 'f'

    params = [
        'X', 'Y', 'Z', 'A', 'B', 'C', 'U', 'V', 'W', 'I', 'J', 'K', 'F', 'S',
        'T', 'Q', 'R', 'L', 'P'
    ]

    if hasattr(pathobj, "Group"):  # We have a compound or project.
        if OUTPUT_COMMENTS:
            out += linenumber() + "(compound: " + pathobj.Label + ")\n"
        for p in pathobj.Group:
            out += parse(p)
        return out

    else:  # parsing simple path
        if not hasattr(
                pathobj,
                "Path"):  # groups might contain non-path things like stock.
            return out

        if OUTPUT_COMMENTS:
            out += linenumber() + "(Path: " + pathobj.Label + ")\n"

        for c in pathobj.Path.Commands:
            outstring = []
            command = c.Name

            outstring.append(command)

            # if modal: only print the command if it is not the same as the last one
            if MODAL:
                if command == lastcommand:
                    outstring.pop(0)

            # Now add the remaining parameters in order
            for param in params:
                if param in c.Parameters:
                    if param == 'F':
                        if command not in RAPID_MOVES:
                            speed = Units.Quantity(c.Parameters['F'],
                                                   FreeCAD.Units.Velocity)
                            if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0:
                                outstring.append(param + format(
                                    float(speed.getValueAs(UNIT_SPEED_FORMAT)),
                                    precision_string))
                    elif param in ['T', 'H', 'D', 'S', 'P', 'L']:
                        outstring.append(param + str(c.Parameters[param]))
                    elif param in ['A', 'B', 'C']:
                        outstring.append(
                            param +
                            format(c.Parameters[param], precision_string))
                    else:  # [X, Y, Z, U, V, W, I, J, K, R, Q] (Conversion eventuelle mm/inches)
                        pos = Units.Quantity(c.Parameters[param],
                                             FreeCAD.Units.Length)
                        outstring.append(
                            param + format(float(pos.getValueAs(UNIT_FORMAT)),
                                           precision_string))

            # store the latest command
            lastcommand = command

            # Memorise la position courante pour calcul des mouvements relatis et du plan de retrait
            if command in MOTION_COMMANDS:
                if 'X' in c.Parameters:
                    CURRENT_X = Units.Quantity(c.Parameters['X'],
                                               FreeCAD.Units.Length)
                if 'Y' in c.Parameters:
                    CURRENT_Y = Units.Quantity(c.Parameters['Y'],
                                               FreeCAD.Units.Length)
                if 'Z' in c.Parameters:
                    CURRENT_Z = Units.Quantity(c.Parameters['Z'],
                                               FreeCAD.Units.Length)

            if command in ('G98', 'G99'):
                DRILL_RETRACT_MODE = command

            if command in ('G90', 'G91'):
                MOTION_MODE = command

            if TRANSLATE_DRILL_CYCLES:
                if command in ('G81', 'G82', 'G83'):
                    out += drill_translate(outstring, command, c.Parameters)
                    # Efface la ligne que l'on vient de translater
                    del (outstring[:])
                    outstring = []

            # Check for Tool Change:
            if command in ('M6', 'M06'):
                if OUTPUT_COMMENTS:
                    out += linenumber() + "(begin toolchange)\n"
                if not OUTPUT_TOOL_CHANGE:
                    outstring[0] = "(" + outstring[0]
                    outstring[-1] = outstring[-1] + ")"
                else:
                    for line in TOOL_CHANGE.splitlines(True):
                        out += linenumber() + line

            if command == "message":
                if OUTPUT_COMMENTS is False:
                    out = []
                else:
                    outstring.pop(0)  # remove the command

            if command in SUPPRESS_COMMANDS:
                outstring[0] = "(" + outstring[0]
                outstring[-1] = outstring[-1] + ")"

            # prepend a line number and append a newline
            if len(outstring) >= 1:
                out += linenumber() + format_outstring(outstring) + "\n"

    return out
Пример #27
0
def parse(pathobj):
    out = ""
    lastcommand = None
    precision_string = "." + str(PRECISION) + "f"
    currLocation = {}  # keep track for no doubles

    # The params list control the order of parameters
    params = [
        "X",
        "Y",
        "Z",
        "A",
        "B",
        "C",
        "I",
        "J",
        "K",
        "R",
        "F",
        "S",
        "T",
        "H",
        "L",
        "Q",
    ]
    firstmove = Path.Command("G0", {"X": -1, "Y": -1, "Z": -1, "F": 0.0})
    currLocation.update(firstmove.Parameters)  # set First location Parameters

    if hasattr(pathobj, "Group"):
        # We have a compound or project.

        # if OUTPUT_COMMENTS:
        #    out += linenumber() + "(compound: " + pathobj.Label + ")\n"
        for p in pathobj.Group:
            out += parse(p)
        return out
    else:
        # parsing simple path

        # groups might contain non-path things like stock.
        if not hasattr(pathobj, "Path"):
            return out

        # if OUTPUT_COMMENTS:
        #    out += linenumber() + "(" + pathobj.Label + ")\n"

        for c in pathobj.Path.Commands:
            commandlist = [
            ]  # list of elements in the command, code and params.
            command = c.Name.strip()  # command M or G code or comment string
            commandlist.append(command)

            # if modal: only print the command if it is not the same as the last one
            if MODAL is True:
                if command == lastcommand:
                    commandlist.pop(0)

            if c.Name[0] == "(" and not OUTPUT_COMMENTS:  # command is a comment
                continue

            # Now add the remaining parameters in order
            for param in params:
                if param in c.Parameters:
                    if param == "F" and (
                            currLocation[param] != c.Parameters[param]
                            or REPEAT_ARGUMENTS):
                        if c.Name not in ["G0", "G00"]:  # No F in G0
                            speed = Units.Quantity(c.Parameters["F"],
                                                   FreeCAD.Units.Velocity)
                            if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0:
                                commandlist.append(param + format(
                                    float(speed.getValueAs(UNIT_SPEED_FORMAT)),
                                    precision_string,
                                ))
                        else:
                            continue
                    elif param == "T":
                        commandlist.append(param + str(int(c.Parameters["T"])))
                    elif param == "H":
                        commandlist.append(param + str(int(c.Parameters["H"])))
                    elif param == "D":
                        commandlist.append(param + str(int(c.Parameters["D"])))
                    elif param == "S":
                        commandlist.append(param + str(int(c.Parameters["S"])))
                    else:
                        if ((not REPEAT_ARGUMENTS) and (param in currLocation)
                                and
                            (currLocation[param] == c.Parameters[param])):
                            continue
                        else:
                            pos = Units.Quantity(c.Parameters[param],
                                                 FreeCAD.Units.Length)
                            commandlist.append(
                                param +
                                format(float(pos.getValueAs(UNIT_FORMAT)),
                                       precision_string))

            # store the latest command
            lastcommand = command
            currLocation.update(c.Parameters)

            # Check for Tool Change:
            if command == "M6":
                for line in TOOL_CHANGE.splitlines(True):
                    out += linenumber() + line

                # add height offset
                if USE_TLO:
                    tool_height = "\nG43 H" + str(int(c.Parameters["T"]))
                    commandlist.append(tool_height)

            if command == "message":
                if OUTPUT_COMMENTS is False:
                    out = []
                else:
                    commandlist.pop(0)  # remove the command

            # prepend a line number and append a newline
            if len(commandlist) >= 1:
                if OUTPUT_LINE_NUMBERS:
                    commandlist.insert(0, (linenumber()))

                # append the line to the final output
                for w in commandlist:
                    out += w.strip() + COMMAND_SPACE
                if trace_gcode:
                    print("parse : >>{}".format(out))
                out = out.strip() + "\n"

        return out
Пример #28
0
def drill_translate(outstring, cmd, params):
    global DRILL_RETRACT_MODE
    global MOTION_MODE
    global CURRENT_X
    global CURRENT_Y
    global CURRENT_Z
    global UNITS
    global UNIT_FORMAT
    global UNIT_SPEED_FORMAT

    strFormat = '.' + str(PRECISION) + 'f'

    trBuff = ""

    if OUTPUT_COMMENTS:  # Comment the original command
        outstring[0] = "(" + outstring[0]
        outstring[-1] = outstring[-1] + ")"
        trBuff += linenumber() + format_outstring(outstring) + "\n"

    # Conversion du cycle
    # Pour l'instant, on gere uniquement les cycles dans le plan XY (G17)
    # les autres plans ZX (G18) et YZ (G19) ne sont pas traites : Calculs sur Z uniquement.
    if MOTION_MODE == 'G90':  # Deplacements en coordonnees absolues
        drill_X = Units.Quantity(params['X'], FreeCAD.Units.Length)
        drill_Y = Units.Quantity(params['Y'], FreeCAD.Units.Length)
        drill_Z = Units.Quantity(params['Z'], FreeCAD.Units.Length)
        RETRACT_Z = Units.Quantity(params['R'], FreeCAD.Units.Length)
    else:  # G91 Deplacements relatifs
        drill_X = CURRENT_X + Units.Quantity(params['X'], FreeCAD.Units.Length)
        drill_Y = CURRENT_Y + Units.Quantity(params['Y'], FreeCAD.Units.Length)
        drill_Z = CURRENT_Z + Units.Quantity(params['Z'], FreeCAD.Units.Length)
        RETRACT_Z = CURRENT_Z + Units.Quantity(params['R'],
                                               FreeCAD.Units.Length)

    if DRILL_RETRACT_MODE == 'G98' and CURRENT_Z >= RETRACT_Z:
        RETRACT_Z = CURRENT_Z

    # Recupere les valeurs des autres parametres
    drill_Speed = Units.Quantity(params['F'], FreeCAD.Units.Velocity)
    if cmd == 'G83':
        drill_Step = Units.Quantity(params['Q'], FreeCAD.Units.Length)
    elif cmd == 'G82':
        drill_DwellTime = params['P']

    if MOTION_MODE == 'G91':
        trBuff += linenumber(
        ) + "G90" + "\n"  # Force des deplacements en coordonnees absolues pendant les cycles

    # Mouvement(s) preliminaire(s))
    if CURRENT_Z < RETRACT_Z:
        trBuff += linenumber() + 'G0 Z' + format(
            float(RETRACT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
    trBuff += linenumber() + 'G0 X' + format(
        float(drill_X.getValueAs(UNIT_FORMAT)), strFormat) + ' Y' + format(
            float(drill_Y.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
    if CURRENT_Z > RETRACT_Z:
        trBuff += linenumber() + 'G0 Z' + format(
            float(CURRENT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"

    # Mouvement de percage
    if cmd in ('G81', 'G82'):
        trBuff += linenumber() + 'G1 Z' + format(
            float(drill_Z.getValueAs(UNIT_FORMAT)), strFormat) + ' F' + format(
                float(drill_Speed.getValueAs(UNIT_SPEED_FORMAT)), '.2f') + "\n"
        # Temporisation eventuelle
        if cmd == 'G82':
            trBuff += linenumber() + 'G4 P' + str(drill_DwellTime) + "\n"
        # Sortie de percage
        trBuff += linenumber() + 'G0 Z' + format(
            float(RETRACT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
    else:  # 'G83'
        next_Stop_Z = RETRACT_Z - drill_Step
        while 1:
            if next_Stop_Z > drill_Z:
                trBuff += linenumber() + 'G1 Z' + format(
                    float(next_Stop_Z.getValueAs(UNIT_FORMAT)),
                    strFormat) + ' F' + format(
                        float(drill_Speed.getValueAs(UNIT_SPEED_FORMAT)),
                        '.2f') + "\n"
                trBuff += linenumber() + 'G0 Z' + format(
                    float(RETRACT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
                next_Stop_Z -= drill_Step
            else:
                trBuff += linenumber() + 'G1 Z' + format(
                    float(drill_Z.getValueAs(UNIT_FORMAT)),
                    strFormat) + ' F' + format(
                        float(drill_Speed.getValueAs(UNIT_SPEED_FORMAT)),
                        '.2f') + "\n"
                trBuff += linenumber() + 'G0 Z' + format(
                    float(RETRACT_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n"
                break

    if MOTION_MODE == 'G91':
        trBuff += linenumber(
        ) + 'G91'  # Restore le mode de deplacement relatif

    return trBuff
Пример #29
0
def compute(lc, fs_ref=True, doc=App.ActiveDocument):
    objs = {'fs':None,
            'ship':None,
            'tanks':[],
            'COG': None,
            'B': None}
    points, ship, weights, tanks = GZ.gz(
        lc, [Units.parseQuantity("0 deg")], True)
    if points == []:
        return None, 0, 0, 0, objs
    gz, draft, trim = points[0]
    group_objs = []
    # Create a free surface
    L = ship.Length
    B = ship.Breadth
    name = __make_name('SinkAndTrim_FS', doc)
    shape = Part.makePlane(2.0 * L, 2.0 * B, App.Vector(-L, -B, 0))
    if not fs_ref:
        shape = __place_shape(shape, -draft, -trim)
    Part.show(shape, name)
    doc.recompute()
    if Gui:
        fs = Gui.getDocument(doc.Name).getObject(name)
        fs.LineColor = (0.0, 0.0, 0.5)
        fs.ShapeColor = (0.0, 0.7, 1.0)
    group_objs.append(doc.getObject(name))
    objs['fs'] = group_objs[-1]

    # Copy and place the ship
    name = __make_name('SinkAndTrim_{}'.format(ship.Name), doc)
    shape = ship.Shape.copy()
    if fs_ref:
        shape = __place_shape(ship.Shape.copy(), draft, trim)
    Part.show(shape, name)
    doc.recompute()
    if Gui:
        plot_ship = Gui.getDocument(doc.Name).getObject(name)
        plot_ship.Transparency = 50
    group_objs.append(doc.getObject(name))
    doc.getObject(name).Label = 'SinkAndTrim_' + ship.Label
    objs['ship'] = group_objs[-1]
    # Copy and place the tanks
    tank_shapes = []  # Untransformed
    for tank, dens, level in tanks:
        name = __make_name('SinkAndTrim_{}'.format(tank.Name), doc)
        vol = tank.Proxy.getVolume(tank, level)
        shape = tank.Proxy.getFluidShape(tank, vol, trim=trim)
        tank_shapes.append(shape)
        if shape is None:
            continue
        if fs_ref:
            shape = __place_shape(shape.copy(), draft, trim)
        Part.show(shape, name)
        doc.recompute()
        group_objs.append(doc.getObject(name))
        doc.getObject(name).Label = 'SinkAndTrim_' + tank.Label
        objs['tanks'].append(group_objs[-1])
    # Place the bouyancy center
    disp, B, _ = Hydrostatics.displacement(ship, draft, trim=trim)
    disp *= GZ.G
    name = __make_name('SinkAndTrim_B', doc)
    shape = Part.Vertex(B)
    if fs_ref:
        shape = __place_shape(shape, draft, trim)
    Part.show(shape, name)
    doc.recompute()
    if Gui:
        b = Gui.getDocument(doc.Name).getObject(name)
        b.PointSize = 10.00
    group_objs.append(doc.getObject(name))
    objs['B'] = group_objs[-1]
    # Place the COG
    COG, W = GZ.weights_cog(weights)
    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, tank_data in enumerate(tanks):
        dens = tank_data[1]
        shape = tank_shapes[i]
        if shape is None:
            continue
        tank_cog, tank_vol = __vol_cog(shape)
        tank_weight = Units.Quantity(tank_vol, Units.Volume) * dens * GZ.G
        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
        W += tank_weight
    COG = Vector(mom_x / W, mom_y / W, mom_z / W)
    name = __make_name('SinkAndTrim_COG', doc)
    shape = Part.Vertex(COG)
    if fs_ref:
        shape = __place_shape(shape, draft, trim)
    Part.show(shape, name)
    doc.recompute()
    if Gui:
        cog = Gui.getDocument(doc.Name).getObject(name)
        cog.PointSize = 10.00
    group_objs.append(doc.getObject(name))
    objs['COG'] = group_objs[-1]

    # Create a group where the results will be placed
    name = __make_name('SinkAndTrim_results', doc)
    group = doc.addObject('App::DocumentObjectGroup', name)
    for obj in group_objs:
        group.addObject(obj)
    doc.recompute()

    return group, draft, trim, disp / GZ.G, objs
Пример #30
0
 def get_region_data(self):
     # mesh regions
     if not self.mesh_obj.MeshRegionList:
         # print("  No mesh regions.")
         pass
     else:
         Console.PrintMessage('  Mesh regions, we need to get the elements.\n')
         # by the use of MeshRegion object and a BooleanSplitCompound
         # there could be problems with node numbers see
         # http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&start=40#p149467
         # http://forum.freecadweb.org/viewtopic.php?f=18&t=18780&p=149520#p149520
         part = self.part_obj
         if (
             self.mesh_obj.MeshRegionList and part.Shape.ShapeType == "Compound"
             and (
                 femutils.is_of_type(part, "FeatureBooleanFragments")
                 or femutils.is_of_type(part, "FeatureSlice")
                 or femutils.is_of_type(part, "FeatureXOR")
             )
         ):
             error_message = (
                 "  The mesh to shape is a boolean split tools Compound "
                 "and the mesh has mesh region list. "
                 "Gmsh could return unexpected meshes in such circumstances. "
                 "It is strongly recommended to extract the shape to mesh "
                 "from the Compound and use this one."
             )
             Console.PrintError(error_message + "\n")
             # TODO: no gui popup because FreeCAD will be in a endless output loop
             #       as long as the pop up is on --> maybe find a better solution for
             #       either of both --> thus the pop up is in task panel
         for mr_obj in self.mesh_obj.MeshRegionList:
             # print(mr_obj.Name)
             # print(mr_obj.CharacteristicLength)
             # print(Units.Quantity(mr_obj.CharacteristicLength).Value)
             if mr_obj.CharacteristicLength:
                 if mr_obj.References:
                     for sub in mr_obj.References:
                         # print(sub[0])  # Part the elements belongs to
                         # check if the shape of the mesh region
                         # is an element of the Part to mesh
                         # if not try to find the element in the shape to mesh
                         search_ele_in_shape_to_mesh = False
                         if not self.part_obj.Shape.isSame(sub[0].Shape):
                             Console.PrintLog(
                                 "  One element of the meshregion {} is "
                                 "not an element of the Part to mesh.\n"
                                 "But we are going to try to find it in "
                                 "the Shape to mesh :-)\n"
                                 .format(mr_obj.Name)
                             )
                             search_ele_in_shape_to_mesh = True
                         for elems in sub[1]:
                             # print(elems)  # elems --> element
                             if search_ele_in_shape_to_mesh:
                                 # we're going to try to find the element in the
                                 # Shape to mesh and use the found element as elems
                                 # the method getElement(element)
                                 # does not return Solid elements
                                 ele_shape = geomtools.get_element(sub[0], elems)
                                 found_element = geomtools.find_element_in_shape(
                                     self.part_obj.Shape, ele_shape
                                 )
                                 if found_element:
                                     elems = found_element
                                 else:
                                     Console.PrintError(
                                         "One element of the meshregion {} could not be found "
                                         "in the Part to mesh. It will be ignored.\n"
                                         .format(mr_obj.Name)
                                     )
                             # print(elems)  # element
                             if elems not in self.ele_length_map:
                                 self.ele_length_map[elems] = Units.Quantity(
                                     mr_obj.CharacteristicLength
                                 ).Value
                             else:
                                 Console.PrintError(
                                     "The element {} of the meshregion {} has "
                                     "been added to another mesh region.\n"
                                     .format(elems, mr_obj.Name)
                                 )
                 else:
                     Console.PrintError(
                         "The meshregion: {} is not used to create the mesh "
                         "because the reference list is empty.\n"
                         .format(mr_obj.Name)
                     )
             else:
                 Console.PrintError(
                     "The meshregion: {} is not used to create the "
                     "mesh because the CharacteristicLength is 0.0 mm.\n"
                     .format(mr_obj.Name)
                 )
         for eleml in self.ele_length_map:
             # the method getElement(element) does not return Solid elements
             ele_shape = geomtools.get_element(self.part_obj, eleml)
             ele_vertexes = geomtools.get_vertexes_by_element(self.part_obj.Shape, ele_shape)
             self.ele_node_map[eleml] = ele_vertexes
         Console.PrintMessage("  {}\n".format(self.ele_length_map))
         Console.PrintMessage("  {}\n".format(self.ele_node_map))