예제 #1
0
 def clicked(self, button):
     if button == QtGui.QDialogButtonBox.Ignore:
         # ask for confirmation before resetting everything
         msgName = Asm4.nameLabel(self.selectedLink)
         # see whether the ExpressionEngine field is filled
         if self.selectedLink.ExpressionEngine:
             # if yes, then ask for confirmation
             confirmed = Asm4.confirmBox(
                 'This command will release all attachments on ' + msgName +
                 ' and set it to manual positioning in its current location.'
             )
             # if not, then it's useless to bother the user
         else:
             confirmed = True
         if confirmed:
             # unset the ExpressionEngine for the Placement
             self.selectedLink.setExpression('Placement', None)
             # reset the assembly properties
             Asm4.makeAsmProperties(self.selectedLink, reset=True)
             # finish
             FCC.PrintWarning("Part is now manually placed\n")
             self.finish()
         else:
             FCC.PrintWarning("Part untouched\n")
             self.finish()
예제 #2
0
def _get_translation_offset(reference_dimensions: List[float],
                            rotation: Rotation,
                            origin_translation_offset: Vector):
    reference_box = Part.makeBox(*reference_dimensions)
    reference_box.rotate(Vector(0, 0, 0), rotation.Axis,
                         degrees(rotation.Angle))
    first_vertex = reference_box.Vertexes[0]
    first_vertex_edges = find_edges_connected_to_vertex(
        first_vertex, reference_box.Edges)
    num_edges = len(first_vertex_edges)
    if num_edges != 3:
        message = 'Found {} edges'.format(num_edges)
        message += ' connected to cube vertex instead of 3.\n'
        Console.PrintWarning(message)
    x = y = z = 1.0
    for e in first_vertex_edges:
        if is_edge_parallel_to_x_axis(e):
            x = e.Length
        elif is_edge_parallel_to_y_axis(e):
            y = e.Length
        elif is_edge_parallel_to_z_axis(e):
            z = e.Length
        else:

            def round_vec(v):
                return Vector(round(v.x), round(v.y), round(v.z))

            Console.PrintWarning(
                'Edge: {} not parallel to x, y, or z axes\n'.format(
                    [round_vec(v.Point) for v in e.Vertexes]))

    return Vector(x * origin_translation_offset.x,
                  y * origin_translation_offset.y,
                  z * origin_translation_offset.z)
def log_warning_if_odd_number_of_z_axes(num_z_axes, num_heated_bed_rods):
    if num_z_axes % 2 == 1:
        Console.PrintWarning(
            'An odd number of {} Z axes has been detected when determining number of heated bed rods.\n'
            .format(num_z_axes))
        Console.PrintWarning(
            'Rounding down to {} Z axes and {} heated bed rods.\n'.format(
                num_z_axes - 1, num_heated_bed_rods))
 def get_face_side(self, frame, face):
     # Exclude cylindrical surfaces and holes
     if not isinstance(face.Surface, Part.Plane):
         Console.PrintWarning('Face is not planar.\n')
         return None
     lower_side, upper_side = self._get_sides()
     if self._is_between_lower_bounds(face, frame):
         return lower_side
     elif self._is_between_upper_bounds(face, frame):
         return upper_side
     else:
         warning_message = 'Face is not between upper or lower bounds.\n'
         Console.PrintWarning(warning_message)
         return None
예제 #5
0
 def Activated(self):
     #Handle single selected App::Link
     selectedLink = None
     parentAssembly = None
     selection = Asm4.getSelectedLink()
     if not selection:
         # This shouldn't happen
         FCC.PrintWarning(
             "This is not an error message you are supposed to see, something went wrong\n"
         )
         return
     else:
         parent = selection.getParentGeoFeatureGroup()
         # only handle if the parent is at the root of the document:
         if parent and parent.TypeId == 'App::Part' and parent.getParentGeoFeatureGroup(
         ) is None:
             # only accept Asm4 Models as assemblies
             # this is self-imposed, works also without an Asm4 Model
             if parent.Name == 'Model':
                 # launch the UI in the task panel
                 Gui.Control.showDialog(placeLinkUI())
             else:
                 Asm4.warningBox(
                     'Please select a link in the assembly Model')
         else:
             Asm4.warningBox('Please select a link in the assembly Model.')
     return
예제 #6
0
 def accept(self):
     if self.onApply():
         if self.selectedDatum:
             self.selectedDatum.ViewObject.ShowLabel = False
         self.finish()
     else:
         FCC.PrintWarning("Problem in selections\n")
예제 #7
0
    def onApply(self):
        # get the name of the part to attach to:
        # it's either the top level part name ('Model')
        # or the provided link's name.
        if self.parentList.currentText() == 'Parent Assembly':
            a_Link = 'Parent Assembly'
            a_Part = None
        elif self.parentList.currentIndex() > 1:
            parent = self.parentTable[ self.parentList.currentIndex() ]
            a_Link = parent.Name
            a_Part = parent.LinkedObject.Document.Name
        else:
            a_Link = None
            a_Part = None

        # the attachment LCS's name in the parent
        # check that something is selected in the QlistWidget
        if self.attLCSlist.selectedItems():
            a_LCS = self.attLCStable[ self.attLCSlist.currentRow() ].Name
        else:
            a_LCS = None

        # check that all of them have something in
        if a_Link and a_LCS :
            # <<LinkName>>.Placement.multiply( <<LinkName>>.<<LCS.>>.Placement )
            # expr = '<<'+ a_Part +'>>.Placement.multiply( <<'+ a_Part +'>>.<<'+ a_LCS +'.>>.Placement )'
            
            Asm4.placeObjectToLCS(self.selectedFastener, a_Link, a_Part, a_LCS)
            
            # highlight the selected fastener in its new position
            Gui.Selection.clearSelection()
            Gui.Selection.addSelection( self.activeDoc.Name, 'Model', self.selectedFastener.Name +'.')
        else:
            FCC.PrintWarning("Problem in selections\n")
        return
예제 #8
0
 def accept(self):
     if self.Apply():
         # highlight in the 3D window the object we placed
         self.finish()
     else:
         FCC.PrintWarning("Problem in selections\n")
         return
예제 #9
0
def find_selected_point() -> Optional[Tuple[Vector, str]]:
    main_window = Gui.getMainWindow()
    # MDI (Multiple Document Interface)
    mdi_area = main_window.findChild(QtGui.QMdiArea)

    active_sub_window = mdi_area.activeSubWindow()
    if active_sub_window.widget().metaObject().className(
    ) == 'SpreadsheetGui::SheetView':
        sheet = active_sub_window.widget()
        table = sheet.findChild(QtGui.QTableView)
        indexes = table.selectedIndexes()
        if len(indexes) > 0:
            Console.PrintMessage(
                f'{len(indexes)} indexes selected, picking 1st.\n')
            first = indexes[0]
            row = str(first.row() + 1)
            column = map_number_to_column(first.column() + 1)
            cell_address = column + row
            selection = Gui.Selection.getSelection()
            if len(selection) > 0:
                Console.PrintMessage(
                    f'{len(selection)} objects selected, picking 1st.\n')
                selected_sheet = selection[0]
                if selected_sheet.TypeId == 'Spreadsheet::Sheet':
                    obj = selected_sheet.get(cell_address)
                    label = selected_sheet.getAlias(cell_address)
                    if isinstance(obj, Placement):
                        return obj.Base, label
                    elif isinstance(obj, Vector):
                        return obj, label
                    else:
                        Console.PrintWarning(
                            f'Selected cell {cell_address} does not contain vector.\n'
                        )
                else:
                    Console.PrintWarning(f'Selected object must be sheet.\n')
            else:
                Console.PrintWarning('No selected objects.\n')
        else:
            Console.PrintWarning('No selected cell in spreasheet.\n')
    else:
        Console.PrintWarning('No active spreadsheet.\n')
