First Commit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Handles the definition of cross sectional profiles
|
||||
|
||||
Maintaining a clean profile library is important for structural simulations and
|
||||
identification of standardised profiles for fabrication and carbon counting.
|
||||
"""
|
||||
|
||||
from .. import wrap_usecases
|
||||
from .add_arbitrary_profile import add_arbitrary_profile
|
||||
from .add_arbitrary_profile_with_voids import add_arbitrary_profile_with_voids
|
||||
from .add_parameterized_profile import add_parameterized_profile
|
||||
from .copy_profile import copy_profile
|
||||
from .edit_profile import edit_profile
|
||||
from .remove_profile import remove_profile
|
||||
|
||||
wrap_usecases(__path__, __name__)
|
||||
|
||||
__all__ = [
|
||||
"add_arbitrary_profile",
|
||||
"add_arbitrary_profile_with_voids",
|
||||
"add_parameterized_profile",
|
||||
"copy_profile",
|
||||
"edit_profile",
|
||||
"remove_profile",
|
||||
]
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,83 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Optional, Union
|
||||
|
||||
import numpy.typing as npt
|
||||
|
||||
import ifcopenshell.util.unit
|
||||
from ifcopenshell.util.shape_builder import SequenceOfVectors, V, ifc_safe_vector_type
|
||||
|
||||
|
||||
def add_arbitrary_profile(
|
||||
file: ifcopenshell.file, profile: SequenceOfVectors, name: Optional[str] = None
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""Adds a new arbitrary polyline-based profile
|
||||
|
||||
The profile is represented as a polyline defined by a list of
|
||||
coordinates. Only straight segments are allowed. Coordinates must be
|
||||
provided in SI meters.
|
||||
|
||||
To represent a closed curve, the first and last coordinate must be
|
||||
identical.
|
||||
|
||||
:param profile: A list of coordinates
|
||||
:param name: If the profile is semantically significant (i.e. to be
|
||||
managed and reused by the user) then it must be named. Otherwise,
|
||||
this may be left as none.
|
||||
:return: The newly created IfcArbitraryClosedProfileDef
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# A 10mm by 100mm rectangle, such that might be used as a wooden
|
||||
# skirting board or kick plate.
|
||||
square = ifcopenshell.api.profile.add_arbitrary_profile(model,
|
||||
profile=[(0., 0.), (.01, 0.), (.01, .1), (0., .1), (0., 0.)],
|
||||
name="SK01 Profile")
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
return usecase.execute(V(profile), name)
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(self, profile: npt.NDArray, name: Union[str, None]):
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
points = self.convert_si_to_unit(profile)
|
||||
if self.file.schema == "IFC2X3":
|
||||
curve = self.file.create_entity(
|
||||
"IfcPolyline",
|
||||
[self.file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(p)) for p in points],
|
||||
)
|
||||
else:
|
||||
dimensions = points.shape[1]
|
||||
if dimensions == 2:
|
||||
ifc_points = self.file.create_entity("IfcCartesianPointList2D", ifc_safe_vector_type(points))
|
||||
elif dimensions == 3:
|
||||
ifc_points = self.file.create_entity("IfcCartesianPointList3D", ifc_safe_vector_type(points))
|
||||
else:
|
||||
assert False, f"Invalid dimensions: {dimensions}."
|
||||
curve = self.file.create_entity("IfcIndexedPolyCurve", ifc_points)
|
||||
return self.file.create_entity("IfcArbitraryClosedProfileDef", "AREA", name, curve)
|
||||
|
||||
def convert_si_to_unit(self, co: npt.NDArray) -> npt.NDArray:
|
||||
return co / self.unit_scale
|
||||
@@ -0,0 +1,114 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Optional, Union
|
||||
|
||||
import numpy.typing as npt
|
||||
|
||||
import ifcopenshell.util.unit
|
||||
from ifcopenshell.util.shape_builder import SequenceOfVectors, V, ifc_safe_vector_type
|
||||
|
||||
|
||||
def add_arbitrary_profile_with_voids(
|
||||
file: ifcopenshell.file,
|
||||
outer_profile: SequenceOfVectors,
|
||||
inner_profiles: list[SequenceOfVectors],
|
||||
name: Optional[str] = None,
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""Adds a new arbitrary polyline-based profile with voids
|
||||
|
||||
The outer profile is represented as a polyline defined by a list of
|
||||
coordinates. Only straight segments are allowed. Coordinates must be
|
||||
provided in SI meters.
|
||||
|
||||
To represent a closed curve, the first and last coordinate must be
|
||||
identical.
|
||||
|
||||
The inner profiles are represented as a list of polylines.
|
||||
Every polyline in defined by a list of coordinates.
|
||||
Only straight segments are allowed. Coordinates must be
|
||||
provided in SI meters.
|
||||
|
||||
:param outer_profile: A list of coordinates
|
||||
:param inner_profiles: A list of polylines
|
||||
:param name: If the profile is semantically significant (i.e. to be
|
||||
managed and reused by the user) then it must be named. Otherwise,
|
||||
this may be left as none.
|
||||
:return: The newly created IfcArbitraryProfileDefWithVoids
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
# A 400mm by 400mm square with a 200mm by 200mm hole in it.
|
||||
square_with_hole = ifcopenshell.api.profile.add_arbitrary_profile_with_voids(model,
|
||||
outer_profile=[(0., 0.), (.4, 0.), (.4, .4), (0., .4), (0., 0.)],
|
||||
inner_profiles=[[(0.1, 0.1), (0.3, 0.1), (0.3, 0.3), (0.1, 0.3), (0.1, 0.1)]],
|
||||
name="SK01 Hole Profile")
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
return usecase.execute(V(outer_profile), [V(p) for p in inner_profiles], name)
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
|
||||
def execute(
|
||||
self,
|
||||
outer_profile: npt.NDArray,
|
||||
inner_profiles: list[npt.NDArray],
|
||||
name: Union[str, None],
|
||||
):
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
outer_points = self.convert_si_to_unit(outer_profile)
|
||||
inner_points: list[npt.NDArray] = []
|
||||
for inner_profile in inner_profiles:
|
||||
inner_points.append(self.convert_si_to_unit(inner_profile))
|
||||
|
||||
inner_curves: list[ifcopenshell.entity_instance] = []
|
||||
if self.file.schema == "IFC2X3":
|
||||
outer_curve = self.file.create_entity(
|
||||
"IfcPolyline",
|
||||
[self.file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(p)) for p in outer_points],
|
||||
)
|
||||
for inner_point in inner_points:
|
||||
inner_curves.append(
|
||||
self.file.create_entity(
|
||||
"IfcPolyline",
|
||||
[self.file.create_entity("IfcCartesianPoint", ifc_safe_vector_type(p)) for p in inner_point],
|
||||
)
|
||||
)
|
||||
else:
|
||||
outer_curve = self.file.create_entity(
|
||||
"IfcIndexedPolyCurve",
|
||||
(self.file.create_entity("IfcCartesianPointList3D", ifc_safe_vector_type(outer_points))),
|
||||
)
|
||||
for inner_point in inner_points:
|
||||
dimensions = inner_point.shape[1]
|
||||
if dimensions == 2:
|
||||
ifc_points = self.file.create_entity("IfcCartesianPointList2D", ifc_safe_vector_type(inner_point))
|
||||
elif dimensions == 3:
|
||||
ifc_points = self.file.create_entity("IfcCartesianPointList3D", ifc_safe_vector_type(inner_point))
|
||||
else:
|
||||
assert False, f"Invalid dimensions: {dimensions}."
|
||||
inner_curves.append(self.file.create_entity("IfcIndexedPolyCurve", ifc_points))
|
||||
return self.file.create_entity("IfcArbitraryProfileDefWithVoids", "AREA", name, outer_curve, inner_curves)
|
||||
|
||||
def convert_si_to_unit(self, co: npt.NDArray) -> npt.NDArray:
|
||||
return co / self.unit_scale
|
||||
@@ -0,0 +1,50 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
from typing import Literal
|
||||
|
||||
import ifcopenshell
|
||||
|
||||
ProfileType = Literal["AREA", "CURVE"]
|
||||
|
||||
|
||||
def add_parameterized_profile(
|
||||
file: ifcopenshell.file, ifc_class: str, profile_type: str = "AREA"
|
||||
) -> ifcopenshell.entity_instance:
|
||||
"""Adds a new parameterised profile
|
||||
|
||||
IFC offers parameterised profiles for common standardised hot roll
|
||||
steel sections and common concrete forms. A full list is available on
|
||||
the IFC documentation as subclasses of IfcParameterizedProfileDef.
|
||||
|
||||
Currently, this API has no benefit over directly calling
|
||||
ifcopenshell.file.create_entity.
|
||||
|
||||
:param ifc_class: The subclass of IfcParameterizedProfileDef that you'd
|
||||
like to create.
|
||||
:param profile_type:
|
||||
:return: The newly created element depending on the specified ifc_class.
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
circle = ifcopenshell.api.profile.add_parameterized_profile(model,
|
||||
ifc_class="IfcCircleProfileDef")
|
||||
circle.Radius = 1.
|
||||
"""
|
||||
return file.create_entity(ifc_class, ProfileType=profile_type)
|
||||
@@ -0,0 +1,47 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
def copy_profile(file: ifcopenshell.file, profile: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
|
||||
"""Copies a profile
|
||||
|
||||
All profile's psets are copied. The copied profile is not
|
||||
associated to any elements.
|
||||
|
||||
:param profile: The IfcProfileDef to copy
|
||||
:return: The new copy of the profile
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
profile = ifcopenshell.api.profile.add_profile(model, ifc_class="IfcRectangleProfileDef")
|
||||
|
||||
# Let's duplicate the rectangle profile
|
||||
profile_copy = ifcopenshell.api.profile.copy_profile(model, profile=profile)
|
||||
"""
|
||||
new_profile = ifcopenshell.util.element.copy_deep(file, profile)
|
||||
inverses = file.get_inverse(profile)
|
||||
psets = [i for i in inverses if i.is_a("IfcProfileProperties")]
|
||||
for pset in psets:
|
||||
new_pset = ifcopenshell.util.element.copy(file, pset)
|
||||
new_pset.ProfileDefinition = new_profile
|
||||
return new_profile
|
||||
@@ -0,0 +1,45 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
from typing import Any
|
||||
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
def edit_profile(file: ifcopenshell.file, profile: ifcopenshell.entity_instance, attributes: dict[str, Any]) -> None:
|
||||
"""Edits the attributes of an IfcProfileDef
|
||||
|
||||
For more information about the attributes and data types of an
|
||||
IfcProfileDef, consult the IFC documentation.
|
||||
|
||||
:param profile: The IfcProfileDef entity you want to edit
|
||||
:param attributes: a dictionary of attribute names and values.
|
||||
:return: None
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
circle = ifcopenshell.api.profile.add_parameterized_profile(model,
|
||||
ifc_class="IfcCircleProfileDef")
|
||||
circle = 1.
|
||||
|
||||
ifcopenshell.api.profile.edit_profile(model,
|
||||
profile=circle, attributes={"ProfileName": "1000mm Dia"})
|
||||
"""
|
||||
for name, value in attributes.items():
|
||||
setattr(profile, name, value)
|
||||
@@ -0,0 +1,60 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.pset
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
def remove_profile(file: ifcopenshell.file, profile: ifcopenshell.entity_instance) -> None:
|
||||
"""Removes a profile
|
||||
|
||||
:param profile: The IfcProfileDef to remove.
|
||||
|
||||
Example:
|
||||
|
||||
.. code:: python
|
||||
|
||||
circle = ifcopenshell.api.profile.add_parameterized_profile(model,
|
||||
ifc_class="IfcCircleProfileDef")
|
||||
circle = 1.
|
||||
ifcopenshell.api.profile.remove_profile(model, profile=circle)
|
||||
"""
|
||||
is_ifc2x3 = file.schema == "IFC2X3"
|
||||
|
||||
subelements = set()
|
||||
for attribute in profile:
|
||||
if isinstance(attribute, ifcopenshell.entity_instance):
|
||||
subelements.add(attribute)
|
||||
|
||||
# Clean up profile proprty sets.
|
||||
profile_psets = []
|
||||
if is_ifc2x3:
|
||||
for pset in file.by_type("IfcProfileProperties"):
|
||||
if pset.ProfileDefinition != profile:
|
||||
continue
|
||||
profile_psets.append(pset)
|
||||
else:
|
||||
profile_psets = profile.HasProperties
|
||||
|
||||
for pset in profile_psets:
|
||||
ifcopenshell.api.pset.remove_pset(file, product=profile, pset=pset)
|
||||
|
||||
file.remove(profile)
|
||||
for subelement in subelements:
|
||||
ifcopenshell.util.element.remove_deep2(file, subelement)
|
||||
Reference in New Issue
Block a user