FreeCADでFEMワークベンチを使っていると,モデル上で板厚や材質を確認することが難しくて困ることがあります(; ・`д・´)
これは板厚や材質といった情報がAnalysisコンテナ内で保持されるため,ShapeやFaceと直接紐付けられていないということに起因します
そこで今回はFreeCADモデルを板厚に応じて着色するPythonスクリプトを説明します
前提条件として
FreeCADのサーフェースモデルを対象とします
板厚はElementGeometry2DのShell plate thicknessの値を参照します
Referencesを指定していないElementGeometry2DをDefault値として扱います
Matplotlibのカラーマップを使用します (Choosing Colormaps in Matplotlib — Matplotlib 3.10.1 documentation)
# Color-mapping for surface-model according to plate's thickness import FreeCAD, FreeCADGui import re import matplotlib.pyplot as plt TYPEID_EG2D = "Fem::FeaturePython" # TypeId of ElementGeometry2D MIN_THICKNESS = 6 # Min default value of thickness (mm) MAX_THICKNESS = 30 # Max default value of thickness (mm) UNDEFINED_COLOR = (0, 0, 0) # Black color as undefined thickness NAME_CMAP = 'rainbow' # https://matplotlib.org/stable/users/explain/colors/colormaps.html def extract_number(s: str) -> float: """ Extract a numerical value from a string using regular expression """ match = re.search(r"[-+]?\d*\.?\d+", s) return float(match.group()) if match else 0.0 def get_color(value: float): """ Get colors using a colormap of matplotlib """ cmap = plt.get_cmap(NAME_CMAP) norm = plt.Normalize(vmin=min_thickness, vmax=max_thickness) return cmap(norm(value))[:3] def gen_colorbar(): """ Generate colorbar-legend using a colormap of matplotlib """ cmap = plt.get_cmap(NAME_CMAP) norm = plt.Normalize(vmin=min_thickness, vmax=max_thickness) fig, ax = plt.subplots(figsize=(2, 6)) # Width, height in inches. fig.subplots_adjust(left=0.4, right=0.5) # Size adjustment for borders cb = plt.colorbar(plt.cm.ScalarMappable(norm, cmap), cax=ax) cb.set_label("Plate thickness [mm]") # Label plt.show() return # Make a dictionaly of plate thicknesses dict_thickness = {} default_thickness = 0 objects = FreeCAD.ActiveDocument.Objects for obj in objects: # Get thickness from ElementGeometry2D if obj.TypeId == TYPEID_EG2D: if(len(obj.References) == 0): # Default of thickness default_thickness = extract_number(str(obj.Thickness)) if obj.Thickness else 0 else: # Define thickness from References faces = obj.References[0][1] for face in faces: dict_thickness[face] = extract_number(str(obj.Thickness)) # Add default thickness to dict_thickness if default_thickness != 0: dict_thickness["default"] = default_thickness if not dict_thickness: FreeCAD.Console.PrintError("-------- No plate thickness defined! --------") else: # Set min/max thickness from dict_thickness min_thickness = min(dict_thickness.values(), default=MIN_THICKNESS) max_thickness = max(dict_thickness.values(), default=MAX_THICKNESS) # Get object from BooleanFragments obj_name = "BooleanFragments" obj = FreeCAD.ActiveDocument.getObject(obj_name) if obj is None: print(f"Error: '{obj_name}' not found.") else: num_faces = len(obj.Shape.Faces) # Make color-list from each plate's thickness colors = [] undefined_faces = [] for i, face in enumerate(obj.Shape.Faces, start=1): face_name = f"Face{i}" if face_name in dict_thickness: thickness = dict_thickness[face_name] colors.append(get_color(thickness)) elif default_thickness != 0: colors.append(get_color(default_thickness)) else: colors.append(UNDEFINED_COLOR) undefined_faces.append(face_name) obj.ViewObject.DiffuseColor = colors FreeCADGui.updateGui() FreeCAD.Console.PrintMessage(f"Applied thickness-based colors to {num_faces} faces. ({min_thickness}/{max_thickness})\n") if default_thickness == 0: # Default thickness was not defined if undefined_faces: FreeCAD.Console.PrintError("Some faces have no specified thickness. They were colored black!\n") else: FreeCAD.Console.PrintMessage("No default thickness was defined, but all faces had a specified thickness.\n") # Generate colorbar-legend gen_colorbar()
【使い方】
・対象となるサーフェースモデルを表示した状態で本スクリプトを実行してください
・NAME_CMAPに使用したいMatplotlibのカラーマップを指定してください(サンプルコードでは'rainbow')
・正常に実行されればサーフェースモデルが着色され,凡例が表示されます
・Default値が設定されていない場合,板厚の定義がされていないFaceはカラーマップに関係なく黒色で着色されます
FreeCADで具体的な形状(複数のH型鋼)に適用した例を示します