def get_furl_transforms(root_document: Document) -> List[Transform]:
    root_document_path = Path(root_document.FileName)
    documents_path = root_document_path.parent
    tail_document_path = documents_path.joinpath('Tail', 'Tail.FCStd')
    tail_document = App.openDocument(str(tail_document_path))
    tail = find_object_by_label(tail_document, 'Tail')
    if len(tail.InList) == 0:
        Console.PrintWarning(f'{tail.Label} has no parents.\n')
        return None
    if len(tail.InList) > 1:
        Console.PrintWarning(
            f'{tail.Label} has more than 1 parent. Choosing 1st.\n')
    tail_parent = tail.InList[0]
    parent_placement = calculate_global_placement(tail_parent)
    hinge_outer = find_object_by_label(tail_document, 'Hinge_Outer')
    return [
        placement_to_dict('parent', parent_placement),
        placement_to_dict('tail', tail.Placement),
        placement_to_dict('hinge', hinge_outer.Placement)
    ]
예제 #11
0
def export(objectslist, fileString, group_values_dict_nogui=None):
    """
    Called when freecad exports a file.
    group_dict_no_gui: dictionary with group_numbers as keys and tuples
    of (marked_value (default=1), default_value (default=0))
    """
    if len(objectslist) != 1:
        Console.PrintError("This exporter can only export one object.\n")
        return
    obj = objectslist[0]
    if not obj.isDerivedFrom("Fem::FemMeshObject"):
        Console.PrintError("No FEM mesh object selected.\n")
        return

    if fileString != "":
        fileName, fileExtension = os.path.splitext(fileString)
        if fileExtension.lower() == ".xml":
            Console.PrintWarning(
                "XML is not designed to save higher order elements.\n")
            Console.PrintWarning("Reducing order for second order mesh.\n")
            Console.PrintWarning("Tri6 -> Tri3, Tet10 -> Tet4, etc.\n")
            writeFenicsXML.write_fenics_mesh_xml(obj, fileString)
        elif fileExtension.lower() == ".xdmf":
            mesh_groups = importToolsFem.get_FemMeshObjectMeshGroups(obj)
            if mesh_groups != ():
                # if there are groups found, make task panel available if GuiUp
                if FreeCAD.GuiUp == 1:
                    panel = WriteXDMFTaskPanel(obj, fileString)
                    FreeCADGui.Control.showDialog(panel)
                else:
                    # create default dict if groupdict_nogui is not None
                    if group_values_dict_nogui is None:
                        group_values_dict_nogui = dict([(g, (1, 0))
                                                        for g in mesh_groups])
                    writeFenicsXDMF.write_fenics_mesh_xdmf(
                        obj,
                        fileString,
                        group_values_dict=group_values_dict_nogui)
            else:
                writeFenicsXDMF.write_fenics_mesh_xdmf(obj, fileString)
예제 #12
0
def get_bound_box(obj: object) -> Optional[BoundBox]:
    bound_box = BoundBox()
    if (hasattr(obj, 'Shape') and obj.Shape and obj.Shape.BoundBox.isValid()):
        bound_box.add(obj.Shape.BoundBox)
    else:
        Console.PrintWarning(
            f'{obj.Label} has no Shape, calculating manual bounding box.')
        bound_box.add(Draft.get_bbox(obj))

    if not bound_box.isValid():
        Console.PrintError(
            f'{obj.Label} does not have a a valid bounding box.')
        return None
    return bound_box
예제 #13
0
 def makeVarLink(self, obj):
     # create a new, empty, hidden, temporary document
     tmpDocName = 'varTmpDoc_'
     i = 1
     while i < 100 and tmpDocName + str(i) in App.listDocuments():
         i += 1
     if i < 100:
         tmpDocName = 'varTmpDoc_' + str(i)
         tmpDoc = App.newDocument(tmpDocName, hidden=True, temp=True)
         # deep-copy the source object and link it back
         obj.LinkedObject = tmpDoc.copyObject(obj.SourceObject, True)
     else:
         FCC.PrintWarning(
             '100 temporary variant documents are already in use, not creating a new one.\n'
         )
     return
def calculate_global_placement(child: object,
                               placements: Placement = []) -> Placement:
    placements.append(child.Placement)
    in_list = child.InList
    num_in = len(in_list)
    if len(in_list) == 0:
        global_placement = Placement()
        placements.reverse()  # Reverse list in order of parent to child.
        for placement in placements:
            global_placement *= placement
        return global_placement
    if num_in > 1:
        Console.PrintWarning(
            f'{child.Label} has more than 1 parent. Choosing 1st.\n')
    parent = in_list[0]
    return calculate_global_placement(parent, placements)
예제 #15
0
    def onApply(self):
        # get the name of the part to attach to:
        # it's either the top level part name ('Model')
        # or the provided link's name.
        if self.parentList.currentText() == 'Parent Assembly':
            a_Link = 'Parent Assembly'
            a_Part = None
        elif self.parentList.currentIndex() > 1:
            parent = self.parentTable[ self.parentList.currentIndex() ]
            a_Link = parent.Name
            a_Part = parent.LinkedObject.Document.Name
        else:
            a_Link = None
            a_Part = None

        # the attachment LCS's name in the parent
        # check that something is selected in the QlistWidget
        if self.attLCSlist.selectedItems():
            a_LCS = self.attLCStable[ self.attLCSlist.currentRow() ].Name
        else:
            a_LCS = None

        # check that all of them have something in
        if a_Link and a_LCS :
            # <<LinkName>>.Placement.multiply( <<LinkName>>.<<LCS.>>.Placement )
            # expr = '<<'+ a_Part +'>>.Placement.multiply( <<'+ a_Part +'>>.<<'+ a_LCS +'.>>.Placement )'
            expr = self.makeExpressionFastener( a_Link, a_Part, a_LCS )
            # indicate the this fastener has been placed with the Assembly4 workbench
            if not hasattr(self.selectedFastener,'AssemblyType'):
                Asm4.makeAsmProperties(self.selectedFastener)
            self.selectedFastener.AssemblyType = 'Asm4EE'
            # the fastener is attached by its Origin, no extra LCS
            self.selectedFastener.AttachedBy = 'Origin'
            # store the part where we're attached to in the constraints object
            self.selectedFastener.AttachedTo = a_Link+'#'+a_LCS
            # load the built expression into the Expression field of the constraint
            self.selectedFastener.setExpression( 'Placement', expr )
            # recompute the object to apply the placement:
            self.selectedFastener.recompute()
            self.parentAssembly.recompute()
            self.activeDoc.recompute()
            # highlight the selected fastener in its new position
            Gui.Selection.clearSelection()
            Gui.Selection.addSelection( self.activeDoc.Name, 'Model', self.selectedFastener.Name +'.')
        else:
            FCC.PrintWarning("Problem in selections\n")
        return
예제 #16
0
    def onApply(self):
        # get the name of the part to attach to:
        # it's either the top level part name ('Model')
        # or the provided link's name.
        if self.parentList.currentText() == 'Parent Assembly':
            a_Link = 'Parent Assembly'
            a_Part = None
        elif self.parentList.currentIndex() > 1:
            parent = self.parentTable[self.parentList.currentIndex()]
            a_Link = parent.Name
            a_Part = parent.LinkedObject.Document.Name
        else:
            a_Link = None
            a_Part = None

        # the attachment LCS's name in the parent
        # check that something is selected in the QlistWidget
        if self.attLCSlist.selectedItems():
            a_LCS = self.attLCStable[self.attLCSlist.currentRow()].Name
        else:
            a_LCS = None

        # check that all of them have something in
        if a_Link and a_LCS:
            # add Asm4 properties if necessary
            Asm4.makeAsmProperties(self.selectedFastener, reset=True)
            # hide "offset" and "invert" properties to avoid confusion as they are not used in Asm4
            if hasattr(self.selectedFastener, 'offset'):
                self.selectedFastener.setPropertyStatus('offset', 'Hidden')
            if hasattr(self.selectedFastener, 'invert'):
                self.selectedFastener.setPropertyStatus('invert', 'Hidden')

            # <<LinkName>>.Placement.multiply( <<LinkName>>.<<LCS.>>.Placement )
            # expr = '<<'+ a_Part +'>>.Placement.multiply( <<'+ a_Part +'>>.<<'+ a_LCS +'.>>.Placement )'

            Asm4.placeObjectToLCS(self.selectedFastener, a_Link, a_Part, a_LCS)

            # highlight the selected fastener in its new position
            Gui.Selection.clearSelection()
            Gui.Selection.addSelection(self.activeDoc.Name,
                                       self.rootAssembly.Name,
                                       self.selectedFastener.Name + '.')
        else:
            FCC.PrintWarning("Problem in selections\n")
        return
