mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 17:58:20 +00:00
Merge remote-tracking branch 'origin/v0.8.0' into tfk-rocksdb-storage
This commit is contained in:
@@ -21,6 +21,7 @@ import numpy as np
|
||||
import ifcopenshell
|
||||
from typing import Any, Union
|
||||
from dataclasses import dataclass
|
||||
from ifcopenshell.util.shape_builder import ShapeBuilder
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -78,9 +79,7 @@ class Clipping:
|
||||
|
||||
if not ifc_file:
|
||||
ifc_file = first_operand.file
|
||||
|
||||
location = ifc_file.createIfcCartesianPoint([i / unit_scale for i in self.location])
|
||||
direction = ifc_file.createIfcDirection(self.normal)
|
||||
builder = ShapeBuilder(ifc_file)
|
||||
|
||||
normal = np.array(self.normal)
|
||||
if np.allclose(normal, np.array([0.0, 0.0, 1.0]), atol=1e-2) or np.allclose(
|
||||
@@ -92,9 +91,9 @@ class Clipping:
|
||||
|
||||
x_axis = np.cross(normal, arbitrary_vector)
|
||||
x_axis /= np.linalg.norm(x_axis)
|
||||
x_axis = ifc_file.createIfcDirection(x_axis.tolist())
|
||||
|
||||
plane = ifc_file.createIfcPlane(ifc_file.createIfcAxis2Placement3D(location, direction, x_axis))
|
||||
placement = builder.create_axis2_placement_3d([i / unit_scale for i in self.location], self.normal, x_axis)
|
||||
plane = ifc_file.create_entity("IfcPlane", placement)
|
||||
|
||||
second_operand = ifc_file.createIfcHalfSpaceSolid(plane, False)
|
||||
return ifc_file.createIfcBooleanClippingResult("DIFFERENCE", first_operand, second_operand)
|
||||
|
||||
@@ -1169,6 +1169,25 @@ def get_groups(element: ifcopenshell.entity_instance) -> list[ifcopenshell.entit
|
||||
return groups
|
||||
|
||||
|
||||
def get_controls(element: ifcopenshell.entity_instance) -> Generator[ifcopenshell.entity_instance]:
|
||||
"""
|
||||
Retrieves the controls of an element.
|
||||
|
||||
:param element: The IFC element
|
||||
:return: Generator of IfcControl elements assigned to the element.
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
task = file.by_type("IfcTask")[0]
|
||||
control = ifcopenshell.util.element.get_controls(task)[0]
|
||||
"""
|
||||
for rel in element.HasAssignments:
|
||||
if rel.is_a("IfcRelAssignsToControl"):
|
||||
yield rel.RelatingControl
|
||||
|
||||
|
||||
def get_parent(element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
|
||||
"""Get the parent in the spatial heirarchy
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.placement
|
||||
from typing import NamedTuple, Optional, Union
|
||||
from decimal import Decimal, ROUND_HALF_UP
|
||||
|
||||
MatrixType = ifcopenshell.util.placement.MatrixType
|
||||
|
||||
@@ -39,39 +40,54 @@ class HelmertTransformation(NamedTuple):
|
||||
factor_z: float
|
||||
|
||||
|
||||
def dms2dd(degrees: int, minutes: int, seconds: int, ms: int = 0) -> float:
|
||||
"""Convert degrees, minutes, and (milli)seconds to decimal degrees
|
||||
def dms2dd(degrees: int, minutes: int, seconds: int, us: int = 0) -> float:
|
||||
"""Convert degrees, minutes, and (micro)seconds to decimal degrees
|
||||
All components must be either positive or negative.
|
||||
|
||||
:param degrees: The degrees component
|
||||
:param minutes: The minutes component
|
||||
:param seconds: The seconds component
|
||||
:param ms: The milliseconds component
|
||||
:param us: The microseconds component
|
||||
:return: The angle in decimal degrees.
|
||||
"""
|
||||
dd = float(degrees) + float(minutes) / 60.0 + float(seconds) / (3600.0) + float(ms / 3600000000.0)
|
||||
return dd
|
||||
all_positive_or_zero = degrees >= 0 and minutes >= 0 and seconds >= 0 and us >= 0
|
||||
all_negative_or_zero = degrees <= 0 and minutes <= 0 and seconds <= 0 and us <= 0
|
||||
assert all_positive_or_zero or all_negative_or_zero
|
||||
return degrees + minutes / 60.0 + seconds / 3600.0 + us / 3600000000.0
|
||||
|
||||
|
||||
def dd2dms(dd: float, use_ms: bool = False) -> Union[tuple[float, float, float, float], tuple[float, float, float]]:
|
||||
"""Convert decimal degrees to degrees, minutes, and (milli)seconds format
|
||||
def dd2dms(dd: float, use_us: bool = False) -> Union[tuple[int, int, int, int], tuple[int, int, float]]:
|
||||
"""Convert decimal degrees to degrees, minutes, and (micro)seconds format
|
||||
|
||||
:param dd: The decimal degrees
|
||||
:param use_ms: True if to include milliseconds and false otherwise. Defaults to false.
|
||||
:return: The angle in a tuple of either 3 or 4 values, being degrees,
|
||||
minutes, seconds, and optionally milliseconds.
|
||||
:param use_us: True if to include microseconds and false otherwise. Defaults to false.
|
||||
:return: The angle in a tuple of either 3 or 4 values,
|
||||
4 values: integer number of degrees, integer number of minutes, integer number of seconds and integer number of microseconds
|
||||
3 values: integer number of degrees, integer number of minutes, and a float number for seconds
|
||||
:note: the tuple follows the format of IfcCompoundPlaneAngleMeasure. Namely all of its components are either positive or negative.
|
||||
"""
|
||||
dd = float(dd)
|
||||
sign = 1 if dd >= 0 else -1
|
||||
dd = abs(dd)
|
||||
if use_ms:
|
||||
seconds, ms = divmod(dd * 60 * 60 * 1000000, 1000000)
|
||||
minutes, seconds = divmod(dd * 60 * 60, 60)
|
||||
degrees, minutes = divmod(minutes, 60)
|
||||
if dd < 0:
|
||||
degrees = -degrees
|
||||
if use_ms:
|
||||
return (int(degrees) * sign, int(minutes) * sign, int(seconds) * sign, int(ms) * sign)
|
||||
return (int(degrees) * sign, int(minutes) * sign, int(seconds) * sign)
|
||||
dd_decimal = Decimal(str(dd))
|
||||
|
||||
degrees = int(dd_decimal)
|
||||
degrees_decimal = Decimal(degrees)
|
||||
|
||||
fractional_part = dd_decimal - degrees_decimal
|
||||
|
||||
minutes_decimal = fractional_part * Decimal(60)
|
||||
minutes = int(minutes_decimal)
|
||||
minutes_decimal_int = Decimal(minutes)
|
||||
|
||||
seconds_decimal = (minutes_decimal - minutes_decimal_int) * Decimal(60)
|
||||
|
||||
if use_us:
|
||||
seconds = int(seconds_decimal)
|
||||
seconds_decimal_int = Decimal(seconds)
|
||||
microseconds_decimal = (seconds_decimal - seconds_decimal_int) * Decimal(1000000)
|
||||
microseconds = int(microseconds_decimal.quantize(Decimal(1), rounding=ROUND_HALF_UP))
|
||||
return (degrees, minutes, seconds, microseconds)
|
||||
else:
|
||||
seconds_float = float(seconds_decimal)
|
||||
return (degrees, minutes, seconds_float)
|
||||
|
||||
|
||||
def xyz2enh(
|
||||
|
||||
@@ -692,7 +692,8 @@ def calculate_unit_scale(ifc_file: ifcopenshell.file, unit_type: str = "LENGTHUN
|
||||
:returns: The scale factor
|
||||
"""
|
||||
if (
|
||||
unit_type
|
||||
type(ifc_file) is ifcopenshell.file
|
||||
and unit_type
|
||||
not in ifcopenshell.ifcopenshell_wrapper.schema_by_name(ifc_file.schema_identifier)
|
||||
.declaration_by_name("IfcUnitEnum")
|
||||
.enumeration_items()
|
||||
|
||||
Reference in New Issue
Block a user