From 7bbfa68698002591d103cb15b4c02b4777e5045a Mon Sep 17 00:00:00 2001 From: marcuspollio Date: Sun, 23 Mar 2025 23:30:31 +0100 Subject: [PATCH] BIM: cleanup imports in importers --- src/Mod/BIM/importers/exportIFC.py | 29 ++++++------ src/Mod/BIM/importers/exportIFCHelper.py | 7 ++- src/Mod/BIM/importers/import3DS.py | 12 +++-- src/Mod/BIM/importers/importDAE.py | 25 +++++----- src/Mod/BIM/importers/importGBXML.py | 13 ++++-- src/Mod/BIM/importers/importIFC.py | 26 ++++++----- src/Mod/BIM/importers/importIFCHelper.py | 2 +- src/Mod/BIM/importers/importIFClegacy.py | 35 +++++++++----- src/Mod/BIM/importers/importIFCmulticore.py | 11 +++-- src/Mod/BIM/importers/importOBJ.py | 20 ++++---- src/Mod/BIM/importers/importSH3D.py | 15 +++--- src/Mod/BIM/importers/importSH3DHelper.py | 51 +++++++++++---------- src/Mod/BIM/importers/importSHP.py | 6 +-- src/Mod/BIM/importers/importWebGL.py | 32 ++++++------- 14 files changed, 157 insertions(+), 127 deletions(-) diff --git a/src/Mod/BIM/importers/exportIFC.py b/src/Mod/BIM/importers/exportIFC.py index fcec025928..55c119c692 100644 --- a/src/Mod/BIM/importers/exportIFC.py +++ b/src/Mod/BIM/importers/exportIFC.py @@ -18,41 +18,44 @@ # * USA * # * * # *************************************************************************** -"""Provide the exporter for IFC files used above all in Arch and BIM. -Internally it uses IfcOpenShell, which must be installed before using. -""" +__title__ = "FreeCAD IFC export" +__author__ = ("Yorik van Havre", "Jonathan Wiedemann", "Bernd Hahnebach") +__url__ = "https://www.freecad.org" + ## @package exportIFC # \ingroup ARCH # \brief IFC file format exporter # # This module provides tools to export IFC files. +"""Provide the exporter for IFC files used above all in Arch and BIM. + +Internally it uses IfcOpenShell, which must be installed before using. +""" + +import math import os import time import tempfile -import math from builtins import open as pyopen import FreeCAD -import Part -import Draft +import FreeCADGui import Arch +import Draft import DraftVecUtils +import Part import ArchIFCSchema -from importers import exportIFCHelper -from importers import exportIFCStructuralTools from DraftGeomUtils import vec -from importers.importIFCHelper import dd2dms from draftutils import params from draftutils.messages import _msg, _err -import FreeCADGui +from importers import exportIFCHelper +from importers import exportIFCStructuralTools +from importers.importIFCHelper import dd2dms -__title__ = "FreeCAD IFC export" -__author__ = ("Yorik van Havre", "Jonathan Wiedemann", "Bernd Hahnebach") -__url__ = "https://www.freecad.org" PARAMS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/BIM") diff --git a/src/Mod/BIM/importers/exportIFCHelper.py b/src/Mod/BIM/importers/exportIFCHelper.py index 8e153de3af..373243965f 100644 --- a/src/Mod/BIM/importers/exportIFCHelper.py +++ b/src/Mod/BIM/importers/exportIFCHelper.py @@ -22,12 +22,15 @@ import json import math -import FreeCAD -# import Draft import ifcopenshell from ifcopenshell import guid + +import FreeCAD +# import Draft + from draftutils import params + def getObjectsOfIfcType(objects, ifcType): results = [] for object in objects: diff --git a/src/Mod/BIM/importers/import3DS.py b/src/Mod/BIM/importers/import3DS.py index 0027c25c1b..c00c7f3902 100644 --- a/src/Mod/BIM/importers/import3DS.py +++ b/src/Mod/BIM/importers/import3DS.py @@ -19,20 +19,24 @@ #* * #*************************************************************************** -import os,FreeCAD,Mesh - __title__ = "FreeCAD 3DS importer" __author__ = "Yorik van Havre" __url__ = "https://www.freecad.org" -DEBUG = True - ## @package import3DS # \ingroup ARCH # \brief 3DS file format importer # # This module provides tools to import 3DS files. +import os + +import FreeCAD +import Mesh + +DEBUG = True + + def check3DS(): "checks if collada if available" global dom3ds diff --git a/src/Mod/BIM/importers/importDAE.py b/src/Mod/BIM/importers/importDAE.py index 9a3797dae4..a2005f5ee0 100644 --- a/src/Mod/BIM/importers/importDAE.py +++ b/src/Mod/BIM/importers/importDAE.py @@ -19,18 +19,29 @@ #* * #*************************************************************************** +__title__ = "FreeCAD Collada importer" +__author__ = "Yorik van Havre" +__url__ = "https://www.freecad.org" + +## @package importDAE +# \ingroup ARCH +# \brief DAE (Collada) file format importer and exporter +# +# This module provides tools to import and export Collada (.dae) files. + import os from typing import Optional import numpy as np -from draftutils import params +import FreeCAD import Arch import Draft -import FreeCAD import Mesh import MeshPart +from draftutils import params + if FreeCAD.GuiUp: from draftutils.translate import translate else: @@ -39,16 +50,6 @@ else: return text # \endcond -## @package importDAE -# \ingroup ARCH -# \brief DAE (Collada) file format importer and exporter -# -# This module provides tools to import and export Collada (.dae) files. - -__title__ = "FreeCAD Collada importer" -__author__ = "Yorik van Havre" -__url__ = "https://www.freecad.org" - DEBUG = True diff --git a/src/Mod/BIM/importers/importGBXML.py b/src/Mod/BIM/importers/importGBXML.py index 5cc0f5ea18..e8f6ce5f1c 100644 --- a/src/Mod/BIM/importers/importGBXML.py +++ b/src/Mod/BIM/importers/importGBXML.py @@ -23,6 +23,14 @@ __title__ = "FreeCAD GbXml exporter" __author__ = "Yorik van Havre" __url__ = "https://www.freecad.org" +## @package importGBXML +# \ingroup ARCH +# \brief GBXML file format exporter +# +# This module provides tools to export GBXML files. + +from builtins import open as pyopen + import FreeCAD import Draft @@ -34,11 +42,6 @@ else: return txt # \endcond -## @package importGBXML -# \ingroup ARCH -# \brief GBXML file format exporter -# -# This module provides tools to export GBXML files. def export(objectslist,filename): diff --git a/src/Mod/BIM/importers/importIFC.py b/src/Mod/BIM/importers/importIFC.py index 8689280076..dcfbda5249 100644 --- a/src/Mod/BIM/importers/importIFC.py +++ b/src/Mod/BIM/importers/importIFC.py @@ -18,40 +18,42 @@ # * USA * # * * # *************************************************************************** -"""Provide the importer for IFC files used above all in Arch and BIM. -Internally it uses IfcOpenShell, which must be installed before using. -""" +__title__ = "FreeCAD IFC importer - Enhanced IfcOpenShell-only version" +__author__ = ("Yorik van Havre", "Jonathan Wiedemann", "Bernd Hahnebach") +__url__ = "https://www.freecad.org" + ## @package importIFC # \ingroup ARCH # \brief IFC file format importer # # This module provides tools to import IFC files. +"""Provide the importer for IFC files used above all in Arch and BIM. + +Internally it uses IfcOpenShell, which must be installed before using. +""" import os import math import time import FreeCAD -import Part -import Draft import Arch -import DraftVecUtils import ArchIFCSchema -from importers import importIFCHelper -from importers import importIFCmulticore +import Draft +import DraftVecUtils +import Part from draftutils import params from draftutils.messages import _msg, _err +from importers import importIFCHelper +from importers import importIFCmulticore + if FreeCAD.GuiUp: import FreeCADGui as Gui -__title__ = "FreeCAD IFC importer - Enhanced IfcOpenShell-only version" -__author__ = ("Yorik van Havre", "Jonathan Wiedemann", "Bernd Hahnebach") -__url__ = "https://www.freecad.org" - DEBUG = False # Set to True to see debug messages. Otherwise, totally silent ZOOMOUT = True # Set to False to not zoom extents after import diff --git a/src/Mod/BIM/importers/importIFCHelper.py b/src/Mod/BIM/importers/importIFCHelper.py index d140cab8e7..3563a42a05 100644 --- a/src/Mod/BIM/importers/importIFCHelper.py +++ b/src/Mod/BIM/importers/importIFCHelper.py @@ -18,8 +18,8 @@ # * USA * # * * # *************************************************************************** + """Helper functions that are used by IFC importer and exporter.""" -import sys import math import FreeCAD diff --git a/src/Mod/BIM/importers/importIFClegacy.py b/src/Mod/BIM/importers/importIFClegacy.py index fbbf9a8f07..0881b4a28c 100644 --- a/src/Mod/BIM/importers/importIFClegacy.py +++ b/src/Mod/BIM/importers/importIFClegacy.py @@ -25,16 +25,27 @@ # # ############################################################################ - -import FreeCAD, Arch, Draft, os, sys, time, Part, DraftVecUtils, uuid, math, re -from builtins import open as pyopen -from draftutils import params -from draftutils.translate import translate - __title__="FreeCAD IFC importer" __author__ = "Yorik van Havre" __url__ = "https://www.freecad.org" +import math +import os +import re +import time +import uuid + +from builtins import open as pyopen + +import FreeCAD +import Arch +import Draft +import DraftVecUtils +import Part + +from draftutils import params +from draftutils.translate import translate + # config subtractiveTypes = ["IfcOpeningElement"] # elements that must be subtracted from their parents SCHEMA = "http://www.steptools.com/support/stdev_docs/ifcbim/ifc4.exp" # only for internal parser @@ -937,7 +948,8 @@ def export(exportList,filename): have IFC export capabilities. IFC export currently requires an experimental version of IfcOpenShell available from https://github.com/aothms/IfcOpenShell""") return - import Arch,Draft + import Draft + import Arch # creating base IFC project getConfig() @@ -1139,7 +1151,8 @@ def export(exportList,filename): ifc.write() if exporttxt: - import time, os + import os + import time txtstring = "List of objects exported by FreeCAD in file\n" txtstring += filename + "\n" txtstring += "On " + time.ctime() + "\n" @@ -1181,7 +1194,8 @@ def getTuples(data,scale=1,placement=None,normal=None,close=True): elif isinstance(data,Part.Shape): t = [] if len(data.Wires) == 1: - import Part,DraftGeomUtils + import Part + import DraftGeomUtils data = Part.Wire(Part.__sortEdges__(data.Wires[0].Edges)) verts = data.Vertexes try: @@ -1261,7 +1275,6 @@ def getIfcExtrusionData(obj,scale=1,nosubs=False): edges = Part.__sortEdges__(p.Edges) for e in edges: if isinstance(e.Curve,Part.Circle): - import math follow = True if last: if not DraftVecUtils.equals(last,e.Vertexes[0].Point): @@ -1779,7 +1792,7 @@ class IfcDocument: def explorer(filename,schema="IFC2X3_TC1.exp"): "returns a PySide dialog showing the contents of an IFC file" - from PySide import QtCore,QtGui + from PySide import QtGui ifc = IfcDocument(filename,schema) schema = IfcSchema(schema) tree = QtGui.QTreeWidget() diff --git a/src/Mod/BIM/importers/importIFCmulticore.py b/src/Mod/BIM/importers/importIFCmulticore.py index f54ee00e4d..1bc7e328c5 100644 --- a/src/Mod/BIM/importers/importIFCmulticore.py +++ b/src/Mod/BIM/importers/importIFCmulticore.py @@ -18,18 +18,21 @@ # * USA * # * * # *************************************************************************** + """FreeCAD IFC importer - Multicore version""" +import os import sys import time -import os import FreeCAD -import Draft import Arch -from importers import importIFCHelper -from FreeCAD import Base import ArchIFC +import Draft + +from FreeCAD import Base + +from importers import importIFCHelper # global dicts to store ifc object/freecad object relationships diff --git a/src/Mod/BIM/importers/importOBJ.py b/src/Mod/BIM/importers/importOBJ.py index 8533ad578a..24a8616322 100644 --- a/src/Mod/BIM/importers/importOBJ.py +++ b/src/Mod/BIM/importers/importOBJ.py @@ -19,9 +19,18 @@ #* * #*************************************************************************** -import os +## @package importOBJ +# \ingroup ARCH +# \brief OBJ file format exporter +# +# This module provides tools to import & export OBJ files. +# It is an alternative to the standard Mesh OBJ exporter +# and supports exporting faces with more than 3 vertices +# and supports object colors / materials + import codecs import ntpath +import os from builtins import open as pyopen import FreeCAD @@ -31,6 +40,7 @@ import DraftGeomUtils import Mesh import MeshPart import Part + from draftutils import params if FreeCAD.GuiUp: @@ -41,14 +51,6 @@ else: return text # \endcond -## @package importOBJ -# \ingroup ARCH -# \brief OBJ file format exporter -# -# This module provides tools to import & export OBJ files. -# It is an alternative to the standard Mesh OBJ exporter -# and supports exporting faces with more than 3 vertices -# and supports object colors / materials def findVert(aVertex,aList): "finds aVertex in aList, returns index" diff --git a/src/Mod/BIM/importers/importSH3D.py b/src/Mod/BIM/importers/importSH3D.py index 5a1cc189e5..defad26c08 100644 --- a/src/Mod/BIM/importers/importSH3D.py +++ b/src/Mod/BIM/importers/importSH3D.py @@ -23,20 +23,19 @@ __title__ = "FreeCAD SweetHome3D Importer" __author__ = "Yorik van Havre" __url__ = "https://www.freecad.org" -import os -import xml.sax -import zipfile - -import FreeCAD -from FreeCAD import Base - - ## @package importSH3D # \ingroup ARCH # \brief SH3D (SweetHome3D) file format importer # # This module provides tools to import SH3D files created from Sweet Home 3D. +import os +import zipfile + +import FreeCAD +from FreeCAD import Base + + DEBUG = True diff --git a/src/Mod/BIM/importers/importSH3DHelper.py b/src/Mod/BIM/importers/importSH3DHelper.py index 4198f563db..86a3cf6c2d 100644 --- a/src/Mod/BIM/importers/importSH3DHelper.py +++ b/src/Mod/BIM/importers/importSH3DHelper.py @@ -18,9 +18,10 @@ # * USA * # * * # *************************************************************************** + """Helper functions that are used by SH3D importer.""" + import itertools -import numpy as np import math import os import re @@ -29,6 +30,9 @@ import uuid import xml.etree.ElementTree as ET import zipfile +import numpy as np + +import FreeCAD as App import Arch import BOPTools.SplitFeatures import BOPTools.BOPFeatures @@ -43,8 +47,6 @@ import TechDraw from draftutils.messages import _err, _log, _msg, _wrn from draftutils.params import get_param_arch -import FreeCAD as App - if App.GuiUp: import FreeCADGui as Gui from draftutils.translate import translate @@ -1367,8 +1369,8 @@ class RoomHandler(BaseHandler): Returns: bool: True if at least one pair of edge intersect. - list(tuple): a list of tuple of v1, e1, v2, e2 where v1 is the - intersection on the first edge e1, and v2 is the intersection + list(tuple): a list of tuple of v1, e1, v2, e2 where v1 is the + intersection on the first edge e1, and v2 is the intersection on the second edge e2. """ for i in range(len(edges)): @@ -1380,7 +1382,7 @@ class RoomHandler(BaseHandler): continue for (v1, v2) in vectors: # Check that the intersections are not extremities - # If both v1 and v2 are extremities then the edges + # If both v1 and v2 are extremities then the edges # are connected which is not really a self-intersecting # situation. if v1 not in [v.Point for v in e1.Vertexes] or v2 not in [v.Point for v in e2.Vertexes]: @@ -1949,8 +1951,8 @@ class WallHandler(BaseHandler): if is_wall_straight: # In order to make sure that the edges are not self-intersecting - # create a convex hull and use these points instead. Maybe - # overkill for a 4 point wall, however not sure how to invert + # create a convex hull and use these points instead. Maybe + # overkill for a 4 point wall, however not sure how to invert # edges. points = list(map(lambda v: v.Point, face.Vertexes)) new_points = convex_hull(points) @@ -2247,7 +2249,7 @@ class DoorOrWindowHandler(BaseFurnitureHandler): # Note that we only move on the XY plane since we assume that # only the right and left face will be used for supporting the - # doorOrWndow. It might not be correct for roof windows and floor + # doorOrWndow. It might not be correct for roof windows and floor # windows... # The absolute coordinate of the corner of the doorOrWindow dow_abs_corner = dow_abs_center.add(App.Vector(-width/2, -depth/2, 0)) @@ -2264,7 +2266,7 @@ class DoorOrWindowHandler(BaseFurnitureHandler): is_opened = False wall_width = depth # Get all the walls hosting that doorOrWndow. - # + # # The main wall is used to determine the projection of the # doorOrWindow bounding_box, and thus the placement of the # resulting Arch element. The main wall is the one containing @@ -2289,7 +2291,7 @@ class DoorOrWindowHandler(BaseFurnitureHandler): # Get the left and right face for the main_wall (_, wall_lface, _, wall_rface) = self.get_faces(main_wall) - # The general process is as follow: + # The general process is as follow: # 1- Find the bounding box face whose normal is properly oriented # with respect to the doorOrWindow (+90º) # 2- Find the wall face with the same orientation. @@ -2329,7 +2331,7 @@ class DoorOrWindowHandler(BaseFurnitureHandler): self._debug_shape(wall_face, f"{label_prefix}-bb-projected-onto#{main_wall.Label}", MAGENTA) self._debug_shape(projected_face, f"{label_prefix}-bb-projection#{main_wall.Label}", RED) - # Determine the base vertex that I later use for the doorOrWindow + # Determine the base vertex that I later use for the doorOrWindow # placement base_vertex = self._get_base_vertex(main_wall, is_on_right, projected_face) @@ -2378,12 +2380,12 @@ class DoorOrWindowHandler(BaseFurnitureHandler): """Returns the wall(s) and slab(s) intersecting with the doorOrWindow bounding_box. - The main wall is the one that contains the doorOrWndow bounding_box - CenterOfGravity. Note that this will not work for open doorOrWindow - (i.e.whose bounding_box is a lot greater than the containing wall). + The main wall is the one that contains the doorOrWndow bounding_box + CenterOfGravity. Note that this will not work for open doorOrWindow + (i.e.whose bounding_box is a lot greater than the containing wall). The _create_door, has a mitigation process for that case. - The main_wall is used to get the face on which to project the + The main_wall is used to get the face on which to project the doorOrWindows bounding_box, and from there the placement of the element on the wall's face. @@ -2391,7 +2393,7 @@ class DoorOrWindowHandler(BaseFurnitureHandler): - find out whether the doorOrWindow span several floors, if so add all the walls (and slab) for that floor to the list of elements to check. - - once the list of elements to check is complete we check if the + - once the list of elements to check is complete we check if the doorOrWindow bounding_box has a volume in common with the wall. Args: @@ -2401,8 +2403,8 @@ class DoorOrWindowHandler(BaseFurnitureHandler): Returns: tuple(Arch::Wall, list(Arch::Wall)): a tuple of the main wall (if - any could be found and a list of any other Arch element that - might be host of that + any could be found and a list of any other Arch element that + might be host of that """ relevant_walls = [*self.importer.get_walls(floor)] # First find out which floor the window might be have an impact on. @@ -2453,7 +2455,7 @@ class DoorOrWindowHandler(BaseFurnitureHandler): """ debug_geometry = self.importer.preferences["DEBUG_GEOMETRY"] # Note that the 'angle' refers to the angle of the face, not its normal. - # we therefore add a '+90º' in SH3D coordinate (i.e. -90º in FC + # we therefore add a '+90º' in SH3D coordinate (i.e. -90º in FC # coordinate). # XXX: Can it be speed up by assuming that left and right are always # Face2 and Face4??? @@ -2474,7 +2476,7 @@ class DoorOrWindowHandler(BaseFurnitureHandler): """Return the base vertex used to place a doorOrWindow. Returns the vertex of the projected_face that serves as the - base for the Placement when creating the doorOrWindow. It is + base for the Placement when creating the doorOrWindow. It is the lowest vertex and closest to the wall reference point. The wall reference point depends on whether we are on the right or left side of the wall. @@ -2618,7 +2620,7 @@ class FurnitureHandler(BaseFurnitureHandler): mesh_transform.scale(-1, 1, 1) # Mirror along X if debug_geometry: self._debug_mesh(mesh, f"{name}-mirrored", mesh_transform) - # We add an initial 90º in order for a yaw-pitch-roll-rotation free + # We add an initial 90º in order for a yaw-pitch-roll-rotation free # model to appear properly in FC mesh_transform.rotateX(math.pi/2) if debug_geometry: self._debug_mesh(mesh, f"{name}-x90", mesh_transform) @@ -2636,7 +2638,7 @@ class FurnitureHandler(BaseFurnitureHandler): z_scale = height / normilized_bb.ZLength mesh_transform.scale(x_scale, y_scale, z_scale) - if debug_geometry: + if debug_geometry: model_size = App.Vector(model_bb.XLength, model_bb.YLength, model_bb.ZLength) normalized_size = App.Vector(normilized_bb.XLength, normilized_bb.YLength, normilized_bb.ZLength) final_size = App.Vector(width, depth, height) @@ -2645,7 +2647,7 @@ class FurnitureHandler(BaseFurnitureHandler): self._debug_mesh(mesh, f"{name}-scaled", mesh_transform, MAGENTA) # At that point the mesh has the proper scale. We determine the placement. - # In order to do that, we need to apply the different rotation (ypr) and + # In order to do that, we need to apply the different rotation (ypr) and # also the translation from the origin to the final point. if pitch != 0: r_pitch = App.Rotation(X_NORM, Radian=-pitch) @@ -3011,4 +3013,3 @@ def convex_hull(points, tol=1e-6): # point_coords = np.array([[p.x, p.y] for p in points]) # new_points = [points[i] for i in scipy.spatial.ConvexHull(point_coords).vertices] # return new_points[0] - diff --git a/src/Mod/BIM/importers/importSHP.py b/src/Mod/BIM/importers/importSHP.py index 1ead995ccf..09efb2c906 100644 --- a/src/Mod/BIM/importers/importSHP.py +++ b/src/Mod/BIM/importers/importSHP.py @@ -26,6 +26,7 @@ from builtins import open as pyopen import FreeCAD translate = FreeCAD.Qt.translate + def open(filename): """opens a SHP/SHX/DBF file in a new FreeCAD document""" @@ -144,11 +145,6 @@ def checkShapeFileLibrary(): f = pyopen(fp,"wb") f.write(b) f.close() - try: - import shapefile - except Exception: - FreeCAD.Console.PrintError(translate("Arch","Could not download shapefile module. Aborting.")+"\n") - return False else: FreeCAD.Console.PrintError(translate("Arch","Shapefile module not downloaded. Aborting.")+"\n") return False diff --git a/src/Mod/BIM/importers/importWebGL.py b/src/Mod/BIM/importers/importWebGL.py index d84b241fce..2bb11ddf65 100644 --- a/src/Mod/BIM/importers/importWebGL.py +++ b/src/Mod/BIM/importers/importWebGL.py @@ -35,18 +35,27 @@ # Development reload oneliner: # def re(): from importlib import reload;import importWebGL;reload(importWebGL);o=FreeCAD.getDocument("YourDocName");importWebGL.export([o.getObject("YourBodyName")],u"C:/path/to/your/file.htm"); +## @package importWebGL +# \ingroup ARCH +# \brief FreeCAD WebGL Exporter +# +# This module provides tools to export HTML files containing the +# exported objects in WebGL format and a simple three.js-based viewer. + """FreeCAD WebGL Exporter""" -from typing import NotRequired, TypedDict - -import FreeCAD -import Mesh -import Draft -import Part -import OfflineRenderingUtils import json import textwrap from builtins import open as pyopen +from typing import NotRequired, TypedDict + +import numpy as np + +import FreeCAD +import Draft +import Mesh +import OfflineRenderingUtils +import Part if FreeCAD.GuiUp: import FreeCADGui @@ -58,15 +67,6 @@ else: return txt -import numpy as np - -## @package importWebGL -# \ingroup ARCH -# \brief FreeCAD WebGL Exporter -# -# This module provides tools to export HTML files containing the -# exported objects in WebGL format and a simple three.js-based viewer. - disableCompression = False # Compress object data before sending to JS base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!#$%&()*+-:;/=>?@[]^_,.{|}~`" # safe str chars for js in all cases baseFloat = ",.-0123456789"