예제 #17
0
    def get_group_data(self):
        # TODO: solids, faces, edges and vertexes don't seem to work together in one group,
        #       some output message or make them work together

        # mesh group objects
        if not self.mesh_obj.MeshGroupList:
            # print("  No mesh group objects.")
            pass
        else:
            Console.PrintMessage(
                "  Mesh group objects, we need to get the elements.\n")
            for mg in self.mesh_obj.MeshGroupList:
                new_group_elements = meshtools.get_mesh_group_elements(
                    mg, self.part_obj)
                for ge in new_group_elements:
                    if ge not in self.group_elements:
                        self.group_elements[ge] = new_group_elements[ge]
                    else:
                        Console.PrintError(
                            "  A group with this name exists already.\n")

        # group meshing for analysis
        analysis_group_meshing = FreeCAD.ParamGet(
            "User parameter:BaseApp/Preferences/Mod/Fem/General").GetBool(
                "AnalysisGroupMeshing", False)
        if self.analysis and analysis_group_meshing:
            Console.PrintWarning(
                "  Group meshing for analysis is set to true in FEM General Preferences. "
                "Are you really sure about this? You could run into trouble!\n"
            )
            self.group_nodes_export = True
            new_group_elements = meshtools.get_analysis_group_elements(
                self.analysis, self.part_obj)
            for ge in new_group_elements:
                if ge not in self.group_elements:
                    self.group_elements[ge] = new_group_elements[ge]
                else:
                    Console.PrintError(
                        "  A group with this name exists already.\n")
        else:
            Console.PrintMessage("  No Group meshing for analysis.\n")

        if self.group_elements:
            Console.PrintMessage("  {}\n".format(self.group_elements))
예제 #18
0
    def Activated(self, name=translate("draft", "Fillet")):
        DraftTools.Creator.Activated(self, name)
        if not self.doc:
            FCC.PrintWarning(translate("draft", "No active document") + "\n")
            return
        if self.ui:
            self.rad = 100
            self.chamfer = False
            self.delete = False
            label = translate("draft", "Fillet radius")
            tooltip = translate("draft", "Radius of fillet")

            # Call the Task panel for a radius
            # The graphical widgets are defined in DraftGui
            self.ui.taskUi(title=name, icon="Draft_Fillet")
            self.ui.radiusUi()
            self.ui.sourceCmd = self
            self.ui.labelRadius.setText(label)
            self.ui.radiusValue.setToolTip(tooltip)
            self.ui.setRadiusValue(self.rad, "Length")
            self.ui.check_delete = self.ui._checkbox("isdelete",
                                                     self.ui.layout,
                                                     checked=self.delete)
            self.ui.check_delete.setText(
                translate("draft", "Delete original objects"))
            self.ui.check_delete.show()
            self.ui.check_chamfer = self.ui._checkbox("ischamfer",
                                                      self.ui.layout,
                                                      checked=self.chamfer)
            self.ui.check_chamfer.setText(translate("draft", "Create chamfer"))
            self.ui.check_chamfer.show()

            QtCore.QObject.connect(self.ui.check_delete,
                                   QtCore.SIGNAL("stateChanged(int)"),
                                   self.set_delete)
            QtCore.QObject.connect(self.ui.check_chamfer,
                                   QtCore.SIGNAL("stateChanged(int)"),
                                   self.set_chamfer)
            self.linetrack = trackers.lineTracker(dotted=True)
            self.arctrack = trackers.arcTracker()
            # self.call = self.view.addEventCallback("SoEvent", self.action)
            FCC.PrintMessage(translate("draft", "Enter radius") + "\n")
예제 #19
0
def typecheck(args_and_types, name="?"):
    """Check that the arguments are instances of certain types.

    Parameters
    ----------
    args_and_types : list
        A list of tuples. The first element of a tuple is tested as being
        an instance of the second element.
        ::
            args_and_types = [(a, Type), (b, Type2), ...]

        Then
        ::
            isinstance(a, Type)
            isinstance(b, Type2)

        A `Type` can also be a tuple of many types, in which case
        the check is done for any of them.
        ::
            args_and_types = [(a, (Type3, int, float)), ...]

            isinstance(a, (Type3, int, float))

    name : str, optional
        Defaults to `'?'`. The name of the check.

    Raises
    -------
    TypeError
        If the first element in the tuple is not an instance of the second
        element.
    """
    for v, t in args_and_types:
        if not isinstance(v, t):
            _msg = ("typecheck[" + str(name) + "]: " + str(v) + " is not " +
                    str(t) + "\n")
            FCC.PrintWarning(_msg)
            raise TypeError("fcvec." + str(name))
예제 #20
0
def _print_warning_message(num_matches, subject, object_type):
    message_template = '{} {} matching type "{}" found in selection.'
    message_template += ' Returning first match.'
    message = message_template.format(num_matches, subject, object_type)
    Console.PrintWarning(message)
