feat: Display float properties as string properties for more precision in the patch panel

This change affects the following recipes: `OffsetObjectPlacements`, `OffsetStoreyElevations`, `SetFalseOrigin`, `SetRefElevation` and `SetWorldCoordinateSystem`
This commit is contained in:
Blender Defender
2024-07-30 13:26:58 +02:00
committed by Dion Moult
parent 5572991a7c
commit 8afb1b8b30
5 changed files with 89 additions and 51 deletions
@@ -20,10 +20,23 @@ import math
import numpy as np import numpy as np
import ifcopenshell import ifcopenshell
import ifcopenshell.util.placement import ifcopenshell.util.placement
import typing
class Patcher: class Patcher:
def __init__(self, src, file, logger, x=None, y=None, z=None, should_rotate_first=True, ax=None, ay=None, az=None): def __init__(
self,
src,
file,
logger,
x: typing.Union[str, float] = "0",
y: typing.Union[str, float] = "0",
z: typing.Union[str, float] = "0",
should_rotate_first: bool = True,
ax: typing.Optional[typing.Union[str, float]] = "",
ay: typing.Optional[typing.Union[str, float]] = "",
az: typing.Optional[typing.Union[str, float]] = "",
):
"""Offset and rotate all object placements in a model """Offset and rotate all object placements in a model
Every physical object in an IFC model has an object placement, a Every physical object in an IFC model has an object placement, a
@@ -41,11 +54,11 @@ class Patcher:
entire IFC model. entire IFC model.
:param x: The X coordinate to offset by in project length units. :param x: The X coordinate to offset by in project length units.
:type x: float :type x: typing.Union[str, float]
:param y: The Y coordinate to offset by in project length units. :param y: The Y coordinate to offset by in project length units.
:type y: float :type y: typing.Union[str, float]
:param z: The Z coordinate to offset by in project length units. :param z: The Z coordinate to offset by in project length units.
:type z: float :type z: typing.Union[str, float]
:param should_rotate_first: Whether or not to rotate first and then :param should_rotate_first: Whether or not to rotate first and then
translate, or to first translate and rotate afterwards. Defaults to translate, or to first translate and rotate afterwards. Defaults to
rotate first then translate. rotate first then translate.
@@ -55,13 +68,13 @@ class Patcher:
around the Z axis). If all angle parameters are specified, then it around the Z axis). If all angle parameters are specified, then it
is treated as the angle to rotate around the X axis. Angles are in is treated as the angle to rotate around the X axis. Angles are in
decimal degrees and positive is anticlockwise. decimal degrees and positive is anticlockwise.
:type ax: float,optional :type ax: typing.Union[str, float],optional
:param ay: An optional angle to rotate by for 3D rotations along the Y :param ay: An optional angle to rotate by for 3D rotations along the Y
axis. Angles are in decimal degrees and positive is anticlockwise. axis. Angles are in decimal degrees and positive is anticlockwise.
:type ay: float,optional :type ay: typing.Union[str, float],optional
:param az: An optional angle to rotate by for 3D rotations along the Z :param az: An optional angle to rotate by for 3D rotations along the Z
axis. Angles are in decimal degrees and positive is anticlockwise. axis. Angles are in decimal degrees and positive is anticlockwise.
:type az: float,optional :type az: typing.Union[str, float],optional
Example: Example:
@@ -79,13 +92,21 @@ class Patcher:
self.src = src self.src = src
self.file = file self.file = file
self.logger = logger self.logger = logger
self.x = x self.x = float(x)
self.y = y self.y = float(y)
self.z = z self.z = float(z)
self.should_rotate_first = should_rotate_first self.should_rotate_first = should_rotate_first
self.ax = ax self.ax = None
self.ay = ay self.ay = None
self.az = az self.az = None
try:
self.ax = float(ax)
self.ay = float(ay)
self.az = float(az)
except Exception:
print("At least one input angle is not specified.")
if self.ax is None: if self.ax is None:
self.angle_type = None self.angle_type = None
elif self.ay is None: elif self.ay is None:
@@ -16,15 +16,17 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with IfcPatch. If not, see <http://www.gnu.org/licenses/>. # along with IfcPatch. If not, see <http://www.gnu.org/licenses/>.
import typing
class Patcher: class Patcher:
def __init__(self, src, file, logger, z=None): def __init__(self, src, file, logger, z: typing.Union[str, float] = "0"):
"""Offset building storeys by a particular Z value """Offset building storeys by a particular Z value
All objects placed relative to the storeys will also be shifted. All objects placed relative to the storeys will also be shifted.
:param z: The Z value in project length units to offset storeys by. :param z: The Z value in project length units to offset storeys by.
:type z: float :type z: typing.Union[str, float]
Example: Example:
@@ -36,7 +38,7 @@ class Patcher:
self.src = src self.src = src
self.file = file self.file = file
self.logger = logger self.logger = logger
self.z = z self.z = float(z)
def patch(self): def patch(self):
project = self.file.by_type("IfcProject")[0] project = self.file.by_type("IfcProject")[0]
+17 -16
View File
@@ -19,6 +19,7 @@
import ifcopenshell import ifcopenshell
import ifcopenshell.api.georeference import ifcopenshell.api.georeference
from ifcpatch.recipes import OffsetObjectPlacements, SetWorldCoordinateSystem from ifcpatch.recipes import OffsetObjectPlacements, SetWorldCoordinateSystem
import typing
class Patcher: class Patcher:
@@ -28,14 +29,14 @@ class Patcher:
file, file,
logger, logger,
name: str = "EPSG:1234", name: str = "EPSG:1234",
x: float = 0, x: typing.Union[str, float] = "0",
y: float = 0, y: typing.Union[str, float] = "0",
z: float = 0, z: typing.Union[str, float] = "0",
e: float = 0, e: typing.Union[str, float] = "0",
n: float = 0, n: typing.Union[str, float] = "0",
h: float = 0, h: typing.Union[str, float] = "0",
gn_angle: float = 0, gn_angle: typing.Union[str, float] = "0",
rotate_angle: float = 0, rotate_angle: typing.Union[str, float] = "0",
): ):
"""Sets a false origin with a map conversion in a model """Sets a false origin with a map conversion in a model
@@ -62,14 +63,14 @@ class Patcher:
self.file = file self.file = file
self.logger = logger self.logger = logger
self.name = name self.name = name
self.x = x self.x = float(x)
self.y = y self.y = float(y)
self.z = z self.z = float(z)
self.e = e self.e = float(e)
self.n = n self.n = float(n)
self.h = h self.h = float(h)
self.gn_angle = gn_angle self.gn_angle = float(gn_angle)
self.rotate_angle = rotate_angle self.rotate_angle = float(rotate_angle)
def patch(self): def patch(self):
SetWorldCoordinateSystem.Patcher(self.src, self.file, self.logger, x=0, y=0, z=0, ax=0, ay=0, az=0).patch() SetWorldCoordinateSystem.Patcher(self.src, self.file, self.logger, x=0, y=0, z=0, ax=0, ay=0, az=0).patch()
@@ -16,9 +16,11 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with IfcPatch. If not, see <http://www.gnu.org/licenses/>. # along with IfcPatch. If not, see <http://www.gnu.org/licenses/>.
import typing
class Patcher: class Patcher:
def __init__(self, src, file, logger, elevation=0): def __init__(self, src, file, logger, elevation: typing.Union[str, float] = "0"):
"""Sets the reference elevation of all IfcSites """Sets the reference elevation of all IfcSites
To completely reference model coordinates, a reference elevation should To completely reference model coordinates, a reference elevation should
@@ -30,7 +32,7 @@ class Patcher:
The reference elevation is simply a numerical attribute. The reference elevation is simply a numerical attribute.
:param elevation: The elevation to set. :param elevation: The elevation to set.
:type elevation: float :type elevation: typing.Union[str, float]
Example: Example:
@@ -42,7 +44,7 @@ class Patcher:
self.src = src self.src = src
self.file = file self.file = file
self.logger = logger self.logger = logger
self.elevation = elevation self.elevation = float(elevation)
def patch(self): def patch(self):
project = self.file.by_type("IfcProject")[0] project = self.file.by_type("IfcProject")[0]
@@ -18,29 +18,41 @@
import math import math
import numpy as np import numpy as np
import typing
class Patcher: class Patcher:
def __init__(self, src, file, logger, x=None, y=None, z=None, ax=None, ay=None, az=None): def __init__(
self,
src,
file,
logger,
x: typing.Union[str, float] = "0",
y: typing.Union[str, float] = "0",
z: typing.Union[str, float] = "0",
ax: typing.Union[str, float] = "0",
ay: typing.Union[str, float] = "0",
az: typing.Union[str, float] = "0",
):
"""Sets the world coordinate system of the geometric representation context """Sets the world coordinate system of the geometric representation context
Sets the world coordinate system to whatever you want. Sets the world coordinate system to whatever you want.
:param x: The X coordinate. :param x: The X coordinate.
:type x: float :type x: typing.Union[str, float]
:param y: The Y coordinate. :param y: The Y coordinate.
:type y: float :type y: typing.Union[str, float]
:param z: The Z coordinate. :param z: The Z coordinate.
:type z: float :type z: typing.Union[str, float]
:param ax: An angle to rotate by for 3D rotations along the X axis. :param ax: An angle to rotate by for 3D rotations along the X axis.
Angles are in decimal degrees and positive is anticlockwise. Angles are in decimal degrees and positive is anticlockwise.
:type ax: float :type ax: typing.Union[str, float]
:param ay: An angle to rotate by for 3D rotations along the Y axis. :param ay: An angle to rotate by for 3D rotations along the Y axis.
Angles are in decimal degrees and positive is anticlockwise. Angles are in decimal degrees and positive is anticlockwise.
:type ay: float :type ay: typing.Union[str, float]
:param az: An angle to rotate by for 3D rotations along the Z axis. :param az: An angle to rotate by for 3D rotations along the Z axis.
Angles are in decimal degrees and positive is anticlockwise. Angles are in decimal degrees and positive is anticlockwise.
:type az: float :type az: typing.Union[str, float]
Example: Example:
@@ -52,17 +64,17 @@ class Patcher:
self.src = src self.src = src
self.file = file self.file = file
self.logger = logger self.logger = logger
self.x = x self.x = float(x)
self.y = y self.y = float(y)
self.z = z self.z = float(z)
self.ax = ax self.ax = float(ax)
self.ay = ay self.ay = float(ay)
self.az = az self.az = float(az)
def patch(self): def patch(self):
rotate = self.identity_matrix() rotate = self.identity_matrix()
for arg in (("x", float(self.ax)), ("y", float(self.ay)), ("z", float(self.az))): for arg in (("x", self.ax), ("y", self.ay), ("z", self.az)):
if arg[1]: if arg[1]:
rotate = getattr(self, f"{arg[0]}_rotation_matrix")(math.radians(arg[1]), rotate) rotate = getattr(self, f"{arg[0]}_rotation_matrix")(math.radians(arg[1]), rotate)
@@ -74,13 +86,13 @@ class Patcher:
for context in self.file.by_type("IfcGeometricRepresentationContext", include_subtypes=False): for context in self.file.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
if context.ContextType == "Model": if context.ContextType == "Model":
context.WorldCoordinateSystem = self.file.createIfcAxis2Placement3D( context.WorldCoordinateSystem = self.file.createIfcAxis2Placement3D(
self.file.createIfcCartesianPoint((float(self.x), float(self.y), float(self.z))), self.file.createIfcCartesianPoint((self.x, self.y, self.z)),
self.file.createIfcDirection(z.tolist()), self.file.createIfcDirection(z.tolist()),
self.file.createIfcDirection(x.tolist()), self.file.createIfcDirection(x.tolist()),
) )
elif context.ContextType == "Plan": elif context.ContextType == "Plan":
context.WorldCoordinateSystem = self.file.createIfcAxis2Placement2D( context.WorldCoordinateSystem = self.file.createIfcAxis2Placement2D(
self.file.createIfcCartesianPoint((float(self.x), float(self.y), float(self.z))), self.file.createIfcCartesianPoint((self.x, self.y, self.z)),
self.file.createIfcDirection(x.tolist()), self.file.createIfcDirection(x.tolist()),
) )