def get_used_mkfluid_labels(self) -> list: "Retrurns a list with all the MKFluid labels used on the case." to_ret = list() for obj in Case.the().get_all_fluid_objects(): if get_fc_object(obj.name).Label not in to_ret: to_ret.append(get_fc_object(obj.name).Label) return to_ret
def refresh(self) -> None: """ Deletes everything and refreshes contents with the current simulation objects. """ self.clear_table_contents() num_objects_in_simulation: int = Case.the( ).number_of_objects_in_simulation() self.set_table_row_count(num_objects_in_simulation) current_row = 0 for sim_object in Case.the().objects: if sim_object.name == CASE_LIMITS_OBJ_NAME: continue target_widget = ObjectOrderWidget(index=current_row, object_mk=sim_object.obj_mk, mktype=sim_object.type, object_name=get_fc_object( sim_object.name).Label, parent=self) if current_row == 0: target_widget.disable_up() if current_row == num_objects_in_simulation - 1: target_widget.disable_down() self.set_table_cell_widget(current_row, 0, target_widget) current_row += 1
def supports_changing_type(self) -> bool: """ Returns whether this object supports changing types or not. """ fc_object = get_fc_object(self.name) return fc_object.TypeId in SUPPORTED_TYPES or \ "part" in fc_object.TypeId.lower() or \ "mesh" in fc_object.TypeId.lower() or \ (fc_object.TypeId == FreeCADObjectType.FOLDER and "fillbox" in fc_object.Name.lower())
def get_objects_info(self) -> str: """ Returns an HTML string with information about the objects in the case. """ each_object_info: list = list() obj: SimulationObject = None for obj in Case.the().objects: if obj.name == CASE_LIMITS_OBJ_NAME: continue is_floating_text: str = "Yes" if Case.the( ).get_mk_based_properties(obj.type, obj.obj_mk).float_property else "No" has_initials_text: str = "Yes" if Case.the( ).get_mk_based_properties(obj.type, obj.obj_mk).initials else "No" to_append = "<li>" to_append += "<b>{}</b> ({})<br>".format( get_fc_object(obj.name).Label, obj.name) to_append += "Type: {type} (MK{type}: <b>{mk}</b> ; MK: <b>{real_mk}</b>)<br/>".format( type=str(obj.type).capitalize(), mk=str(obj.obj_mk), real_mk=str(obj.obj_mk + MKFLUID_OFFSET if obj.type == ObjectType.FLUID else obj.obj_mk + MKFLUID_LIMIT)) to_append += "Fill mode: {}<br/>".format( str(obj.fillmode).capitalize()) to_append += "Floating: {}<br/>".format(is_floating_text) to_append += "Initials: {}</li><br/>".format(has_initials_text) to_append += "</li>" each_object_info.append(to_append) return "<ul>{}</ul>".format( "".join(each_object_info) if each_object_info else "No objects were added to the case.")
def on_tree_item_selection_change(properties_widget, designsphysics_dock): """ Refreshes relevant parts of DesignsPHysics under an important change event. """ debug("Syncronizing FreeCAD data structures with DesignSPHysics") selection = FreeCADGui.Selection.getSelection() properties_widget.set_add_button_enabled(True) if selection: if len(selection) > 1: # Multiple objects selected properties_widget.configure_to_add_multiple_selection() else: # One object selected if selection[0].Name == "Case_Limits" or "_internal_" in selection[ 0].Name: properties_widget.configure_to_no_selection() elif Case.the().is_damping_bound_to_object(selection[0].Name): properties_widget.configure_to_damping_selection() elif Case.the().is_object_in_simulation(selection[0].Name): # Show properties on table properties_widget.configure_to_regular_selection() properties_widget.adapt_to_simulation_object( Case.the().get_simulation_object(selection[0].Name), selection[0]) else: if not selection[0].InList: # Show button to add to simulation properties_widget.configure_to_add_single_selection() else: properties_widget.configure_to_incompatible_object() else: properties_widget.configure_to_no_selection() # Delete invalid or already deleted (in FreeCAD) objects for object_name in Case.the().get_all_simulation_object_names(): fc_object = get_fc_object(object_name) if not fc_object or fc_object.InList: Case.the().remove_object(object_name) for damping_to_delete in list( filter(lambda x: not get_fc_object(x), Case.the().damping_zones)): Case.the().remove_damping_zone(damping_to_delete) # Update dsph objects list designsphysics_dock.refresh_object_list() properties_widget.fit_size()
def on_2d_toggle(self): """ Handles Toggle 3D/2D Button. Changes the Case Limits object accordingly. """ if not valid_document_environment(): error("Not a valid case environment") return fc_object = get_fc_object(CASE_LIMITS_OBJ_NAME) if Case.the().mode3d: # 3D to 2D Case.the().info.last_3d_width = fc_object.Width.Value config_dialog = Mode2DConfigDialog(fc_object.Placement.Base.y, parent=get_fc_main_window()) if config_dialog.exit_status == QtGui.QDialog.Rejected: return fc_object.Placement.Base.y = float(config_dialog.stored_y_value) fc_object.Label = CASE_LIMITS_2D_LABEL Case.the().mode3d = not Case.the().mode3d else: # 2D to 3D Case.the().mode3d = not Case.the().mode3d fc_object.Width = Case.the().info.last_3d_width if Case.the( ).info.last_3d_width > 0.0 else fc_object.Length fc_object.Label = CASE_LIMITS_3D_LABEL
def save_case(save_name: str, case: "Case") -> None: """ Saves a case to disk in the given path. """ project_name = save_name.split("/")[-1] case.path = save_name case.name = project_name if not path.exists(save_name): makedirs(save_name) if not path.exists("{}/{}_out".format(save_name, project_name)): makedirs("{}/{}_out".format(save_name, project_name)) # Export all complex objects to STL for obj in case.get_all_complex_objects(): Mesh.export([get_fc_object(obj.name)], "{}/{}.stl".format(save_name, obj.name)) # FIXME: Too many branches # Copy files from movements and change its paths to be inside the project. for _, mkproperties in case.mkbasedproperties.items(): for movement in mkproperties.movements: if isinstance(movement, SpecialMovement): if isinstance(movement.generator, (FileGen, RotationFileGen)): filename = movement.generator.filename debug("Copying {} to {}".format(filename, save_name)) # Change directory to de case one, so if file path is already relative it copies it to the # out folder chdir(save_name)
def supports_motion(self) -> bool: """ Returns whether this object supports motion or not. """ fc_object = get_fc_object(self.name) return fc_object.TypeId in SUPPORTED_TYPES \ or FreeCADObjectType.CUSTOM_MESH in str(fc_object.TypeId) or \ (fc_object.TypeId == FreeCADObjectType.FOLDER and "fillbox" in fc_object.Name.lower())
def supports_floating(self) -> bool: """ Returns whether this object supports floating or not. """ fc_object = get_fc_object(self.name) return fc_object.TypeId in SUPPORTED_TYPES or \ (fc_object.TypeId == FreeCADObjectType.FOLDER and "fillbox" in fc_object.Name.lower())
def supports_changing_fillmode(self) -> bool: """ Returns whether this object supports changing its fillmode or not. """ fc_object = get_fc_object(self.name) return fc_object.TypeId in SUPPORTED_TYPES
def save_case(save_name: str, case: "Case") -> None: """ Saves a case to disk in the given path. """ project_name = save_name.split("/")[-1] case.path = save_name case.name = project_name if not path.exists(save_name): makedirs(save_name) if not path.exists("{}/{}_out".format(save_name, project_name)): makedirs("{}/{}_out".format(save_name, project_name)) # Export all complex objects to STL for obj in case.get_all_complex_objects(): Mesh.export([get_fc_object(obj.name)], "{}/{}.stl".format(save_name, obj.name)) # FIXME: Too many branches # Copy files from movements and change its paths to be inside the project. for _, mkproperties in case.mkbasedproperties.items(): for movement in mkproperties.movements: if isinstance(movement, SpecialMovement): if isinstance(movement.generator, (FileGen, RotationFileGen)): filename = movement.generator.filename debug("Copying {} to {}".format(filename, save_name)) # Change directory to de case one, so if file path is already relative it copies it to the # out folder chdir(save_name)
def __init__(self, parent=None): super().__init__(parent=parent) # Reference to avoid calling instance every time self.case = Case.the() # Creates a dialog self.setWindowTitle("Chrono configuration") self.setMinimumWidth(500) self.setMinimumHeight(600) self.main_layout = QtGui.QVBoxLayout() # Option for saves CSV with data exchange for each time interval self.csv_option_layout = QtGui.QHBoxLayout() self.csv_intervals_checkbox = QtGui.QCheckBox() self.csv_intervals_checkbox.setCheckState(QtCore.Qt.Checked if self.case.chrono.csv_intervals.enabled else QtCore.Qt.Unchecked) self.csv_intervals_checkbox.toggled.connect(self.on_csv_intervals_check) self.csv_intervals_option = QtGui.QLabel(__("CSV intervals:")) self.csv_intervals_line_edit = QtGui.QLineEdit(str(self.case.chrono.csv_intervals.value)) self.csv_option_layout.addWidget(self.csv_intervals_checkbox) self.csv_option_layout.addWidget(self.csv_intervals_option) self.csv_option_layout.addWidget(self.csv_intervals_line_edit) # Option for define scale used to create the initial scheme of Chrono objects self.scale_scheme_option_layout = QtGui.QHBoxLayout() self.scale_scheme_checkbox = QtGui.QCheckBox() self.scale_scheme_checkbox.setCheckState(QtCore.Qt.Checked if self.case.chrono.scale_scheme.enabled else QtCore.Qt.Unchecked) self.scale_scheme_checkbox.toggled.connect(self.on_scale_scheme_checkbox) self.scale_scheme_option = QtGui.QLabel(__("Scale for scheme:")) self.scale_scheme_line_edit = QtGui.QLineEdit(str(self.case.chrono.scale_scheme.value)) self.scale_scheme_option_layout.addWidget(self.scale_scheme_checkbox) self.scale_scheme_option_layout.addWidget(self.scale_scheme_option) self.scale_scheme_option_layout.addWidget(self.scale_scheme_line_edit) # Option for allow collision overlap according Dp self.collisiondp_option_layout = QtGui.QHBoxLayout() self.collisiondp_checkbox = QtGui.QCheckBox() if self.case.chrono.collisiondp.enabled: self.collisiondp_checkbox.setCheckState(QtCore.Qt.Checked) else: self.collisiondp_checkbox.setCheckState(QtCore.Qt.Unchecked) self.collisiondp_checkbox.toggled.connect(self.on_collisiondp_checkbox) self.collisiondp_option = QtGui.QLabel(__("Collision Dp:")) self.collisiondp_line_edit = QtGui.QLineEdit(str(self.case.chrono.collisiondp.value)) self.collisiondp_option_layout.addWidget(self.collisiondp_checkbox) self.collisiondp_option_layout.addWidget(self.collisiondp_option) self.collisiondp_option_layout.addWidget(self.collisiondp_line_edit) # Create the list for chrono objects self.main_chrono = QtGui.QGroupBox("Chrono objects") self.main_chrono.setMinimumHeight(150) self.chrono_layout = QtGui.QVBoxLayout() self.objectlist_table = QtGui.QTableWidget(0, 1) self.objectlist_table.setObjectName("Chrono objects table") self.objectlist_table.verticalHeader().setVisible(False) self.objectlist_table.horizontalHeader().setVisible(False) self.objectlist_table.horizontalHeader().setResizeMode(0, QtGui.QHeaderView.Stretch) self.objectlist_table.setEnabled(True) # Create the necessary spaces in the list self.count = 0 self.objectlist_table.setRowCount(len(self.case.get_all_bound_objects())) self.current_row = 0 self.objects_with_parent = list() self.is_floating = "" self.chrono_object_options_widgets = list() # Select the objects that are going to be listed for sim_object in self.case.get_all_bound_objects(): freecad_object = get_fc_object(sim_object.name) self.is_floating = "bodyfloating" if self.case.get_mk_based_properties(sim_object.type, sim_object.obj_mk).float_property else "bodyfixed" # Collects the information of the object self.target_widget = ChronoObjectCheckOptions( key=sim_object.name, object_mk=sim_object.obj_mk, mktype=sim_object.type, object_name=freecad_object.Label, is_floating=self.is_floating, parent=get_fc_main_window() ) # Updates the state of list options if self.case.chrono.objects: for elem in self.case.chrono.objects: if elem.id == sim_object.name: self.target_widget.object_check.setCheckState(QtCore.Qt.Checked) self.target_widget.geometry_check.setCheckState(QtCore.Qt.Checked if elem.modelnormal_enabled else QtCore.Qt.Unchecked) self.target_widget.modelnormal_input.setCurrentIndex({ChronoModelNormalType.ORIGINAL: 0, ChronoModelNormalType.INVERT: 1, ChronoModelNormalType.TWOFACE: 2}[elem.modelnormal_type]) # Saves the information about object for being process later self.chrono_object_options_widgets.append(self.target_widget) # Shows the object in table self.objectlist_table.setCellWidget(self.current_row, 0, self.target_widget) self.current_row += 1 # Add table to the layout self.chrono_layout.addWidget(self.objectlist_table) # Creates 2 main buttons self.ok_button = QtGui.QPushButton("Save") self.cancel_button = QtGui.QPushButton("Cancel") self.button_layout = QtGui.QHBoxLayout() self.button_layout.addStretch(1) self.ok_button.clicked.connect(self.on_ok) self.cancel_button.clicked.connect(self.on_cancel) # Link Linearspring option list self.main_link_linearspring = QtGui.QGroupBox("Linearspring") self.link_linearspring_layout = QtGui.QVBoxLayout() self.link_linearspring_layout2 = QtGui.QVBoxLayout() self.link_linearspring_button_layout = QtGui.QHBoxLayout() self.button_link_linearspring = QtGui.QPushButton("Add") self.link_linearspring_button_layout.addStretch(1) self.link_linearspring_button_layout.addWidget(self.button_link_linearspring) self.button_link_linearspring.clicked.connect(self.on_link_linearspring_add) self.link_linearspring_layout.addLayout(self.link_linearspring_button_layout) self.link_linearspring_layout.addLayout(self.link_linearspring_layout2) self.main_link_linearspring.setLayout(self.link_linearspring_layout) self.refresh_link_linearspring() # Link hinge option list self.main_link_hinge = QtGui.QGroupBox("Hinge") self.link_hinge_layout = QtGui.QVBoxLayout() self.link_hinge_layout2 = QtGui.QVBoxLayout() self.link_hinge_button_layout = QtGui.QHBoxLayout() self.button_link_hinge = QtGui.QPushButton("Add") self.link_hinge_button_layout.addStretch(1) self.link_hinge_button_layout.addWidget(self.button_link_hinge) self.button_link_hinge.clicked.connect(self.on_link_hinge_add) self.link_hinge_layout.addLayout(self.link_hinge_button_layout) self.link_hinge_layout.addLayout(self.link_hinge_layout2) self.main_link_hinge.setLayout(self.link_hinge_layout) self.refresh_link_hinge() # Link Spheric option list self.main_link_spheric = QtGui.QGroupBox("Spheric") self.link_spheric_layout = QtGui.QVBoxLayout() self.link_spheric_layout2 = QtGui.QVBoxLayout() self.link_spheric_button_layout = QtGui.QHBoxLayout() self.button_link_spheric = QtGui.QPushButton("Add") self.link_spheric_button_layout.addStretch(1) self.link_spheric_button_layout.addWidget(self.button_link_spheric) self.button_link_spheric.clicked.connect(self.on_link_spheric_add) self.link_spheric_layout.addLayout(self.link_spheric_button_layout) self.link_spheric_layout.addLayout(self.link_spheric_layout2) self.main_link_spheric.setLayout(self.link_spheric_layout) self.refresh_link_spheric() # Link Pointline option list self.main_link_pointline = QtGui.QGroupBox("Pointline") self.link_pointline_layout = QtGui.QVBoxLayout() self.link_pointline_layout2 = QtGui.QVBoxLayout() self.link_pointline_button_layout = QtGui.QHBoxLayout() self.button_link_pointline = QtGui.QPushButton("Add") self.link_pointline_button_layout.addStretch(1) self.link_pointline_button_layout.addWidget(self.button_link_pointline) self.button_link_pointline.clicked.connect(self.on_link_pointline_add) self.link_pointline_layout.addLayout(self.link_pointline_button_layout) self.link_pointline_layout.addLayout(self.link_pointline_layout2) self.main_link_pointline.setLayout(self.link_pointline_layout) self.refresh_link_pointline() # Adds all layouts to main self.main_layout.addLayout(self.csv_option_layout) self.main_layout.addLayout(self.scale_scheme_option_layout) self.main_layout.addLayout(self.collisiondp_option_layout) self.main_chrono.setLayout(self.chrono_layout) self.main_layout.addWidget(self.main_chrono) self.main_layout.addWidget(self.main_link_linearspring) self.main_layout.addWidget(self.main_link_hinge) self.main_layout.addWidget(self.main_link_spheric) self.main_layout.addWidget(self.main_link_pointline) self.button_layout.addWidget(self.ok_button) self.button_layout.addWidget(self.cancel_button) # Adds scroll area self.main_layout_dialog = QtGui.QVBoxLayout() self.main_layout_scroll = QtGui.QScrollArea() self.main_layout_scroll.setMinimumWidth(400) self.main_layout_scroll.setWidgetResizable(True) self.main_layout_scroll_widget = QtGui.QWidget() self.main_layout_scroll_widget.setMinimumWidth(400) self.main_layout_scroll_widget.setLayout(self.main_layout) self.main_layout_scroll.setWidget(self.main_layout_scroll_widget) self.main_layout_scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.main_layout_dialog.addWidget(self.main_layout_scroll) self.main_layout_dialog.addLayout(self.button_layout) self.on_scale_scheme_checkbox() self.on_csv_intervals_check() self.on_collisiondp_checkbox() self.setLayout(self.main_layout_dialog) self.ok_button.setFocus() self.exec_()
def save_case(save_name: str, case: "Case") -> None: """ Saves a case to disk in the given path. """ project_name = save_name.split("/")[-1] case.path = save_name case.name = project_name if not path.exists(save_name): makedirs(save_name) if not path.exists("{}/{}_out".format(save_name, project_name)): makedirs("{}/{}_out".format(save_name, project_name)) # Export all complex objects to STL for obj in case.get_all_complex_objects(): Mesh.export([get_fc_object(obj.name)], "{}/{}.stl".format(save_name, obj.name)) # FIXME: Too many branches # Copy files from movements and change its paths to be inside the project. for _, mkproperties in case.mkbasedproperties.items(): for movement in mkproperties.movements: if isinstance(movement, SpecialMovement): if isinstance(movement.generator, (FileGen, RotationFileGen)): filename = movement.generator.filename debug("Copying {} to {}".format(filename, save_name)) # Change directory to de case one, so if file path is already relative it copies it to the # out folder chdir(save_name)