예제 #21
0
def importAvs(filename, analysis=None, result_name_prefix=""):
    import ObjectsFem
    from feminout import importToolsFem

    TUNE = False
    if TUNE:
        import time
        cur = time.time()

    if analysis:
        doc = analysis.Document
    else:
        doc = FreeCAD.ActiveDocument

    m = read_avs_result(filename)

    result_mesh_object = None
    res_obj = None

    if TUNE:
        new = time.time()
        Console.PrintMessage("dtime 1:" + '%8.3f' % (new - cur) + "\n")
        cur = new

    if len(m["Nodes"]) > 0:
        mesh = importToolsFem.make_femmesh(m)
        if TUNE:
            new = time.time()
            Console.PrintMessage("dtime 2:" + '%8.3f' % (new - cur) + "\n")
            cur = new

        result_mesh_object = ObjectsFem.makeMeshResult(doc, "ResultMesh")
        result_mesh_object.FemMesh = mesh
        res_mesh_is_compacted = False
        nodenumbers_for_compacted_mesh = []

        number_of_increments = len(m["Results"])
        Console.PrintLog("Increments: " + str(number_of_increments) + "\n")
        if TUNE:
            new = time.time()
            Console.PrintMessage("dtime 3:" + '%8.3f' % (new - cur) + "\n")
            cur = new
        if len(m["Results"]) > 0:

            for result_set in m["Results"]:
                if "number" in result_set:
                    eigenmode_number = result_set["number"]
                else:
                    eigenmode_number = 0
                step_time = result_set["time"]
                step_time = round(step_time, 2)
                if eigenmode_number > 0:
                    results_name = ("{}Mode{}_Results".format(
                        result_name_prefix, eigenmode_number))
                elif number_of_increments > 1:
                    results_name = ("{}Time{}_Results".format(
                        result_name_prefix, step_time))
                else:
                    results_name = ("{}Results".format(result_name_prefix))

                if TUNE:
                    new = time.time()
                    Console.PrintMessage("dtime 4:" + '%8.3f' % (new - cur) +
                                         "\n")
                    cur = new
                res_obj = ObjectsFem.makeResultMechanical(doc, results_name)
                res_obj.Mesh = result_mesh_object

                if TUNE:
                    new = time.time()
                    Console.PrintMessage("dtime 5:" + '%8.3f' % (new - cur) +
                                         "\n")
                    cur = new

                res_obj = importToolsFem.fill_femresult_mechanical(
                    res_obj, result_set)
                if analysis:
                    # need to be here, becasause later on, the analysis objs are needed
                    # see fill of principal stresses
                    analysis.addObject(res_obj)
                if TUNE:
                    new = time.time()
                    Console.PrintMessage("dtime 6:" + '%8.3f' % (new - cur) +
                                         "\n")
                    cur = new

                # more result object calculations
                from femresult import resulttools
                from femtools import femutils
                if not res_obj.MassFlowRate:
                    if res_mesh_is_compacted is False:
                        # first result set, compact FemMesh and NodeNumbers
                        res_obj = resulttools.compact_result(res_obj)
                        res_mesh_is_compacted = True
                        nodenumbers_for_compacted_mesh = res_obj.NodeNumbers
                    else:
                        # all other result sets, do not compact FemMesh, only set NodeNumbers
                        res_obj.NodeNumbers = nodenumbers_for_compacted_mesh

                if TUNE:
                    new = time.time()
                    Console.PrintMessage("dtime 7:" + '%8.3f' % (new - cur) +
                                         "\n")
                    cur = new
                # fill DisplacementLengths
                res_obj = resulttools.add_disp_apps(res_obj)

                if TUNE:
                    new = time.time()
                    Console.PrintMessage("dtime 8:" + '%8.3f' % (new - cur) +
                                         "\n")
                    cur = new

                # fill vonMises
                mstress = []
                for nid in res_obj.NodeNumbers:
                    mstress.append(result_set["mises"][nid])
                res_obj.vonMises = mstress

                if TUNE:
                    new = time.time()
                    Console.PrintMessage("dtime 9:" + '%8.3f' % (new - cur) +
                                         "\n")
                    cur = new

                # fill principal stress
                prinstress1 = []
                prinstress2 = []
                prinstress3 = []
                for nid in res_obj.NodeNumbers:
                    pstr = result_set["pstress"][nid]
                    prinstress1.append(pstr[0])
                    prinstress2.append(pstr[1])
                    prinstress3.append(pstr[2])
                res_obj.PrincipalMax = prinstress1
                res_obj.PrincipalMed = prinstress2
                res_obj.PrincipalMin = prinstress3

                # fill Stats
                res_obj = resulttools.fill_femresult_stats(res_obj)

                if TUNE:
                    new = time.time()
                    Console.PrintMessage("dtime10:" + '%8.3f' % (new - cur) +
                                         "\n")
                    cur = new
        else:
            error_message = (
                "Nodes, but no results found in avs file. "
                "It means there only is a mesh but no results in avs file. "
                "Usually this happens for: \n"
                "- analysis type 'NOANALYSIS'\n"
                "- if FrontISTR returned no results "
                "(happens on nonpositive jacobian determinant in at least one element)\n"
                "- just no avs results where requestet in input file "
                "(neither 'node file' nor 'el file' in output section')\n")
            Console.PrintWarning(error_message)

        # create a result obj, even if we have no results but a result mesh in avs file
        # see error message above for more information
        if not res_obj:
            if result_name_prefix:
                results_name = ("{}_Results".format(result_name_prefix))
            else:
                results_name = ("Results".format(result_name_prefix))
            res_obj = ObjectsFem.makeResultMechanical(doc, results_name)
            res_obj.Mesh = result_mesh_object
            # TODO, node numbers in result obj could be set
            if analysis:
                analysis.addObject(res_obj)

        if FreeCAD.GuiUp:
            if analysis:
                import FemGui
                FemGui.setActiveAnalysis(analysis)
            doc.recompute()

        if TUNE:
            new = time.time()
            Console.PrintMessage("dtime11:" + '%8.3f' % (new - cur) + "\n")
            cur = new

    else:
        Console.PrintError(
            "Problem on avs file import. No nodes found in avs file.\n")
        # None will be returned
        # or would it be better to raise an exception if there are not even nodes in avs file?

    return res_obj
예제 #22
0
                               placements: Placement = []) -> Placement:
    placements.append(child.Placement)
    in_list = child.InList
    num_in = len(in_list)
    if num_in == 0:
        global_placement = Placement()
        placements.reverse()  # Reverse list in order of parent to child.
        for placement in placements:
            global_placement *= placement
        return global_placement
    if num_in > 1:
        Console.PrintWarning(
            f'{child.Label} has more than 1 parent. Choosing 1st.\n')
    parent = in_list[0]
    Console.PrintMessage(f'{parent.Label} ({parent.TypeId})\n')
    return calculate_global_placement(parent, placements)


selection = Selection.getSelection()

if len(selection) == 0:
    Console.PrintWarning(f'Must select at least 1 object.')
else:
    if len(selection) > 1:
        Console.PrintWarning(f'Selected more than 1 object. Choosing 1st.')

    selected = selection[0]
    global_placement = calculate_global_placement(selected)
    Console.PrintMessage(f'{selected.Label} Global Placement\n')
    Console.PrintMessage(global_placement)
예제 #23
0
    def read_mesh_block(mesh_block):
        """
            Reading mesh block from XML file.
            The mesh block only contains cells and vertices.
        """
        dim = int(mesh_block.get("dim"))
        cell_type = mesh_block.get("celltype")

        vertex_size = 0

        Console.PrintLog("Mesh dimension: %d\n" % (dim, ))
        Console.PrintLog("Mesh cell type: %s\n" % (cell_type, ))

        # every cell type contains a dict with key=dimension and value=number

        cells_parts_dim = {
            "point": {
                0: 1
            },
            "interval": {
                0: 2,
                1: 1
            },
            "triangle": {
                0: 3,
                1: 3,
                2: 1
            },
            "tetrahedron": {
                0: 4,
                1: 6,
                2: 4,
                3: 1
            },
            "quadrilateral": {
                0: 4,
                1: 4,
                2: 1
            },
            "hexahedron": {
                0: 8,
                1: 12,
                2: 6,
                3: 1
            }
        }

        find_vertices = mesh_block.find("vertices")
        find_cells = mesh_block.find("cells")

        nodes_dict = {}
        cell_dict = {}

        if find_vertices is None:
            Console.PrintWarning("No vertices found!\n")
        else:
            vertex_size = int(find_vertices.attrib.get("size"))
            Console.PrintLog("Reading %d vertices\n" % (vertex_size, ))

            for vertex in find_vertices:
                ind = int(vertex.get("index"))

                if vertex.tag.lower() == "vertex":
                    [node_x, node_y, node_z] = [
                        float(vertex.get(coord, 0.))
                        for coord in ["x", "y", "z"]
                    ]

                    nodes_dict[ind + 1] = FreeCAD.Vector(
                        node_x, node_y, node_z)
                    # increase node index by one, since fenics starts at 0, FreeCAD at 1
                    # print("%d %f %f %f" % (ind, node_x, node_y, node_z))
                else:
                    Console.PrintWarning("found strange vertex tag: %s\n" %
                                         (vertex.tag, ))

        if find_cells is None:
            Console.PrintWarning("No cells found!\n")
        else:
            Console.PrintLog("Reading %d cells\n" %
                             (int(find_cells.attrib.get("size")), ))
            for cell in find_cells:
                ind = int(cell.get("index"))

                if cell.tag.lower() != cell_type.lower():
                    Console.PrintWarning(
                        "Strange mismatch between cell type {} and cell tag {}\n"
                        .format(cell_type, cell.tag.lower()))
                num_vertices = cells_parts_dim[cell_type][0]

                vtupel = tuple([
                    int(cell.get("v" + str(vnum))) + 1
                    for vnum in range(num_vertices)
                ])
                # generate "v0", "v1", ... from dimension lookup table
                # increase numbers by one to match FC numbering convention

                cell_dict[ind + 1] = vtupel

                # valtupel = tuple([ind] + list(vtupel))
                # print(("%d " + ("%d "*len(vtupel))) % valtupel)

        return (nodes_dict, cell_dict, cell_type, dim)
