mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-10 06:00:51 +00:00
clip_solid/clip_solid_bounded: implement element param to register BBIM_Boolean
This commit is contained in:
@@ -18,8 +18,11 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Sequence
|
import json
|
||||||
|
from typing import Optional, Sequence
|
||||||
|
|
||||||
|
import ifcopenshell.api.pset
|
||||||
|
import ifcopenshell.util.element
|
||||||
import ifcopenshell.util.unit
|
import ifcopenshell.util.unit
|
||||||
from ifcopenshell.util.data import Clipping
|
from ifcopenshell.util.data import Clipping
|
||||||
|
|
||||||
@@ -61,9 +64,23 @@ def clip_solid(
|
|||||||
or ``IfcBooleanClippingResult``).
|
or ``IfcBooleanClippingResult``).
|
||||||
:param location: A point on the clipping plane in the representation's
|
:param location: A point on the clipping plane in the representation's
|
||||||
local coordinate system.
|
local coordinate system.
|
||||||
:param normal: Plane normal pointing toward the material to be removed.
|
:param normal: Plane normal pointing toward the material to be removed
|
||||||
|
(see warning above).
|
||||||
|
:param element: If provided, the resulting ``IfcBooleanClippingResult`` is
|
||||||
|
registered in the element's ``BBIM_Boolean`` property set so that
|
||||||
|
:func:`regenerate_wall_representation` preserves it during regeneration.
|
||||||
:return: The resulting ``IfcBooleanClippingResult``.
|
:return: The resulting ``IfcBooleanClippingResult``.
|
||||||
"""
|
"""
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
|
||||||
clipping = Clipping(location=tuple(location), normal=tuple(normal))
|
clipping = Clipping(location=tuple(location), normal=tuple(normal))
|
||||||
return clipping.apply(file, item, unit_scale)
|
result = clipping.apply(file, item, unit_scale)
|
||||||
|
if element is not None:
|
||||||
|
pset_data = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
|
||||||
|
if pset_data:
|
||||||
|
pset = file.by_id(pset_data["id"])
|
||||||
|
data = list(set(json.loads(pset_data["Data"]) + [result.id()]))
|
||||||
|
else:
|
||||||
|
pset = ifcopenshell.api.pset.add_pset(file, product=element, name="BBIM_Boolean")
|
||||||
|
data = [result.id()]
|
||||||
|
ifcopenshell.api.pset.edit_pset(file, pset=pset, properties={"Data": json.dumps(data)})
|
||||||
|
return result
|
||||||
|
|||||||
@@ -18,10 +18,13 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Sequence
|
import json
|
||||||
|
from typing import Optional, Sequence
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
import ifcopenshell.api.pset
|
||||||
|
import ifcopenshell.util.element
|
||||||
import ifcopenshell.util.unit
|
import ifcopenshell.util.unit
|
||||||
from ifcopenshell.util.shape_builder import ShapeBuilder
|
from ifcopenshell.util.shape_builder import ShapeBuilder
|
||||||
|
|
||||||
@@ -33,6 +36,7 @@ def clip_solid_bounded(
|
|||||||
normal: Sequence[float],
|
normal: Sequence[float],
|
||||||
boundary_points: Sequence[Sequence[float]],
|
boundary_points: Sequence[Sequence[float]],
|
||||||
boundary_position: Sequence[float] = (0.0, 0.0, 0.0),
|
boundary_position: Sequence[float] = (0.0, 0.0, 0.0),
|
||||||
|
element: Optional[ifcopenshell.entity_instance] = None,
|
||||||
) -> ifcopenshell.entity_instance:
|
) -> ifcopenshell.entity_instance:
|
||||||
"""Clip a solid with a polygonally bounded half-space, returning an IfcBooleanClippingResult.
|
"""Clip a solid with a polygonally bounded half-space, returning an IfcBooleanClippingResult.
|
||||||
|
|
||||||
@@ -67,6 +71,9 @@ def clip_solid_bounded(
|
|||||||
is automatically closed — do not repeat the first point.
|
is automatically closed — do not repeat the first point.
|
||||||
:param boundary_position: 3D origin of the boundary coordinate system
|
:param boundary_position: 3D origin of the boundary coordinate system
|
||||||
(axes default to the global X/Y/Z directions). Defaults to the origin.
|
(axes default to the global X/Y/Z directions). Defaults to the origin.
|
||||||
|
:param element: If provided, the resulting ``IfcBooleanClippingResult`` is
|
||||||
|
registered in the element's ``BBIM_Boolean`` property set so that
|
||||||
|
:func:`regenerate_wall_representation` preserves it during regeneration.
|
||||||
:return: The resulting ``IfcBooleanClippingResult``.
|
:return: The resulting ``IfcBooleanClippingResult``.
|
||||||
"""
|
"""
|
||||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
|
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
|
||||||
@@ -96,4 +103,14 @@ def clip_solid_bounded(
|
|||||||
boundary = file.createIfcPolyline(ifc_pts)
|
boundary = file.createIfcPolyline(ifc_pts)
|
||||||
|
|
||||||
half_space = file.create_entity("IfcPolygonalBoundedHalfSpace", plane, False, boundary_pos_entity, boundary)
|
half_space = file.create_entity("IfcPolygonalBoundedHalfSpace", plane, False, boundary_pos_entity, boundary)
|
||||||
return file.create_entity("IfcBooleanClippingResult", "DIFFERENCE", item, half_space)
|
result = file.create_entity("IfcBooleanClippingResult", "DIFFERENCE", item, half_space)
|
||||||
|
if element is not None:
|
||||||
|
pset_data = ifcopenshell.util.element.get_pset(element, "BBIM_Boolean")
|
||||||
|
if pset_data:
|
||||||
|
pset = file.by_id(pset_data["id"])
|
||||||
|
data = list(set(json.loads(pset_data["Data"]) + [result.id()]))
|
||||||
|
else:
|
||||||
|
pset = ifcopenshell.api.pset.add_pset(file, product=element, name="BBIM_Boolean")
|
||||||
|
data = [result.id()]
|
||||||
|
ifcopenshell.api.pset.edit_pset(file, pset=pset, properties={"Data": json.dumps(data)})
|
||||||
|
return result
|
||||||
|
|||||||
@@ -16,7 +16,10 @@
|
|||||||
# 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 IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
import ifcopenshell.api.geometry
|
import ifcopenshell.api.geometry
|
||||||
|
import ifcopenshell.util.element
|
||||||
import ifcopenshell.util.shape_builder
|
import ifcopenshell.util.shape_builder
|
||||||
import test.bootstrap
|
import test.bootstrap
|
||||||
|
|
||||||
@@ -100,5 +103,53 @@ class TestClipSolid(test.bootstrap.IFC4):
|
|||||||
assert result.SecondOperand.is_a("IfcHalfSpaceSolid")
|
assert result.SecondOperand.is_a("IfcHalfSpaceSolid")
|
||||||
|
|
||||||
|
|
||||||
|
def test_element_registers_result_in_bbim_boolean(self):
|
||||||
|
extrusion = self.make_extrusion()
|
||||||
|
wall = self.file.createIfcWall()
|
||||||
|
result = ifcopenshell.api.geometry.clip_solid(
|
||||||
|
self.file,
|
||||||
|
item=extrusion,
|
||||||
|
location=[0.0, 0.0, 3.0],
|
||||||
|
normal=[0.0, 0.0, 1.0],
|
||||||
|
element=wall,
|
||||||
|
)
|
||||||
|
pset = ifcopenshell.util.element.get_pset(wall, "BBIM_Boolean")
|
||||||
|
assert pset is not None
|
||||||
|
assert result.id() in json.loads(pset["Data"])
|
||||||
|
|
||||||
|
def test_element_appends_to_existing_bbim_boolean(self):
|
||||||
|
extrusion = self.make_extrusion()
|
||||||
|
wall = self.file.createIfcWall()
|
||||||
|
first = ifcopenshell.api.geometry.clip_solid(
|
||||||
|
self.file,
|
||||||
|
item=extrusion,
|
||||||
|
location=[0.0, 0.0, 3.0],
|
||||||
|
normal=[0.0, 0.0, 1.0],
|
||||||
|
element=wall,
|
||||||
|
)
|
||||||
|
second = ifcopenshell.api.geometry.clip_solid(
|
||||||
|
self.file,
|
||||||
|
item=first,
|
||||||
|
location=[0.0, 0.0, 1.0],
|
||||||
|
normal=[0.0, 0.0, -1.0],
|
||||||
|
element=wall,
|
||||||
|
)
|
||||||
|
pset = ifcopenshell.util.element.get_pset(wall, "BBIM_Boolean")
|
||||||
|
ids = json.loads(pset["Data"])
|
||||||
|
assert first.id() in ids
|
||||||
|
assert second.id() in ids
|
||||||
|
|
||||||
|
def test_no_element_does_not_create_pset(self):
|
||||||
|
extrusion = self.make_extrusion()
|
||||||
|
wall = self.file.createIfcWall()
|
||||||
|
ifcopenshell.api.geometry.clip_solid(
|
||||||
|
self.file,
|
||||||
|
item=extrusion,
|
||||||
|
location=[0.0, 0.0, 3.0],
|
||||||
|
normal=[0.0, 0.0, 1.0],
|
||||||
|
)
|
||||||
|
assert ifcopenshell.util.element.get_pset(wall, "BBIM_Boolean") is None
|
||||||
|
|
||||||
|
|
||||||
class TestClipSolidIFC2X3(test.bootstrap.IFC2X3, TestClipSolid):
|
class TestClipSolidIFC2X3(test.bootstrap.IFC2X3, TestClipSolid):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -16,7 +16,10 @@
|
|||||||
# 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 IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
import ifcopenshell.api.geometry
|
import ifcopenshell.api.geometry
|
||||||
|
import ifcopenshell.util.element
|
||||||
import ifcopenshell.util.shape_builder
|
import ifcopenshell.util.shape_builder
|
||||||
import test.bootstrap
|
import test.bootstrap
|
||||||
|
|
||||||
@@ -145,5 +148,33 @@ class TestClipSolidBounded(test.bootstrap.IFC4):
|
|||||||
assert first_clip.FirstOperand == extrusion
|
assert first_clip.FirstOperand == extrusion
|
||||||
|
|
||||||
|
|
||||||
|
def test_element_registers_result_in_bbim_boolean(self):
|
||||||
|
extrusion = self.make_extrusion()
|
||||||
|
wall = self.file.createIfcWall()
|
||||||
|
result = ifcopenshell.api.geometry.clip_solid_bounded(
|
||||||
|
self.file,
|
||||||
|
item=extrusion,
|
||||||
|
location=[2.5, 0.0, 2.0],
|
||||||
|
normal=[0.6, 0.0, 0.8],
|
||||||
|
boundary_points=[[2.0, 0.0], [3.0, 0.0], [3.0, 2.0], [2.0, 2.0]],
|
||||||
|
element=wall,
|
||||||
|
)
|
||||||
|
pset = ifcopenshell.util.element.get_pset(wall, "BBIM_Boolean")
|
||||||
|
assert pset is not None
|
||||||
|
assert result.id() in json.loads(pset["Data"])
|
||||||
|
|
||||||
|
def test_no_element_does_not_create_pset(self):
|
||||||
|
extrusion = self.make_extrusion()
|
||||||
|
wall = self.file.createIfcWall()
|
||||||
|
ifcopenshell.api.geometry.clip_solid_bounded(
|
||||||
|
self.file,
|
||||||
|
item=extrusion,
|
||||||
|
location=[2.5, 0.0, 2.0],
|
||||||
|
normal=[0.6, 0.0, 0.8],
|
||||||
|
boundary_points=[[2.0, 0.0], [3.0, 0.0], [3.0, 2.0], [2.0, 2.0]],
|
||||||
|
)
|
||||||
|
assert ifcopenshell.util.element.get_pset(wall, "BBIM_Boolean") is None
|
||||||
|
|
||||||
|
|
||||||
class TestClipSolidBoundedIFC2X3(test.bootstrap.IFC2X3, TestClipSolidBounded):
|
class TestClipSolidBoundedIFC2X3(test.bootstrap.IFC2X3, TestClipSolidBounded):
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user