예제 #24
0
def read_fenics_mesh_xml(xmlfilename):
    """
        Returns element dictionary to be evaluated by make_femmesh later
    """

    Fenics_to_FreeCAD_dict = {
        "triangle": "tria3",
        "tetrahedron": "tetra4",
        "hexahedron": "hexa8",
        "interval": "seg2",
        "quadrilateral": "quad4",
    }

    def read_mesh_block(mesh_block):
        """
            Reading mesh block from XML file.
            The mesh block only contains cells and vertices.
        """
        dim = int(mesh_block.get("dim"))
        cell_type = mesh_block.get("celltype")

        vertex_size = 0

        Console.PrintLog("Mesh dimension: %d\n" % (dim, ))
        Console.PrintLog("Mesh cell type: %s\n" % (cell_type, ))

        # every cell type contains a dict with key=dimension and value=number

        cells_parts_dim = {
            "point": {
                0: 1
            },
            "interval": {
                0: 2,
                1: 1
            },
            "triangle": {
                0: 3,
                1: 3,
                2: 1
            },
            "tetrahedron": {
                0: 4,
                1: 6,
                2: 4,
                3: 1
            },
            "quadrilateral": {
                0: 4,
                1: 4,
                2: 1
            },
            "hexahedron": {
                0: 8,
                1: 12,
                2: 6,
                3: 1
            }
        }

        find_vertices = mesh_block.find("vertices")
        find_cells = mesh_block.find("cells")

        nodes_dict = {}
        cell_dict = {}

        if find_vertices is None:
            Console.PrintWarning("No vertices found!\n")
        else:
            vertex_size = int(find_vertices.attrib.get("size"))
            Console.PrintLog("Reading %d vertices\n" % (vertex_size, ))

            for vertex in find_vertices:
                ind = int(vertex.get("index"))

                if vertex.tag.lower() == "vertex":
                    [node_x, node_y, node_z] = [
                        float(vertex.get(coord, 0.))
                        for coord in ["x", "y", "z"]
                    ]

                    nodes_dict[ind + 1] = FreeCAD.Vector(
                        node_x, node_y, node_z)
                    # increase node index by one, since fenics starts at 0, FreeCAD at 1
                    # print("%d %f %f %f" % (ind, node_x, node_y, node_z))
                else:
                    Console.PrintWarning("found strange vertex tag: %s\n" %
                                         (vertex.tag, ))

        if find_cells is None:
            Console.PrintWarning("No cells found!\n")
        else:
            Console.PrintLog("Reading %d cells\n" %
                             (int(find_cells.attrib.get("size")), ))
            for cell in find_cells:
                ind = int(cell.get("index"))

                if cell.tag.lower() != cell_type.lower():
                    Console.PrintWarning(
                        "Strange mismatch between cell type {} and cell tag {}\n"
                        .format(cell_type, cell.tag.lower()))
                num_vertices = cells_parts_dim[cell_type][0]

                vtupel = tuple([
                    int(cell.get("v" + str(vnum))) + 1
                    for vnum in range(num_vertices)
                ])
                # generate "v0", "v1", ... from dimension lookup table
                # increase numbers by one to match FC numbering convention

                cell_dict[ind + 1] = vtupel

                # valtupel = tuple([ind] + list(vtupel))
                # print(("%d " + ("%d "*len(vtupel))) % valtupel)

        return (nodes_dict, cell_dict, cell_type, dim)

    def generate_lower_dimensional_structures(nodes, cell_dict, cell_type,
                                              dim):
        def correct_volume_det(element_dict):
            """
                Checks whether the cell elements
                all have the same volume (<0?)
                sign (is necessary to avoid negative
                Jacobian errors).
                Works only with tet4 and tri3 elements at the moment
            """
            if dim == 3:
                for (ind, tet) in list(element_dict["tetra4"].items()):
                    v0 = nodes[tet[0]]
                    v1 = nodes[tet[1]]
                    v2 = nodes[tet[2]]
                    v3 = nodes[tet[3]]
                    a = v1 - v0
                    b = v2 - v0
                    c = v3 - v0
                    if a.dot(b.cross(c)) > 0:
                        element_dict["tetra4"][ind] = (tet[1], tet[0], tet[2],
                                                       tet[3])
            if dim == 2:
                nz = FreeCAD.Vector(0., 0., 1.)
                for (ind, tria) in list(element_dict["tria3"].items()):
                    v0 = nodes[tria[0]]
                    v1 = nodes[tria[1]]
                    v2 = nodes[tria[2]]
                    a = v1 - v0
                    b = v2 - v0
                    if nz.dot(a.cross(b)) < 0:
                        element_dict["tria3"][ind] = (tria[1], tria[0],
                                                      tria[2])

        element_dict = {}
        element_counter = {}

        # TODO: remove upper level lookup
        for (key, val) in list(Fenics_to_FreeCAD_dict.items()):
            element_dict[val] = {}
            element_counter[
                key] = 0  # count every distinct element and sub element type

        def addtupletodict(di, tpl, counter):
            sortedtpl = tuple(sorted(tpl))
            if di.get(sortedtpl) is None:
                di[sortedtpl] = counter
                counter += 1
            return counter

        def invertdict(dic):
            invdic = {}
            for (key, it) in list(dic.items()):
                invdic[it] = key
            return invdic

        num_vert_dict = {
            "interval": 2,
            "triangle": 3,
            "tetrahedron": 4,
            "hexahedron": 8,
            "quadrilateral": 4
        }
        lower_dims_dict = {
            "interval": [],
            "triangle": ["interval"],
            "tetrahedron": ["triangle", "interval"],
            "hexahedron": ["quadrilateral", "interval"],
            "quadrilateral": ["interval"]
        }

        # generate cell list from file
        # read vertex list from cells
        # generate lower dimensional objects in mesh from cell

        for (cell_index, cell) in list(cell_dict.items()):
            cell_lower_dims = lower_dims_dict[cell_type]
            element_counter[cell_type] += 1
            element_dict[Fenics_to_FreeCAD_dict[cell_type]][
                cell] = element_counter[cell_type]
            for ld in cell_lower_dims:
                for vertextuple in itertools.combinations(
                        cell, num_vert_dict[ld]):
                    element_counter[ld] = addtupletodict(
                        element_dict[Fenics_to_FreeCAD_dict[ld]], vertextuple,
                        element_counter[ld])

        length_counter = len(nodes)  # maintain distinct counting values
        # print("nodes")
        # print("len & len counter", length_counter)
        for (key, val_dict) in list(element_dict.items()):
            # to ensure distinct indices for FreeCAD
            # print("key: ", key)
            for (vkey, it) in list(val_dict.items()):
                val_dict[
                    vkey] = it + length_counter  # maintain distinct element numbers
            len_val_dict = len(val_dict)
            if len_val_dict > 0:
                length_counter += len_val_dict + 1  # only if preceding list is not empty
            # print("len: ", len_val_dict)
            # print("lencounter: ", length_counter)
            # inverse of the dict (dict[key] = val -> dict[val] = key)
            element_dict[key] = invertdict(val_dict)

        correct_volume_det(element_dict)  # corrects negative determinants

        return element_dict  # returns complete element dictionary

    nodes = {}
    element_dict = {}
    # TODO: remove two times initialization
    for val in list(Fenics_to_FreeCAD_dict.values()):
        element_dict[val] = {}

    tree = ET.parse(xmlfilename)
    root = tree.getroot()

    if root.tag.lower() != "dolfin":
        Console.PrintWarning("Strange root tag, should be dolfin!\n")

    find_mesh = root.find("mesh")
    if find_mesh is not None:  # these are consistency checks of the XML structure
        Console.PrintMessage("Mesh found\n")
        (nodes, cells_dict, cell_type, dim) = read_mesh_block(find_mesh)
        element_dict = generate_lower_dimensional_structures(
            nodes, cells_dict, cell_type, dim)
        Console.PrintMessage("Show min max element dict")
        for (elm, numbers) in list(element_dict.items()):
            lst = sorted(list(numbers.items()), key=lambda x: x[0])
            if lst != []:
                Console.PrintWarning(elm, " min: ", lst[0], " max: ", lst[-1],
                                     "\n")
    else:
        Console.PrintError("No mesh found")

    if root.find("data") is not None:
        Console.PrintLog("Internal mesh data found\n")

    return {
        "Nodes": nodes,
        "Seg2Elem": element_dict["seg2"],
        "Seg3Elem": {},
        "Tria3Elem": element_dict["tria3"],
        "Tria6Elem": {},
        "Quad4Elem": element_dict["quad4"],
        "Quad8Elem": {},
        "Tetra4Elem": element_dict["tetra4"],
        "Tetra10Elem": {},
        "Hexa8Elem": {},
        "Hexa20Elem": {},
        "Penta6Elem": {},
        "Penta15Elem": {}
    }
예제 #25
0
    def __init__(self):
        # remove selectionFilter
        self.selectionFilterStatus = selectionFilter.observerStatus()
        selectionFilter.observerDisable()

        # get the current active document to avoid errors if user changes tab
        self.activeDoc = App.ActiveDocument

        # we have checked before that all this is correct 
        selection = Asm4.getSelectedLink()
        if selection is None:
            selection = Asm4.getSelectedVarLink()
        self.selectedObj = selection

        #self.rootAssembly = self.selectedObj.getParentGeoFeatureGroup()
        self.rootAssembly = Asm4.getAssembly()

        # has been checked before, this is for security only
        if Asm4.isAsm4EE(self.selectedObj):
            # get the old values
            self.old_AO = self.selectedObj.AttachmentOffset
            self.old_linkLCS = self.selectedObj.AttachedBy[1:]
        else:
            # this shouldn't happen
            FCC.PrintWarning("WARNING : unsupported Assembly/Solver/Part combination, you shouldn't be seeing this\n")
            Asm4.makeAsmProperties(self.selectedObj)
            self.old_AO = []
            self.old_linkLCS = ''

        # define the GUI
        # draw the GUI, objects are defined later down
        # self.UI = QtGui.QWidget()
        # self.form = self.UI
        self.form = QtGui.QWidget()
        iconFile = os.path.join( Asm4.iconPath , 'Place_Link.svg')
        self.form.setWindowIcon(QtGui.QIcon( iconFile ))
        self.form.setWindowTitle('Place linked Part')
        self.drawUI(self.form)

        #save original AttachmentOffset of linked part
        self.old_LinkAttachmentOffset = self.selectedObj.AttachmentOffset
        self.old_LinkRotation = self.selectedObj.AttachmentOffset.Rotation
        self.old_LinkPosition = self.selectedObj.AttachmentOffset.Base
        # default values correspond to original AttachmentOffset of linked part
        self.Xtranslation = self.old_LinkPosition[0]
        self.Ytranslation = self.old_LinkPosition[1]
        self.Ztranslation = self.old_LinkPosition[2]
        self.XrotationAngle = self.old_LinkRotation.toEuler()[0]
        self.YrotationAngle = self.old_LinkRotation.toEuler()[1]
        self.ZrotationAngle = self.old_LinkRotation.toEuler()[2]
        
        # save previous view properties
        self.old_OverrideMaterial = self.selectedObj.ViewObject.OverrideMaterial
        self.old_DrawStyle = self.selectedObj.ViewObject.DrawStyle
        self.old_LineWidth = self.selectedObj.ViewObject.LineWidth
        self.old_DiffuseColor = self.selectedObj.ViewObject.ShapeMaterial.DiffuseColor
        self.old_Transparency = self.selectedObj.ViewObject.ShapeMaterial.Transparency
        # set new view properties
        self.selectedObj.ViewObject.OverrideMaterial = True
        self.selectedObj.ViewObject.DrawStyle = DrawStyle
        self.selectedObj.ViewObject.LineWidth = LineWidth
        self.selectedObj.ViewObject.ShapeMaterial.DiffuseColor = DiffuseColor
        self.selectedObj.ViewObject.ShapeMaterial.Transparency = Transparency
        

        # get the old values
        self.old_EE     = ''
        old_Parent      = ''
        old_ParentPart  = ''
        old_attLCS      = ''
        constrName      = ''
        linkedDoc       = ''
        old_linkLCS     = ''
        # get and store the current expression engine:
        self.old_EE = Asm4.placementEE(self.selectedObj.ExpressionEngine)

        # decode the old ExpressionEngine
        # if the decode is unsuccessful, old_Expression is set to False and the other things are set to 'None'
        (self.old_Parent, separator, self.old_parentLCS) = self.selectedObj.AttachedTo.partition('#')
        ( old_Parent, old_attLCS, old_linkLCS ) = self.splitExpressionLink( self.old_EE, self.old_Parent )
        # sometimes, the object is in << >> which is an error by FreeCAD,
        # because that's reserved for labels, but we still look for it
        if len(old_attLCS)>4 and old_attLCS[:2]=='<<' and old_attLCS[-2:]=='>>':
            old_attLCS = old_attLCS[2:-2]
        if len(old_linkLCS)>4 and old_linkLCS[:2]=='<<' and old_linkLCS[-2:]=='>>':
            old_linkLCS = old_linkLCS[2:-2]

        # initialize the UI with the current data
        self.attLCStable = []
        self.initUI()
        # now self.parentList and self.parentTable are available

        # find all the linked parts in the assembly
        for obj in self.activeDoc.findObjects("App::Link"):
            if self.rootAssembly.getObject(obj.Name) is not None and hasattr(obj.LinkedObject,'isDerivedFrom'):
                linkedObj = obj.LinkedObject
                if linkedObj.isDerivedFrom('App::Part') or linkedObj.isDerivedFrom('PartDesign::Body'):
                # ... except if it's the selected link itself
                    if obj != self.selectedObj:
                        self.parentTable.append( obj )
                        # add to the drop-down combo box with the assembly tree's parts
                        objIcon = linkedObj.ViewObject.Icon
                        objText = Asm4.labelName(obj)
                        self.parentList.addItem( objIcon, objText, obj)

        # find all the LCS in the selected link
        self.partLCStable = Asm4.getPartLCS( self.selectedObj.LinkedObject )
        # build the list
        self.partLCSlist.clear()
        for lcs in self.partLCStable:
            newItem = QtGui.QListWidgetItem()
            newItem.setText(Asm4.labelName(lcs))
            newItem.setIcon( lcs.ViewObject.Icon )
            self.partLCSlist.addItem(newItem)

        # find the old LCS in the list of LCS of the linked part...
        # MatchExactly, MatchContains, MatchEndsWith ...
        # find with Name ...
        lcs_found = self.partLCSlist.findItems( old_linkLCS, QtCore.Qt.MatchExactly )
        # ... or with (Name)
        if not lcs_found:
            lcs_found = self.partLCSlist.findItems( '('+old_linkLCS+')', QtCore.Qt.MatchEndsWith )
        if lcs_found:
            # ... and select it
            self.partLCSlist.setCurrentItem( lcs_found[0] )

        # find the oldPart in the part list...
        if old_Parent == 'Parent Assembly':
            parent_found = True
            parent_index = 1
        else:
            parent_found = False
            parent_index = 1
            for item in self.parentTable[1:]:
                if item.Name == old_Parent:
                    parent_found = True
                    break
                else:
                    parent_index = parent_index +1
        if not parent_found:
            parent_index = 0
        self.parentList.setCurrentIndex( parent_index )
        # this should have triggered self.getPartLCS() to fill the LCS list

        # find the old attachment Datum in the list of the Datums in the linked part...
        lcs_found = self.attLCSlist.findItems( old_attLCS, QtCore.Qt.MatchExactly )
        if not lcs_found:
            lcs_found = self.attLCSlist.findItems( '('+old_attLCS+')', QtCore.Qt.MatchEndsWith )
        if lcs_found:
            # ... and select it
            self.attLCSlist.setCurrentItem( lcs_found[0] )
        # selection observer to detect selection of LCS in the 3D window and tree
        Gui.Selection.addObserver(self, 0)
예제 #26
0
    def Apply( self ):
        # get the instance to attach to:
        # it's either the top level assembly or a sister App::Link
        if self.parentList.currentText() == 'Parent Assembly':
            a_Link = 'Parent Assembly'
            a_Part = None
        elif self.parentList.currentIndex() > 1:
            parent = self.parentTable[ self.parentList.currentIndex() ]
            a_Link = parent.Name
            a_Part = parent.LinkedObject.Document.Name
        else:
            a_Link = None
            a_Part = None

        # the attachment LCS's name in the parent
        # check that something is selected in the QlistWidget
        if self.attLCSlist.selectedItems():
            a_LCS = self.attLCStable[ self.attLCSlist.currentRow() ].Name
        else:
            a_LCS = None

        # the linked App::Part's name
        l_Part = self.selectedObj.LinkedObject.Document.Name

        # the LCS's name in the linked part to be used for its attachment
        # check that something is selected in the QlistWidget
        if self.partLCSlist.selectedItems():
            #l_LCS = self.partLCSlist.selectedItems()[0].text()
            l_LCS = self.partLCStable[ self.partLCSlist.currentRow() ].Name
        else:
            l_LCS = None
            
        # check that all of them have something in
        # constrName has been checked at the beginning
        if a_Link and a_LCS and l_Part and l_LCS :
            # add the Asm4 properties if it's a pure App::Link
            Asm4.makeAsmProperties(self.selectedObj)
            # self.selectedObj.AssemblyType = 'Part::Link'
            self.selectedObj.AttachedBy = '#'+l_LCS
            self.selectedObj.AttachedTo = a_Link+'#'+a_LCS
            self.selectedObj.SolverId = 'Placement::ExpressionEngine'
            # build the expression for the ExpressionEngine
            # this is where all the magic is, see:
            # 
            # https://forum.freecadweb.org/viewtopic.php?p=278124#p278124
            #
            # as of FreeCAD v0.19 the syntax is different:
            # https://forum.freecadweb.org/viewtopic.php?f=17&t=38974&p=337784#p337784
            #
            # expr = ParentLink.Placement * ParentPart#LCS.Placement * constr_LinkName.AttachmentOffset * LinkedPart#LCS.Placement ^ -1'			
            # expr = LCS_in_the_assembly.Placement * constr_LinkName.AttachmentOffset * LinkedPart#LCS.Placement ^ -1'			
            expr = Asm4.makeExpressionPart( a_Link, a_Part, a_LCS, l_Part, l_LCS )
            # load the expression into the link's Expression Engine
            self.selectedObj.setExpression('Placement', expr )
            # recompute the object to apply the placement:
            self.selectedObj.recompute()
            self.rootAssembly.recompute(True)
            return True
        else:
            FCC.PrintWarning("Problem in selections\n")
            return False
예제 #27
0
 def _is_between_lower_bounds(self, face, frame):
     Console.PrintWarning('Bottom side bounds checking not supported.\n')
     pass
예제 #28
0
    def __init__(self):
        self.base = QtGui.QWidget()
        self.form = self.base
        iconFile = os.path.join(Asm4.iconPath, 'Place_Link.svg')
        self.form.setWindowIcon(QtGui.QIcon(iconFile))
        self.form.setWindowTitle('Place linked Part')

        # check that we have selected two LCS or an App::Link object
        self.selectedLink = []
        self.selectedLCSA = None
        self.selectedLinkB = None
        self.selectedLCSB = None
        selection = Asm4.getSelectedLink()
        #selectedLCSPair = Asm4.getLinkAndDatum2()
        self.Xtranslation = 0.00
        self.Ytranslation = 0.00
        self.Ztranslation = 0.00
        self.XrotationAngle = 0.00
        self.YrotationAngle = 0.00
        self.ZrotationAngle = 0.00

        # draw the GUI, objects are defined later down
        self.drawUI()
        global taskUI
        taskUI = self

        #Handle single selected App::Link
        if not selection:
            # This shouldn't happen
            FCC.PrintWarning(
                "This is not an error message you are supposed to see, something went wrong\n"
            )
            Gui.Control.closeDialog()
        else:
            self.selectedLink = selection
            Asm4.makeAsmProperties(self.selectedLink)

        #save original AttachmentOffset of linked part
        self.old_LinkAttachmentOffset = self.selectedLink.AttachmentOffset
        self.old_LinkRotation = self.selectedLink.AttachmentOffset.Rotation
        self.old_LinkPosition = self.selectedLink.AttachmentOffset.Base
        # default values correspond to original AttachmentOffset of linked part
        self.Xtranslation = self.old_LinkPosition[0]
        self.Ytranslation = self.old_LinkPosition[1]
        self.Ztranslation = self.old_LinkPosition[2]
        self.XrotationAngle = self.old_LinkRotation.toEuler()[0]
        self.YrotationAngle = self.old_LinkRotation.toEuler()[1]
        self.ZrotationAngle = self.old_LinkRotation.toEuler()[2]

        # save previous view properties
        self.old_OverrideMaterial = self.selectedLink.ViewObject.OverrideMaterial
        self.old_DrawStyle = self.selectedLink.ViewObject.DrawStyle
        self.old_LineWidth = self.selectedLink.ViewObject.LineWidth
        self.old_DiffuseColor = self.selectedLink.ViewObject.ShapeMaterial.DiffuseColor
        self.old_Transparency = self.selectedLink.ViewObject.ShapeMaterial.Transparency
        # set new view properties
        self.selectedLink.ViewObject.OverrideMaterial = True
        self.selectedLink.ViewObject.DrawStyle = DrawStyle
        self.selectedLink.ViewObject.LineWidth = LineWidth
        self.selectedLink.ViewObject.ShapeMaterial.DiffuseColor = DiffuseColor
        self.selectedLink.ViewObject.ShapeMaterial.Transparency = Transparency

        # get the current active document to avoid errors if user changes tab
        self.activeDoc = App.activeDocument()
        # the parent (top-level) assembly is the App::Part called Model (hard-coded)
        self.parentAssembly = self.activeDoc.Model

        # check that the link is an Asm4 link:
        self.isAsm4EE = False
        if hasattr(self.selectedLink, 'AssemblyType'):
            if self.selectedLink.AssemblyType == 'Asm4EE' or self.selectedLink.AssemblyType == '':
                self.isAsm4EE = True
            else:
                Asm4.warningBox(
                    "This Link's assembly type doesn't correspond to this WorkBench"
                )
                return

        # initialize the UI with the current data
        self.attLCStable = []
        self.initUI()
        # now self.parentList and self.parentTable are available

        # find all the linked parts in the assembly
        for objName in self.parentAssembly.getSubObjects():
            # remove the trailing .
            obj = self.activeDoc.getObject(objName[0:-1])
            if obj.TypeId == 'App::Link' and hasattr(obj.LinkedObject,
                                                     'isDerivedFrom'):
                if obj.LinkedObject.isDerivedFrom(
                        'App::Part') or obj.LinkedObject.isDerivedFrom(
                            'PartDesign::Body'):
                    # ... except if it's the selected link itself
                    if obj != self.selectedLink:
                        self.parentTable.append(obj)
                        # add to the drop-down combo box with the assembly tree's parts
                        objIcon = obj.LinkedObject.ViewObject.Icon
                        objText = Asm4.nameLabel(obj)
                        self.parentList.addItem(objIcon, objText, obj)

        # find all the LCS in the selected link
        self.partLCStable = Asm4.getPartLCS(self.selectedLink.LinkedObject)
        # build the list
        self.partLCSlist.clear()
        for lcs in self.partLCStable:
            newItem = QtGui.QListWidgetItem()
            newItem.setText(Asm4.nameLabel(lcs))
            newItem.setIcon(lcs.ViewObject.Icon)
            self.partLCSlist.addItem(newItem)

        # get the old values
        if self.isAsm4EE:
            self.old_AO = self.selectedLink.AttachmentOffset
            self.old_linkLCS = self.selectedLink.AttachedBy[1:]
            (self.old_Parent, separator,
             self.old_parentLCS) = self.selectedLink.AttachedTo.partition('#')
        else:
            self.old_AO = []
            self.old_Parent = ''

        self.old_EE = ''
        # get and store the current expression engine:
        self.old_EE = Asm4.placementEE(self.selectedLink.ExpressionEngine)

        # decode the old ExpressionEngine
        old_Parent = ''
        old_ParentPart = ''
        old_attLCS = ''
        constrName = ''
        linkedDoc = ''
        old_linkLCS = ''
        # if the decode is unsuccessful, old_Expression is set to False and the other things are set to 'None'
        (old_Parent, old_attLCS,
         old_linkLCS) = Asm4.splitExpressionLink(self.old_EE, self.old_Parent)

        # find the old LCS in the list of LCS of the linked part...
        # MatchExactly, MatchContains, MatchEndsWith ...
        lcs_found = self.partLCSlist.findItems(old_linkLCS,
                                               QtCore.Qt.MatchExactly)
        if not lcs_found:
            lcs_found = self.partLCSlist.findItems(old_linkLCS + ' (',
                                                   QtCore.Qt.MatchStartsWith)
        if lcs_found:
            # ... and select it
            self.partLCSlist.setCurrentItem(lcs_found[0])

        # find the oldPart in the part list...
        if old_Parent == 'Parent Assembly':
            parent_found = True
            parent_index = 1
        else:
            parent_found = False
            parent_index = 1
            for item in self.parentTable[1:]:
                if item.Name == old_Parent:
                    parent_found = True
                    break
                else:
                    parent_index = parent_index + 1
        if not parent_found:
            parent_index = 0
        self.parentList.setCurrentIndex(parent_index)
        # this should have triggered self.getPartLCS() to fill the LCS list

        # find the old attachment Datum in the list of the Datums in the linked part...
        lcs_found = self.attLCSlist.findItems(old_attLCS,
                                              QtCore.Qt.MatchExactly)
        if not lcs_found:
            lcs_found = self.attLCSlist.findItems(old_attLCS + ' (',
                                                  QtCore.Qt.MatchStartsWith)
        if lcs_found:
            # ... and select it
            self.attLCSlist.setCurrentItem(lcs_found[0])
예제 #29
0
def get_lengths(arc, mat):
    """
    Get needed parameters for arc calculation
    from the user-defined arc or the calculated vector matrix
    """

    #[0,1] = Radius; [2, 3] = Tangent, [4] = Middle, [5] = Chord
    lengths = mat.diagonal().A[0]

    params = [
        arc.get('Radius'),
        arc.get('Tangent'),
        arc.get('Middle'),
        arc.get('Chord'),
        arc.get('Delta')
    ]

    for _i in range(0, 2):

        #get two consecutive elements, saving only if they're valid
        _s = [_v for _v in lengths[_i * 2:(_i + 1) * 2] if _v]

        #skip the rest if not defined, we'll use the user values
        if not any(_s):
            continue

        #duplicate the only calculated length
        if len(_s) == 1:
            _s.append(_s[0])

        #if both were calculated and they aren't the same, quit
        if all(_s) and not support.within_tolerance(_s[0], _s[1]):

            _attribs = ['radius', 'Start-Center-End']

            if _i == 1:
                _attribs = ['tangent', 'Start-PI-End']

            Console.PrintWarning("""
            \nArc {0} length and {1} distance mismatch by {2:f} mm. Using calculated value of {3:f} mm
            """\
                .format(_attribs[0], _attribs[1], abs(_s[1] - _s[0]), _s[0]))

        if _s[0]:
            if not support.within_tolerance(_s[0], params[_i]):
                params[_i] = _s[0]

    #test middle and chord.
    #If no user-defined value or out-of-tolerance, use calculated
    for _i in range(4, 6):

        if lengths[_i]:
            if not support.within_tolerance(lengths[_i], params[_i - 2]):
                params[_i - 2] = lengths[_i]

    return {
        'Radius': params[0],
        'Tangent': params[1],
        'Middle': params[2],
        'Chord': params[3]
    }
예제 #30
0
def importFrd(filename, analysis=None, result_name_prefix=""):
    import ObjectsFem
    from . import importToolsFem

    if analysis:
        doc = analysis.Document
    else:
        doc = FreeCAD.ActiveDocument

    m = read_frd_result(filename)
    result_mesh_object = None
    res_obj = None

    if len(m["Nodes"]) > 0:
        mesh = importToolsFem.make_femmesh(m)
        result_mesh_object = ObjectsFem.makeMeshResult(doc, "ResultMesh")
        result_mesh_object.FemMesh = mesh
        res_mesh_is_compacted = False
        nodenumbers_for_compacted_mesh = []

        number_of_increments = len(m["Results"])
        Console.PrintLog("Increments: " + str(number_of_increments) + "\n")
        if len(m["Results"]) > 0:
            for result_set in m["Results"]:
                if "number" in result_set:
                    eigenmode_number = result_set["number"]
                else:
                    eigenmode_number = 0
                step_time = result_set["time"]
                step_time = round(step_time, 2)
                if eigenmode_number > 0:
                    results_name = ("{}Mode{}_Results".format(
                        result_name_prefix, eigenmode_number))
                elif number_of_increments > 1:
                    results_name = ("{}Time{}_Results".format(
                        result_name_prefix, step_time))
                else:
                    results_name = ("{}Results".format(result_name_prefix))

                res_obj = ObjectsFem.makeResultMechanical(doc, results_name)
                res_obj.Mesh = result_mesh_object
                res_obj = importToolsFem.fill_femresult_mechanical(
                    res_obj, result_set)
                if analysis:
                    # need to be here, becasause later on, the analysis objs are needed
                    # see fill of principal stresses
                    analysis.addObject(res_obj)

                # more result object calculations
                from femresult import resulttools
                from femtools import femutils
                if not res_obj.MassFlowRate:
                    # information 1:
                    # only compact result if not Flow 1D results
                    # compact result object, workaround for bug 2873
                    # https://www.freecadweb.org/tracker/view.php?id=2873
                    # information 2:
                    # if the result data has multiple result sets there will be multiple result objs
                    # they all will use one mesh obj
                    # on the first res obj fill: the mesh obj will be compacted, thus
                    # it does not need to be compacted on further result sets
                    # but NodeNumbers need to be compacted for every result set (res object fill)
                    # example frd file: https://forum.freecadweb.org/viewtopic.php?t=32649#p274291
                    if res_mesh_is_compacted is False:
                        # first result set, compact FemMesh and NodeNumbers
                        res_obj = resulttools.compact_result(res_obj)
                        res_mesh_is_compacted = True
                        nodenumbers_for_compacted_mesh = res_obj.NodeNumbers
                    else:
                        # all other result sets, do not compact FemMesh, only set NodeNumbers
                        res_obj.NodeNumbers = nodenumbers_for_compacted_mesh

                # fill DisplacementLengths
                res_obj = resulttools.add_disp_apps(res_obj)
                # fill vonMises
                res_obj = resulttools.add_von_mises(res_obj)
                # fill principal stress
                # if material reinforced object use add additional values to the res_obj
                if res_obj.getParentGroup():
                    has_reinforced_mat = False
                    for obj in res_obj.getParentGroup().Group:
                        if femutils.is_of_type(obj, "Fem::MaterialReinforced"):
                            has_reinforced_mat = True
                            Console.PrintLog(
                                "Reinfoced material object detected, "
                                "reinforced principal stresses and standard principal "
                                " stresses will be added.\n")
                            resulttools.add_principal_stress_reinforced(
                                res_obj)
                            break
                    if has_reinforced_mat is False:
                        Console.PrintLog(
                            "No einfoced material object detected, "
                            "standard principal stresses will be added.\n")
                        # fill PrincipalMax, PrincipalMed, PrincipalMin, MaxShear
                        res_obj = resulttools.add_principal_stress_std(res_obj)
                else:
                    Console.PrintLog(
                        "No Analysis detected, standard principal stresses will be added.\n"
                    )
                    # if a pure frd file was opened no analysis and thus no parent group
                    # fill PrincipalMax, PrincipalMed, PrincipalMin, MaxShear
                    res_obj = resulttools.add_principal_stress_std(res_obj)
                # fill Stats
                res_obj = resulttools.fill_femresult_stats(res_obj)

        else:
            error_message = (
                "Nodes, but no results found in frd file. "
                "It means there only is a mesh but no results in frd file. "
                "Usually this happens for: \n"
                "- analysis type 'NOANALYSIS'\n"
                "- if CalculiX returned no results "
                "(happens on nonpositive jacobian determinant in at least one element)\n"
                "- just no frd results where requestet in input file "
                "(neither 'node file' nor 'el file' in output section')\n")
            Console.PrintWarning(error_message)

        # create a result obj, even if we have no results but a result mesh in frd file
        # see error message above for more information
        if not res_obj:
            if result_name_prefix:
                results_name = ("{}_Results".format(result_name_prefix))
            else:
                results_name = ("Results".format(result_name_prefix))
            res_obj = ObjectsFem.makeResultMechanical(doc, results_name)
            res_obj.Mesh = result_mesh_object
            # TODO, node numbers in result obj could be set
            if analysis:
                analysis.addObject(res_obj)

        if FreeCAD.GuiUp:
            if analysis:
                import FemGui
                FemGui.setActiveAnalysis(analysis)
            doc.recompute()

    else:
        Console.PrintError(
            "Problem on frd file import. No nodes found in frd file.\n")
        # None will be returned
        # or would it be better to raise an exception if there are not even nodes in frd file?

    return res_obj