mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
Merge branch 'IfcOpenShell:v0.7.0' into v0.7.0
This commit is contained in:
@@ -0,0 +1,95 @@
|
|||||||
|
name: ci_py_only
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'src/**'
|
||||||
|
- 'test/**'
|
||||||
|
- 'conda/**'
|
||||||
|
- 'cmake/**'
|
||||||
|
- '.github/workflows/ci_py_only.yml'
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
activate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: |
|
||||||
|
github.repository == 'IfcOpenShell/IfcOpenShell' &&
|
||||||
|
!contains(github.event.head_commit.message, 'skip ci')
|
||||||
|
steps:
|
||||||
|
- run: echo ok go
|
||||||
|
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
needs: activate
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Install C++ dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt-get install --no-install-recommends \
|
||||||
|
git cmake gcc g++ \
|
||||||
|
libboost-date-time-dev \
|
||||||
|
libboost-filesystem-dev \
|
||||||
|
libboost-iostreams-dev \
|
||||||
|
libboost-program-options-dev \
|
||||||
|
libboost-regex-dev \
|
||||||
|
libboost-system-dev \
|
||||||
|
libboost-thread-dev \
|
||||||
|
python3-all-dev python3-pip \
|
||||||
|
swig libpcre3-dev libxml2-dev \
|
||||||
|
libtbb-dev nlohmann-json3-dev \
|
||||||
|
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
|
||||||
|
libhdf5-dev libcgal-dev
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: hendrikmuhs/ccache-action@v1
|
||||||
|
|
||||||
|
- name: Build ifcopenshell
|
||||||
|
run: |
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake \
|
||||||
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_PREFIX_PATH=/usr \
|
||||||
|
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
|
||||||
|
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
|
||||||
|
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||||
|
-DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 \
|
||||||
|
-DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.8 \
|
||||||
|
-DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.8.so \
|
||||||
|
-DCOLLADA_SUPPORT=Off \
|
||||||
|
"-DSCHEMA_VERSIONS=2x3;4" \
|
||||||
|
-DBUILD_CONVERT=Off \
|
||||||
|
-DGLTF_SUPPORT=On \
|
||||||
|
-DJSON_INCLUDE_DIR=/usr/include \
|
||||||
|
-DCGAL_INCLUDE_DIR=/usr/include \
|
||||||
|
-DGMP_INCLUDE_DIR=/usr/include \
|
||||||
|
-DMPFR_INCLUDE_DIR=/usr/include \
|
||||||
|
-DGMP_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||||
|
-DMPFR_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||||
|
-DHDF5_INCLUDE_DIR=/usr/include/hdf5/serial \
|
||||||
|
../cmake
|
||||||
|
sudo make -j $(nproc)
|
||||||
|
sudo make install
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
sudo /usr/bin/python -m pip install -U pip
|
||||||
|
sudo /usr/bin/python -m pip install xmlschema numpy lxml
|
||||||
|
sudo /usr/bin/python -m pip install src/bcf
|
||||||
|
sudo /usr/bin/python -m pip install pytest
|
||||||
|
sudo /usr/bin/python -m pip install isodate
|
||||||
|
sudo /usr/bin/python -m pip install lark
|
||||||
|
sudo /usr/bin/python -m pip install networkx
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
cd test
|
||||||
|
sudo /usr/bin/python tests.py
|
||||||
|
cd ../src/ifcopenshell-python
|
||||||
|
mv ifcopenshell ifcopenshell-local # Force testing on installed module
|
||||||
|
make test
|
||||||
+1
-1
@@ -10,4 +10,4 @@
|
|||||||
url = https://github.com/IfcOpenShell/svgfill
|
url = https://github.com/IfcOpenShell/svgfill
|
||||||
[submodule "src/ifcopenshell-python/test/Sample-BIM-Files"]
|
[submodule "src/ifcopenshell-python/test/Sample-BIM-Files"]
|
||||||
path = src/ifcopenshell-python/test/Sample-BIM-Files
|
path = src/ifcopenshell-python/test/Sample-BIM-Files
|
||||||
url = https://github.com/atomczak/Sample-BIM-Files
|
url = https://github.com/IfcOpenShell/ids-test-files
|
||||||
@@ -666,7 +666,7 @@ if (BUILD_IFCGEOM)
|
|||||||
endforeach()
|
endforeach()
|
||||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES})
|
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
if (BUILD_CONVERT)
|
if (BUILD_CONVERT OR BUILD_IFCPYTHON)
|
||||||
foreach(s ${SCHEMA_VERSIONS})
|
foreach(s ${SCHEMA_VERSIONS})
|
||||||
set(SERIALIZER_SCHEMA_LIBRARIES ${SERIALIZER_SCHEMA_LIBRARIES} Serializers_ifc${s})
|
set(SERIALIZER_SCHEMA_LIBRARIES ${SERIALIZER_SCHEMA_LIBRARIES} Serializers_ifc${s})
|
||||||
endforeach()
|
endforeach()
|
||||||
@@ -739,7 +739,7 @@ TARGET_LINK_LIBRARIES(IfcGeom IfcParse ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREA
|
|||||||
|
|
||||||
endif(BUILD_IFCGEOM)
|
endif(BUILD_IFCGEOM)
|
||||||
|
|
||||||
if (BUILD_CONVERT)
|
if (BUILD_CONVERT OR BUILD_IFCPYTHON)
|
||||||
|
|
||||||
# Serializers
|
# Serializers
|
||||||
file(GLOB SERIALIZERS_H_FILES ../src/serializers/*.h)
|
file(GLOB SERIALIZERS_H_FILES ../src/serializers/*.h)
|
||||||
@@ -760,6 +760,10 @@ set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS $
|
|||||||
|
|
||||||
TARGET_LINK_LIBRARIES(Serializers ${SERIALIZER_SCHEMA_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
|
TARGET_LINK_LIBRARIES(Serializers ${SERIALIZER_SCHEMA_LIBRARIES} ${OPENCOLLADA_LIBRARIES})
|
||||||
|
|
||||||
|
endif(BUILD_CONVERT or BUILD_IFCPYTHON)
|
||||||
|
|
||||||
|
if (BUILD_CONVERT)
|
||||||
|
|
||||||
# IfcConvert
|
# IfcConvert
|
||||||
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
|
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
|
||||||
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
|
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ classes = [
|
|||||||
operator.SelectSchemaDir,
|
operator.SelectSchemaDir,
|
||||||
operator.SelectURIAttribute,
|
operator.SelectURIAttribute,
|
||||||
prop.StrProperty,
|
prop.StrProperty,
|
||||||
|
operator.BIM_OT_enum_property_search, # /!\ Register AFTER prop.StrProperty
|
||||||
prop.ObjProperty,
|
prop.ObjProperty,
|
||||||
prop.Attribute,
|
prop.Attribute,
|
||||||
prop.ModuleVisibility,
|
prop.ModuleVisibility,
|
||||||
|
|||||||
@@ -38,20 +38,13 @@ def draw_attribute(attribute, layout, copy_operator=None):
|
|||||||
if not value_name:
|
if not value_name:
|
||||||
layout.label(text=attribute.name)
|
layout.label(text=attribute.name)
|
||||||
return
|
return
|
||||||
if len(attribute.enumerated_values) != 0:
|
if value_name == "enum_value":
|
||||||
layout.label(text=attribute.name)
|
prop_with_search(layout, attribute, "enum_value", text=attribute.name)
|
||||||
grid = layout.column_flow(columns=3)
|
|
||||||
for e in attribute.enumerated_values:
|
|
||||||
grid.prop(
|
|
||||||
e,
|
|
||||||
"is_selected",
|
|
||||||
text=str(e[value_name])
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
layout.prop(
|
layout.prop(
|
||||||
attribute,
|
attribute,
|
||||||
value_name,
|
value_name,
|
||||||
text=attribute.name,
|
text=attribute.name,
|
||||||
)
|
)
|
||||||
if attribute.is_optional:
|
if attribute.is_optional:
|
||||||
layout.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
layout.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||||
@@ -115,6 +108,16 @@ def export_attributes(props, callback=None):
|
|||||||
return attributes
|
return attributes
|
||||||
|
|
||||||
|
|
||||||
|
def prop_with_search(layout, data, prop_name, **kwargs):
|
||||||
|
# kwargs are layout.prop arguments (text, icon, etc.)
|
||||||
|
row = layout.row(align=True)
|
||||||
|
# Magick courtesy of https://blender.stackexchange.com/a/203443/86891
|
||||||
|
row.context_pointer_set(name="data", data=data)
|
||||||
|
row.prop(data, prop_name, **kwargs)
|
||||||
|
op = row.operator("bim.enum_property_search", text="", icon="VIEWZOOM")
|
||||||
|
op.prop_name = prop_name
|
||||||
|
|
||||||
|
|
||||||
class IfcHeaderExtractor:
|
class IfcHeaderExtractor:
|
||||||
def __init__(self, filepath: str):
|
def __init__(self, filepath: str):
|
||||||
self.filepath = filepath
|
self.filepath = filepath
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class BIMBrickProperties(PropertyGroup):
|
|||||||
libraries: EnumProperty(name="Libraries", items=get_libraries)
|
libraries: EnumProperty(name="Libraries", items=get_libraries)
|
||||||
namespace: EnumProperty(name="Namespace", items=get_namespaces)
|
namespace: EnumProperty(name="Namespace", items=get_namespaces)
|
||||||
brick_equipment_class: EnumProperty(name="Brick Equipment Class", items=get_brick_equipment_classes)
|
brick_equipment_class: EnumProperty(name="Brick Equipment Class", items=get_brick_equipment_classes)
|
||||||
|
|
||||||
getter_enum = {
|
getter_enum = {
|
||||||
"libraries": get_libraries,
|
"libraries": get_libraries,
|
||||||
"namespace": get_namespaces,
|
"namespace": get_namespaces,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from bpy.types import Panel, UIList
|
from bpy.types import Panel, UIList
|
||||||
from blenderbim.bim.ui import prop_with_search
|
from blenderbim.bim.helper import prop_with_search
|
||||||
from blenderbim.bim.module.brick.data import BrickschemaData, BrickschemaReferencesData
|
from blenderbim.bim.module.brick.data import BrickschemaData, BrickschemaReferencesData
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ class CreateAllShapes(bpy.types.Operator):
|
|||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
self.file = IfcStore.get_file()
|
||||||
elements = self.file.by_type("IfcElement") + self.file.by_type("IfcSpace")
|
elements = self.file.by_type("IfcElement") + self.file.by_type("IfcSpace")
|
||||||
|
|
||||||
total = len(elements)
|
total = len(elements)
|
||||||
settings = ifcopenshell.geom.settings()
|
settings = ifcopenshell.geom.settings()
|
||||||
failures = []
|
failures = []
|
||||||
|
|||||||
@@ -152,13 +152,13 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
|
|
||||||
with profile("Generate underlay"):
|
with profile("Generate underlay"):
|
||||||
underlay_svg = self.generate_underlay(context)
|
underlay_svg = self.generate_underlay(context)
|
||||||
|
|
||||||
with profile("Generate linework"):
|
with profile("Generate linework"):
|
||||||
linework_svg = self.generate_linework(context)
|
linework_svg = self.generate_linework(context)
|
||||||
|
|
||||||
with profile("Generate annotation"):
|
with profile("Generate annotation"):
|
||||||
annotation_svg = self.generate_annotation(context)
|
annotation_svg = self.generate_annotation(context)
|
||||||
|
|
||||||
with profile("Combine SVG layers"):
|
with profile("Combine SVG layers"):
|
||||||
svg_path = self.combine_svgs(context, underlay_svg, linework_svg, annotation_svg)
|
svg_path = self.combine_svgs(context, underlay_svg, linework_svg, annotation_svg)
|
||||||
|
|
||||||
|
|||||||
@@ -392,6 +392,7 @@ class BIMTextProperties(PropertyGroup):
|
|||||||
name="Font Size",
|
name="Font Size",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BIMAssignedProductProperties(PropertyGroup):
|
class BIMAssignedProductProperties(PropertyGroup):
|
||||||
is_editing_product: BoolProperty(name="Is Editing Product", default=False)
|
is_editing_product: BoolProperty(name="Is Editing Product", default=False)
|
||||||
relating_product: PointerProperty(name="Relating Product", type=bpy.types.Object)
|
relating_product: PointerProperty(name="Relating Product", type=bpy.types.Object)
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class SheetBuilder:
|
|||||||
sheet_tree = ET.parse(sheet_path)
|
sheet_tree = ET.parse(sheet_path)
|
||||||
sheet_root = sheet_tree.getroot()
|
sheet_root = sheet_tree.getroot()
|
||||||
|
|
||||||
for g in sheet_root.findall('{http://www.w3.org/2000/svg}g'):
|
for g in sheet_root.findall("{http://www.w3.org/2000/svg}g"):
|
||||||
if g.attrib.get("data-id") == str(reference.id()):
|
if g.attrib.get("data-id") == str(reference.id()):
|
||||||
sheet_root.remove(g)
|
sheet_root.remove(g)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class SvgWriter:
|
|||||||
viewBox=("0 0 {} {}".format(self.width, self.height)),
|
viewBox=("0 0 {} {}".format(self.width, self.height)),
|
||||||
id="root",
|
id="root",
|
||||||
data_scale=self.human_scale,
|
data_scale=self.human_scale,
|
||||||
debug=False, # Disable validation so that we can insert the IFC namespace
|
debug=False, # Disable validation so that we can insert the IFC namespace
|
||||||
)
|
)
|
||||||
self.svg.attribs["xmlns:ifc"] = "http://www.ifcopenshell.org/ns"
|
self.svg.attribs["xmlns:ifc"] = "http://www.ifcopenshell.org/ns"
|
||||||
return self
|
return self
|
||||||
@@ -81,7 +81,9 @@ class SvgWriter:
|
|||||||
def draw_underlay(self, image):
|
def draw_underlay(self, image):
|
||||||
self.svg.add(
|
self.svg.add(
|
||||||
self.svg.image(
|
self.svg.image(
|
||||||
os.path.join("..", "diagrams", os.path.basename(image)), width=self.width, height=self.height,
|
os.path.join("..", "diagrams", os.path.basename(image)),
|
||||||
|
width=self.width,
|
||||||
|
height=self.height,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return self
|
return self
|
||||||
@@ -252,7 +254,9 @@ class SvgWriter:
|
|||||||
end = Vector(((x_offset + v1.x), (y_offset - v1.y)))
|
end = Vector(((x_offset + v1.x), (y_offset - v1.y)))
|
||||||
vector = end - start
|
vector = end - start
|
||||||
line = self.svg.add(
|
line = self.svg.add(
|
||||||
self.svg.line(start=tuple(start * self.svg_scale), end=tuple(end * self.svg_scale), class_=" ".join(classes))
|
self.svg.line(
|
||||||
|
start=tuple(start * self.svg_scale), end=tuple(end * self.svg_scale), class_=" ".join(classes)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
line["stroke-dasharray"] = "12.5, 3, 3, 3"
|
line["stroke-dasharray"] = "12.5, 3, 3, 3"
|
||||||
axis_tag = tool.Ifc.get_entity(obj).Name
|
axis_tag = tool.Ifc.get_entity(obj).Name
|
||||||
@@ -361,7 +365,9 @@ class SvgWriter:
|
|||||||
end = Vector(((x_offset + v1.x), (y_offset - v1.y)))
|
end = Vector(((x_offset + v1.x), (y_offset - v1.y)))
|
||||||
vector = end - start
|
vector = end - start
|
||||||
line = self.svg.add(
|
line = self.svg.add(
|
||||||
self.svg.line(start=tuple(start * self.svg_scale), end=tuple(end * self.svg_scale), class_=" ".join(classes))
|
self.svg.line(
|
||||||
|
start=tuple(start * self.svg_scale), end=tuple(end * self.svg_scale), class_=" ".join(classes)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def draw_leader_annotation(self, obj):
|
def draw_leader_annotation(self, obj):
|
||||||
@@ -427,7 +433,9 @@ class SvgWriter:
|
|||||||
(symbol_position * self.svg_scale)[1],
|
(symbol_position * self.svg_scale)[1],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.svg.add(self.svg.use("#elevation-arrow", insert=tuple(symbol_position * self.svg_scale), transform=transform))
|
self.svg.add(
|
||||||
|
self.svg.use("#elevation-arrow", insert=tuple(symbol_position * self.svg_scale), transform=transform)
|
||||||
|
)
|
||||||
self.svg.add(self.svg.use("#elevation-tag", insert=tuple(symbol_position * self.svg_scale)))
|
self.svg.add(self.svg.use("#elevation-tag", insert=tuple(symbol_position * self.svg_scale)))
|
||||||
|
|
||||||
reference_id, sheet_id = self.get_reference_and_sheet_id_from_annotation(tool.Ifc.get_entity(obj))
|
reference_id, sheet_id = self.get_reference_and_sheet_id_from_annotation(tool.Ifc.get_entity(obj))
|
||||||
@@ -666,7 +674,7 @@ class SvgWriter:
|
|||||||
dir2 = ((arc_matrix.inverted() @ arc_end_pts[1]) - (arc_matrix.inverted() @ center)).normalized()
|
dir2 = ((arc_matrix.inverted() @ arc_end_pts[1]) - (arc_matrix.inverted() @ center)).normalized()
|
||||||
angle = -dir1.xy.angle_signed(dir2.xy)
|
angle = -dir1.xy.angle_signed(dir2.xy)
|
||||||
|
|
||||||
#if is_reflex:
|
# if is_reflex:
|
||||||
# angle = angle % (math.pi * 2)
|
# angle = angle % (math.pi * 2)
|
||||||
|
|
||||||
# Center of gravity of all vertices, used to help position the text
|
# Center of gravity of all vertices, used to help position the text
|
||||||
@@ -680,7 +688,9 @@ class SvgWriter:
|
|||||||
arc_midpoint = center + ((cog - center).normalized() * radius)
|
arc_midpoint = center + ((cog - center).normalized() * radius)
|
||||||
|
|
||||||
text_position = self.project_point_onto_camera(arc_midpoint)
|
text_position = self.project_point_onto_camera(arc_midpoint)
|
||||||
text_position = Vector(((x_offset + text_position.x) * self.svg_scale, (y_offset - text_position.y) * self.svg_scale))
|
text_position = Vector(
|
||||||
|
((x_offset + text_position.x) * self.svg_scale, (y_offset - text_position.y) * self.svg_scale)
|
||||||
|
)
|
||||||
|
|
||||||
center_projected = self.project_point_onto_camera(center)
|
center_projected = self.project_point_onto_camera(center)
|
||||||
center_position = Vector(
|
center_position = Vector(
|
||||||
@@ -704,8 +714,12 @@ class SvgWriter:
|
|||||||
|
|
||||||
# Draw SVG arc, see for details: http://xahlee.info/js/svg_circle_arc.html
|
# Draw SVG arc, see for details: http://xahlee.info/js/svg_circle_arc.html
|
||||||
arc_proj_end_pts = [self.project_point_onto_camera(v) for v in arc_end_pts]
|
arc_proj_end_pts = [self.project_point_onto_camera(v) for v in arc_end_pts]
|
||||||
p1 = Vector(((x_offset + arc_proj_end_pts[0].x) * self.svg_scale, (y_offset - arc_proj_end_pts[0].y) * self.svg_scale))
|
p1 = Vector(
|
||||||
p2 = Vector(((x_offset + arc_proj_end_pts[1].x) * self.svg_scale, (y_offset - arc_proj_end_pts[1].y) * self.svg_scale))
|
((x_offset + arc_proj_end_pts[0].x) * self.svg_scale, (y_offset - arc_proj_end_pts[0].y) * self.svg_scale)
|
||||||
|
)
|
||||||
|
p2 = Vector(
|
||||||
|
((x_offset + arc_proj_end_pts[1].x) * self.svg_scale, (y_offset - arc_proj_end_pts[1].y) * self.svg_scale)
|
||||||
|
)
|
||||||
r = radius * self.svg_scale
|
r = radius * self.svg_scale
|
||||||
# reflex = 1 if angle > math.pi else 0
|
# reflex = 1 if angle > math.pi else 0
|
||||||
reflex = is_reflex
|
reflex = is_reflex
|
||||||
@@ -735,10 +749,16 @@ class SvgWriter:
|
|||||||
path = self.svg.add(self.svg.path(d=d, class_=" ".join(classes)))
|
path = self.svg.add(self.svg.path(d=d, class_=" ".join(classes)))
|
||||||
|
|
||||||
p0 = Vector(
|
p0 = Vector(
|
||||||
((x_offset + projected_points[0].x) * self.svg_scale, (y_offset - projected_points[0].y) * self.svg_scale)
|
(
|
||||||
|
(x_offset + projected_points[0].x) * self.svg_scale,
|
||||||
|
(y_offset - projected_points[0].y) * self.svg_scale,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
p1 = Vector(
|
p1 = Vector(
|
||||||
((x_offset + projected_points[1].x) * self.svg_scale, (y_offset - projected_points[1].y) * self.svg_scale)
|
(
|
||||||
|
(x_offset + projected_points[1].x) * self.svg_scale,
|
||||||
|
(y_offset - projected_points[1].y) * self.svg_scale,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
text_offset = (p0 - p1).xy.normalized() * 5
|
text_offset = (p0 - p1).xy.normalized() * 5
|
||||||
text_position = projected_points[0]
|
text_position = projected_points[0]
|
||||||
@@ -823,7 +843,9 @@ class SvgWriter:
|
|||||||
text_position = (mid * self.svg_scale) + perpendicular
|
text_position = (mid * self.svg_scale) + perpendicular
|
||||||
rotation = math.degrees(vector.angle_signed(Vector((1, 0))))
|
rotation = math.degrees(vector.angle_signed(Vector((1, 0))))
|
||||||
line = self.svg.add(
|
line = self.svg.add(
|
||||||
self.svg.line(start=tuple(start * self.svg_scale), end=tuple(end * self.svg_scale), class_=" ".join(classes))
|
self.svg.line(
|
||||||
|
start=tuple(start * self.svg_scale), end=tuple(end * self.svg_scale), class_=" ".join(classes)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
if text_override is not None:
|
if text_override is not None:
|
||||||
text = text_override
|
text = text_override
|
||||||
|
|||||||
@@ -207,7 +207,10 @@ class UpdateRepresentation(bpy.types.Operator):
|
|||||||
new_representation = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
|
new_representation = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
|
||||||
|
|
||||||
if tool.Geometry.is_body_representation(new_representation):
|
if tool.Geometry.is_body_representation(new_representation):
|
||||||
[tool.Geometry.run_style_add_style(obj=mat) for mat in tool.Geometry.get_object_materials_without_styles(obj)]
|
[
|
||||||
|
tool.Geometry.run_style_add_style(obj=mat)
|
||||||
|
for mat in tool.Geometry.get_object_materials_without_styles(obj)
|
||||||
|
]
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"style.assign_representation_styles",
|
"style.assign_representation_styles",
|
||||||
self.file,
|
self.file,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy.types import Panel
|
from bpy.types import Panel
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.ui import prop_with_search
|
from blenderbim.bim.helper import prop_with_search
|
||||||
from blenderbim.bim.module.geometry.data import RepresentationsData, DerivedPlacementsData
|
from blenderbim.bim.module.geometry.data import RepresentationsData, DerivedPlacementsData
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,9 @@ class ObjectMaterialData:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def materials(cls):
|
def materials(cls):
|
||||||
return sorted([(str(m.id()), m.Name or "Unnamed", "") for m in tool.Ifc.get().by_type("IfcMaterial")], key=lambda x: x[1])
|
return sorted(
|
||||||
|
[(str(m.id()), m.Name or "Unnamed", "") for m in tool.Ifc.get().by_type("IfcMaterial")], key=lambda x: x[1]
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def type_material(cls):
|
def type_material(cls):
|
||||||
|
|||||||
@@ -137,3 +137,5 @@ class BIMObjectMaterialProperties(PropertyGroup):
|
|||||||
parameterized_profile_classes: EnumProperty(
|
parameterized_profile_classes: EnumProperty(
|
||||||
items=getParameterizedProfileClasses, name="Parameterized Profile Classes"
|
items=getParameterizedProfileClasses, name="Parameterized Profile Classes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
getter_enum = {"material": get_materials}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from ifcopenshell.api.material.data import Data
|
|||||||
from ifcopenshell.api.profile.data import Data as ProfileData
|
from ifcopenshell.api.profile.data import Data as ProfileData
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.helper import draw_attributes
|
from blenderbim.bim.helper import draw_attributes
|
||||||
|
from blenderbim.bim.helper import prop_with_search
|
||||||
from blenderbim.bim.module.material.data import MaterialsData, ObjectMaterialData
|
from blenderbim.bim.module.material.data import MaterialsData, ObjectMaterialData
|
||||||
|
|
||||||
|
|
||||||
@@ -190,7 +191,7 @@ class BIM_PT_object_material(Panel):
|
|||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(self.props, "material_type", text="")
|
row.prop(self.props, "material_type", text="")
|
||||||
if self.props.material_type == "IfcMaterial" or self.props.material_type == "IfcMaterialList":
|
if self.props.material_type == "IfcMaterial" or self.props.material_type == "IfcMaterialList":
|
||||||
row.prop(self.props, "material", text="")
|
prop_with_search(row, self.props, "material", text="")
|
||||||
row.operator("bim.assign_material", icon="ADD", text="")
|
row.operator("bim.assign_material", icon="ADD", text="")
|
||||||
|
|
||||||
def draw_material_ui(self):
|
def draw_material_ui(self):
|
||||||
@@ -220,8 +221,7 @@ class BIM_PT_object_material(Panel):
|
|||||||
return self.draw_read_only_single_ui()
|
return self.draw_read_only_single_ui()
|
||||||
|
|
||||||
def draw_editable_single_ui(self):
|
def draw_editable_single_ui(self):
|
||||||
row = self.layout.row(align=True)
|
prop_with_search(self.layout, self.props, "material", text="")
|
||||||
row.prop(self.props, "material", text="")
|
|
||||||
|
|
||||||
def draw_read_only_single_ui(self):
|
def draw_read_only_single_ui(self):
|
||||||
material = Data.materials[self.product_data["id"]]
|
material = Data.materials[self.product_data["id"]]
|
||||||
@@ -242,7 +242,7 @@ class BIM_PT_object_material(Panel):
|
|||||||
row.prop(attribute, "string_value", text=attribute.name)
|
row.prop(attribute, "string_value", text=attribute.name)
|
||||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(self.props, "material", text="")
|
prop_with_search(row, self.props, "material", text="")
|
||||||
|
|
||||||
op = row.operator(f"bim.add_{self.set_item_name}", icon="ADD", text="")
|
op = row.operator(f"bim.add_{self.set_item_name}", icon="ADD", text="")
|
||||||
setattr(op, f"{self.set_item_name}_set", self.material_set_id)
|
setattr(op, f"{self.set_item_name}_set", self.material_set_id)
|
||||||
|
|||||||
@@ -65,14 +65,14 @@ class MepGenerator:
|
|||||||
|
|
||||||
def create_rectangle_segment(self):
|
def create_rectangle_segment(self):
|
||||||
verts = [
|
verts = [
|
||||||
Vector((- self.width / 2, self.height / 2, 0)),
|
Vector((-self.width / 2, self.height / 2, 0)),
|
||||||
Vector((- self.width / 2, - self.height / 2, 0)),
|
Vector((-self.width / 2, -self.height / 2, 0)),
|
||||||
Vector((- self.width / 2, self.height / 2, self.length)),
|
Vector((-self.width / 2, self.height / 2, self.length)),
|
||||||
Vector((- self.width / 2, - self.height / 2, self.length)),
|
Vector((-self.width / 2, -self.height / 2, self.length)),
|
||||||
Vector((self.width / 2, self.height / 2, 0)),
|
Vector((self.width / 2, self.height / 2, 0)),
|
||||||
Vector((self.width / 2, - self.height / 2, 0)),
|
Vector((self.width / 2, -self.height / 2, 0)),
|
||||||
Vector((self.width / 2, self.height / 2, self.length)),
|
Vector((self.width / 2, self.height / 2, self.length)),
|
||||||
Vector((self.width / 2, - self.height / 2, self.length)),
|
Vector((self.width / 2, -self.height / 2, self.length)),
|
||||||
]
|
]
|
||||||
faces = [
|
faces = [
|
||||||
[1, 3, 2, 0],
|
[1, 3, 2, 0],
|
||||||
|
|||||||
@@ -121,9 +121,7 @@ class AddTypeInstance(bpy.types.Operator):
|
|||||||
collection_obj = bpy.data.objects.get(collection.name)
|
collection_obj = bpy.data.objects.get(collection.name)
|
||||||
bpy.ops.bim.assign_class(obj=obj.name, ifc_class=instance_class)
|
bpy.ops.bim.assign_class(obj=obj.name, ifc_class=instance_class)
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
blenderbim.core.type.assign_type(
|
blenderbim.core.type.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type)
|
||||||
tool.Ifc, tool.Type, element=element, type=relating_type
|
|
||||||
)
|
|
||||||
|
|
||||||
if building_obj:
|
if building_obj:
|
||||||
if instance_class in ["IfcWindow", "IfcDoor"]:
|
if instance_class in ["IfcWindow", "IfcDoor"]:
|
||||||
|
|||||||
@@ -253,10 +253,7 @@ class ObjectActorData:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def load(cls):
|
def load(cls):
|
||||||
cls.is_loaded = True
|
cls.is_loaded = True
|
||||||
cls.data = {
|
cls.data = {"actor": cls.actor(), "actors": cls.actors()}
|
||||||
"actor": cls.actor(),
|
|
||||||
"actors": cls.actors()
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def actor(cls):
|
def actor(cls):
|
||||||
@@ -279,9 +276,9 @@ class ObjectActorData:
|
|||||||
roles = cls.get_roles(actor.TheActor.ThePerson)
|
roles = cls.get_roles(actor.TheActor.ThePerson)
|
||||||
roles.extend(cls.get_roles(actor.TheActor.TheOrganization))
|
roles.extend(cls.get_roles(actor.TheActor.TheOrganization))
|
||||||
role = ", ".join(roles)
|
role = ", ".join(roles)
|
||||||
results.append({
|
results.append(
|
||||||
"id": actor.id(), "name": actor.Name or "Unnamed", "role": role, "ifc_class": actor.is_a()
|
{"id": actor.id(), "name": actor.Name or "Unnamed", "role": role, "ifc_class": actor.is_a()}
|
||||||
})
|
)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from blenderbim.bim.ui import prop_with_search
|
from blenderbim.bim.helper import prop_with_search
|
||||||
import bpy
|
import bpy
|
||||||
from blenderbim.bim.helper import draw_attributes
|
from blenderbim.bim.helper import draw_attributes
|
||||||
|
|
||||||
|
|||||||
@@ -732,7 +732,7 @@ class ToggleLinkVisibility(bpy.types.Operator):
|
|||||||
|
|
||||||
def toggle_wireframe(self, link):
|
def toggle_wireframe(self, link):
|
||||||
objs = filter(lambda obj: "IfcOpeningElement" not in obj.name, link.collection.all_objects)
|
objs = filter(lambda obj: "IfcOpeningElement" not in obj.name, link.collection.all_objects)
|
||||||
for i,obj in enumerate(objs):
|
for i, obj in enumerate(objs):
|
||||||
if i == 0:
|
if i == 0:
|
||||||
if obj.display_type == "WIRE":
|
if obj.display_type == "WIRE":
|
||||||
display_type = "TEXTURED"
|
display_type = "TEXTURED"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from blenderbim.bim.ui import prop_with_search
|
from blenderbim.bim.helper import prop_with_search
|
||||||
from bpy.types import Panel, UIList
|
from bpy.types import Panel, UIList
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.module.project.data import ProjectData
|
from blenderbim.bim.module.project.data import ProjectData
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ classes = (
|
|||||||
operator.BIM_OT_rename_parameters,
|
operator.BIM_OT_rename_parameters,
|
||||||
operator.BIM_OT_add_edit_custom_property,
|
operator.BIM_OT_add_edit_custom_property,
|
||||||
operator.BIM_OT_bulk_remove_psets,
|
operator.BIM_OT_bulk_remove_psets,
|
||||||
prop.EnumerationValues,
|
prop.IfcPropertyEnumeratedValue,
|
||||||
prop.IfcSimpleProperty,
|
prop.IfcProperty,
|
||||||
prop.PsetProperties,
|
prop.PsetProperties,
|
||||||
prop.MaterialPsetProperties,
|
prop.MaterialPsetProperties,
|
||||||
prop.TaskPsetProperties,
|
prop.TaskPsetProperties,
|
||||||
|
|||||||
@@ -122,85 +122,91 @@ class EnablePsetEditing(bpy.types.Operator):
|
|||||||
for prop_template in pset_template.HasPropertyTemplates:
|
for prop_template in pset_template.HasPropertyTemplates:
|
||||||
if not prop_template.is_a("IfcSimplePropertyTemplate"):
|
if not prop_template.is_a("IfcSimplePropertyTemplate"):
|
||||||
continue # Other types not yet supported
|
continue # Other types not yet supported
|
||||||
|
|
||||||
if prop_template.TemplateType == "P_SINGLEVALUE":
|
if prop_template.TemplateType == "P_SINGLEVALUE":
|
||||||
try:
|
self.load_single_value(prop_template, data)
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(
|
|
||||||
IfcStore.get_schema().declaration_by_name(prop_template.PrimaryMeasureType or "IfcLabel")
|
|
||||||
)
|
|
||||||
except:
|
|
||||||
# TODO: Occurs if the data type is something that exists in
|
|
||||||
# IFC4 and not in IFC2X3. To fully fix this we need to
|
|
||||||
# generate the IFC2X3 pset template definitions.
|
|
||||||
continue
|
|
||||||
elif prop_template.TemplateType in ["Q_LENGTH", "Q_AREA", "Q_VOLUME", "Q_WEIGHT", "Q_TIME"]:
|
|
||||||
data_type = "float"
|
|
||||||
elif prop_template.TemplateType == "Q_COUNT":
|
|
||||||
data_type = "integer"
|
|
||||||
elif prop_template.TemplateType == "P_ENUMERATEDVALUE":
|
elif prop_template.TemplateType == "P_ENUMERATEDVALUE":
|
||||||
enum_items = [v.wrappedValue for v in prop_template.Enumerators.EnumerationValues]
|
self.load_enumerated_value(prop_template, data)
|
||||||
#selected_enum_items = [e.EnumerationValues.wrappedValue for e in Data.properties[e]]
|
|
||||||
data_type = ""
|
|
||||||
else:
|
|
||||||
continue # Other types not yet supported
|
|
||||||
|
|
||||||
new = self.props.properties.add()
|
def load_single_value(self, prop_template, data):
|
||||||
new.name = prop_template.Name
|
try:
|
||||||
new.is_null = data.get(prop_template.Name, None) is None
|
data_type = ifcopenshell.util.attribute.get_primitive_type(
|
||||||
new.is_optional = True
|
IfcStore.get_schema().declaration_by_name(prop_template.PrimaryMeasureType or "IfcLabel")
|
||||||
new.is_uri = prop_template.PrimaryMeasureType == "IfcURIReference"
|
)
|
||||||
new.data_type = data_type
|
except:
|
||||||
|
# TODO: Occurs if the data type is something that exists in
|
||||||
if data_type == "string":
|
# IFC4 and not in IFC2X3. To fully fix this we need to
|
||||||
new.string_value = "" if new.is_null else data[prop_template.Name]
|
# generate the IFC2X3 pset template definitions.
|
||||||
elif data_type == "integer":
|
return
|
||||||
new.int_value = 0 if new.is_null else data[prop_template.Name]
|
|
||||||
elif data_type == "float":
|
|
||||||
new.float_value = 0.0 if new.is_null else data[prop_template.Name]
|
|
||||||
elif data_type == "boolean":
|
|
||||||
new.bool_value = False if new.is_null else data[prop_template.Name]
|
|
||||||
if prop_template.TemplateType == "P_ENUMERATEDVALUE":
|
|
||||||
|
|
||||||
new.set_value(prop_template.Enumerators.EnumerationValues[0].wrappedValue)
|
prop = self.props.properties.add()
|
||||||
|
prop.value_type = "IfcPropertySingleValue"
|
||||||
for enum in enum_items:
|
metadata = prop.metadata
|
||||||
new_enum = new.enumerated_values.add()
|
metadata.name = prop_template.Name
|
||||||
data_type = new.get_value_name()
|
metadata.is_null = data.get(prop_template.Name, None) is None
|
||||||
setattr(new_enum, data_type, enum)
|
metadata.is_optional = True
|
||||||
if data.get(prop_template.Name):
|
metadata.is_uri = prop_template.PrimaryMeasureType == "IfcURIReference"
|
||||||
new_enum.is_selected = enum in data[prop_template.Name]
|
metadata.data_type = data_type
|
||||||
|
|
||||||
|
if data_type == "string":
|
||||||
|
metadata.string_value = "" if metadata.is_null else data[prop_template.Name]
|
||||||
|
elif data_type == "integer":
|
||||||
|
metadata.int_value = 0 if metadata.is_null else data[prop_template.Name]
|
||||||
|
elif data_type == "float":
|
||||||
|
metadata.float_value = 0.0 if metadata.is_null else data[prop_template.Name]
|
||||||
|
elif data_type == "boolean":
|
||||||
|
metadata.bool_value = False if metadata.is_null else data[prop_template.Name]
|
||||||
|
|
||||||
|
def load_enumerated_value(self, prop_template, data):
|
||||||
|
enum_items = [v.wrappedValue for v in prop_template.Enumerators.EnumerationValues]
|
||||||
|
selected_enum_items = data.get(prop_template.Name, [])
|
||||||
|
|
||||||
|
prop = self.props.properties.add()
|
||||||
|
prop.value_type = "IfcPropertyEnumeratedValue"
|
||||||
|
metadata = prop.metadata
|
||||||
|
metadata.name = prop_template.Name
|
||||||
|
metadata.is_null = data.get(prop_template.Name, None) is None
|
||||||
|
metadata.is_optional = True
|
||||||
|
metadata.is_uri = prop_template.PrimaryMeasureType == "IfcURIReference"
|
||||||
|
|
||||||
|
# Cute hack to abuse the metadata to find the Blender data_type
|
||||||
|
metadata.set_value(enum_items[0])
|
||||||
|
data_type = metadata.get_value_name()
|
||||||
|
|
||||||
|
for enum in enum_items:
|
||||||
|
new = prop.enumerated_value.enumerated_values.add()
|
||||||
|
setattr(new, data_type, enum)
|
||||||
|
new.is_selected = enum in selected_enum_items
|
||||||
|
|
||||||
def load_from_pset_data(self, pset_data):
|
def load_from_pset_data(self, pset_data):
|
||||||
for prop_id in pset_data["Properties"]:
|
for prop_id in pset_data["Properties"]:
|
||||||
prop = Data.properties[prop_id]
|
prop = Data.properties[prop_id]
|
||||||
|
|
||||||
if prop["type"] == "IfcPropertyEnumeratedValue":
|
if prop["type"] == "IfcPropertyEnumeratedValue":
|
||||||
new = self.props.properties.add()
|
simple_prop = self.props.properties.add()
|
||||||
new.name = prop["Name"]
|
simple_prop.value_type = "IfcPropertyEnumeratedValue"
|
||||||
new.is_null = new.enumerated_values is None
|
metadata = simple_prop.metadata
|
||||||
new.is_optional = True
|
metadata.name = prop["Name"]
|
||||||
new.set_value(prop["EnumerationReference"].EnumerationValues[0].wrappedValue)
|
metadata.is_null = len(simple_prop.enumerated_value.enumerated_values) == 0
|
||||||
|
metadata.is_optional = True
|
||||||
enum_ref = [v.wrappedValue for v in prop["EnumerationReference"].EnumerationValues]
|
metadata.set_value(prop["EnumerationReference"].EnumerationValues[0].wrappedValue)
|
||||||
enum_vals = [v.wrappedValue for v in prop["EnumerationValues"]]
|
|
||||||
for enum in enum_ref:
|
enum_items = [v.wrappedValue for v in prop["EnumerationReference"].EnumerationValues]
|
||||||
new_enum = new.enumerated_values.add()
|
selected_enum_items = [v.wrappedValue for v in prop["EnumerationValues"]]
|
||||||
data_type = new.get_value_name()
|
data_type = metadata.get_value_name()
|
||||||
setattr(new_enum, data_type, enum)
|
|
||||||
if enum in enum_vals:
|
for enum in enum_items:
|
||||||
new_enum.is_selected = True
|
new = simple_prop.enumerated_value.enumerated_values.add()
|
||||||
else:
|
setattr(new, data_type, enum)
|
||||||
new_enum.is_selected = False
|
new.is_selected = enum in selected_enum_items
|
||||||
|
|
||||||
else:
|
else:
|
||||||
value = prop["NominalValue"]
|
value = prop["NominalValue"]
|
||||||
new = self.props.properties.add()
|
prop = self.props.properties.add()
|
||||||
new.set_value(value)
|
metadata = prop.metadata
|
||||||
new.name = prop["Name"]
|
metadata.set_value(value)
|
||||||
new.is_null = value is None
|
metadata.name = prop["Name"]
|
||||||
new.is_optional = True
|
metadata.is_null = value is None
|
||||||
new.set_value(new.get_value_default() if new.is_null else value)
|
metadata.is_optional = True
|
||||||
|
metadata.set_value(metadata.get_value_default() if metadata.is_null else value)
|
||||||
|
|
||||||
|
|
||||||
class DisablePsetEditing(bpy.types.Operator, Operator):
|
class DisablePsetEditing(bpy.types.Operator, Operator):
|
||||||
@@ -236,11 +242,13 @@ class EditPset(bpy.types.Operator, Operator):
|
|||||||
else:
|
else:
|
||||||
data = Data.psets if pset_id in Data.psets else Data.qtos
|
data = Data.psets if pset_id in Data.psets else Data.qtos
|
||||||
for prop in props.properties:
|
for prop in props.properties:
|
||||||
if len(prop.enumerated_values) != 0:
|
if prop.value_type == "IfcPropertySingleValue":
|
||||||
value_name = prop.get_value_name()
|
properties[prop.metadata.name] = prop.metadata.get_value()
|
||||||
properties[prop.name] = [e[value_name] for e in prop.enumerated_values if e.is_selected]
|
elif prop.value_type == "IfcPropertyEnumeratedValue":
|
||||||
else:
|
value_name = prop.metadata.get_value_name()
|
||||||
properties[prop.name] = prop.get_value()
|
properties[prop.metadata.name] = [
|
||||||
|
e[value_name] for e in prop.enumerated_value.enumerated_values if e.is_selected
|
||||||
|
]
|
||||||
|
|
||||||
if pset_id in Data.psets:
|
if pset_id in Data.psets:
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
@@ -507,15 +515,15 @@ class BIM_OT_add_edit_custom_property(bpy.types.Operator):
|
|||||||
continue
|
continue
|
||||||
ifc_element = tool.Ifc.get().by_id(ifc_definition_id)
|
ifc_element = tool.Ifc.get().by_id(ifc_definition_id)
|
||||||
|
|
||||||
for prop in props:
|
for prop in props:
|
||||||
value = getattr(prop, prop.get_value_name())
|
value = getattr(prop, prop.get_value_name())
|
||||||
primary_measure_type = prop.primary_measure_type
|
primary_measure_type = prop.primary_measure_type
|
||||||
|
|
||||||
if prop.template_type == "IfcPropertyEnumeratedValue":
|
if prop.template_type == "IfcPropertyEnumeratedValue":
|
||||||
value_ifc_entity = self.generate_enum_entity(prop)
|
value_ifc_entity = self.generate_enum_entity(prop)
|
||||||
elif prop.template_type == "IfcPropertySingleValue":
|
elif prop.template_type == "IfcPropertySingleValue":
|
||||||
value_ifc_entity = getattr(self.file, f"create{primary_measure_type}")(value)
|
value_ifc_entity = getattr(self.file, f"create{primary_measure_type}")(value)
|
||||||
|
|
||||||
new_pset = ifcopenshell.api.run("pset.add_pset", self.file, product=ifc_element, name=prop.pset_name)
|
new_pset = ifcopenshell.api.run("pset.add_pset", self.file, product=ifc_element, name=prop.pset_name)
|
||||||
ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"pset.edit_pset", self.file, pset=new_pset, properties={prop.property_name: value_ifc_entity}
|
"pset.edit_pset", self.file, pset=new_pset, properties={prop.property_name: value_ifc_entity}
|
||||||
@@ -523,22 +531,26 @@ class BIM_OT_add_edit_custom_property(bpy.types.Operator):
|
|||||||
Data.load(IfcStore.get_file(), ifc_definition_id)
|
Data.load(IfcStore.get_file(), ifc_definition_id)
|
||||||
self.report({"INFO"}, "Finished applying changes")
|
self.report({"INFO"}, "Finished applying changes")
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def generate_enum_entity(self, prop):
|
def generate_enum_entity(self, prop):
|
||||||
prop_type = prop.get_value_name()
|
prop_type = prop.get_value_name()
|
||||||
prop_enum = self.file.create_entity(
|
prop_enum = self.file.create_entity(
|
||||||
"IFCPROPERTYENUMERATION",
|
"IFCPROPERTYENUMERATION",
|
||||||
Name=prop.property_name,
|
Name=prop.property_name,
|
||||||
EnumerationValues=tuple(self.file.create_entity(
|
EnumerationValues=tuple(
|
||||||
prop.primary_measure_type, ev[prop_type]) for ev in prop.enum_values)
|
self.file.create_entity(prop.primary_measure_type, ev[prop_type]) for ev in prop.enum_values
|
||||||
)
|
),
|
||||||
|
)
|
||||||
prop_enum_value = self.file.create_entity(
|
prop_enum_value = self.file.create_entity(
|
||||||
"IFCPROPERTYENUMERATEDVALUE",
|
"IFCPROPERTYENUMERATEDVALUE",
|
||||||
Name=prop.property_name,
|
Name=prop.property_name,
|
||||||
EnumerationValues=tuple(self.file.create_entity(
|
EnumerationValues=tuple(
|
||||||
prop.primary_measure_type, ev[prop_type]) for ev in prop.enum_values if ev.is_selected == True),
|
self.file.create_entity(prop.primary_measure_type, ev[prop_type])
|
||||||
EnumerationReference=prop_enum
|
for ev in prop.enum_values
|
||||||
)
|
if ev.is_selected == True
|
||||||
|
),
|
||||||
|
EnumerationReference=prop_enum,
|
||||||
|
)
|
||||||
return prop_enum_value
|
return prop_enum_value
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -139,26 +139,22 @@ def get_primary_measure_type(self, context):
|
|||||||
return AddEditCustomPropertiesData.data["primary_measure_type"]
|
return AddEditCustomPropertiesData.data["primary_measure_type"]
|
||||||
|
|
||||||
|
|
||||||
class EnumerationValues(PropertyGroup):
|
class IfcPropertyEnumeratedValue(PropertyGroup):
|
||||||
string_value: StringProperty(name="Value")
|
enumerated_values: CollectionProperty(type=Attribute)
|
||||||
bool_value: BoolProperty(name="Value")
|
|
||||||
int_value: IntProperty(name="Value")
|
|
||||||
float_value: FloatProperty(name="Value")
|
|
||||||
is_selected: BoolProperty(default=False)
|
|
||||||
|
|
||||||
|
|
||||||
class IfcSimpleProperty(Attribute):
|
class IfcProperty(PropertyGroup):
|
||||||
# bounded_values:
|
metadata: PointerProperty(type=Attribute)
|
||||||
enumerated_values: CollectionProperty(type=EnumerationValues)
|
value_type: EnumProperty(
|
||||||
# list_values:
|
items=[(v, v, v) for v in ("IfcPropertySingleValue", "IfcPropertyEnumeratedValue")], name="Value Type"
|
||||||
# reference_values:
|
)
|
||||||
# table_values:
|
enumerated_value: PointerProperty(type=IfcPropertyEnumeratedValue)
|
||||||
|
|
||||||
|
|
||||||
class PsetProperties(PropertyGroup):
|
class PsetProperties(PropertyGroup):
|
||||||
active_pset_id: IntProperty(name="Active Pset ID")
|
active_pset_id: IntProperty(name="Active Pset ID")
|
||||||
active_pset_name: StringProperty(name="Pset Name")
|
active_pset_name: StringProperty(name="Pset Name")
|
||||||
properties: CollectionProperty(name="Properties", type=IfcSimpleProperty)
|
properties: CollectionProperty(name="Properties", type=IfcProperty)
|
||||||
pset_name: EnumProperty(items=get_pset_names, name="Pset Name")
|
pset_name: EnumProperty(items=get_pset_names, name="Pset Name")
|
||||||
qto_name: EnumProperty(items=get_qto_names, name="Qto Name")
|
qto_name: EnumProperty(items=get_qto_names, name="Qto Name")
|
||||||
|
|
||||||
@@ -225,7 +221,7 @@ class AddEditProperties(PropertyGroup):
|
|||||||
],
|
],
|
||||||
name="Template Type",
|
name="Template Type",
|
||||||
)
|
)
|
||||||
enum_values: CollectionProperty(name="Enum Values", type=EnumerationValues)
|
enum_values: CollectionProperty(name="Enum Values", type=Attribute)
|
||||||
|
|
||||||
getter_enum = {
|
getter_enum = {
|
||||||
"primary_measure_type": get_primary_measure_type,
|
"primary_measure_type": get_primary_measure_type,
|
||||||
|
|||||||
@@ -18,8 +18,7 @@
|
|||||||
|
|
||||||
from bpy.types import Panel
|
from bpy.types import Panel
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.ui import prop_with_search
|
from blenderbim.bim.helper import prop_with_search
|
||||||
from blenderbim.bim.helper import draw_attribute
|
|
||||||
from blenderbim.bim.module.pset.data import (
|
from blenderbim.bim.module.pset.data import (
|
||||||
ObjectPsetsData,
|
ObjectPsetsData,
|
||||||
ObjectQtosData,
|
ObjectQtosData,
|
||||||
@@ -32,6 +31,45 @@ from blenderbim.bim.module.pset.data import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_property(prop, layout, copy_operator=None):
|
||||||
|
if prop.value_type == "IfcPropertySingleValue":
|
||||||
|
draw_single_property(prop, layout, copy_operator)
|
||||||
|
elif prop.value_type == "IfcPropertyEnumeratedValue":
|
||||||
|
draw_enumerated_property(prop, layout, copy_operator)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_single_property(prop, layout, copy_operator=None):
|
||||||
|
value_name = prop.metadata.get_value_name()
|
||||||
|
if not value_name:
|
||||||
|
layout.label(text=prop.metadata.name)
|
||||||
|
return
|
||||||
|
layout.prop(
|
||||||
|
prop.metadata,
|
||||||
|
value_name,
|
||||||
|
text=prop.metadata.name,
|
||||||
|
)
|
||||||
|
if prop.metadata.is_optional:
|
||||||
|
layout.prop(prop.metadata, "is_null", icon="RADIOBUT_OFF" if prop.metadata.is_null else "RADIOBUT_ON", text="")
|
||||||
|
if copy_operator:
|
||||||
|
op = layout.operator(f"{copy_operator}", text="", icon="COPYDOWN")
|
||||||
|
op.name = prop.metadata.name
|
||||||
|
if prop.metadata.is_uri:
|
||||||
|
op = layout.operator("bim.select_uri_prop", text="", icon="FILE_FOLDER")
|
||||||
|
op.data_path = prop.metadata.path_from_id("string_value")
|
||||||
|
|
||||||
|
|
||||||
|
def draw_enumerated_property(prop, layout, copy_operator=None):
|
||||||
|
value_name = prop.metadata.get_value_name()
|
||||||
|
if not value_name:
|
||||||
|
layout.label(text=prop.metadata.name)
|
||||||
|
return
|
||||||
|
if len(prop.enumerated_value.enumerated_values) != 0:
|
||||||
|
layout.label(text=prop.metadata.name)
|
||||||
|
grid = layout.column_flow(columns=3)
|
||||||
|
for e in prop.enumerated_value.enumerated_values:
|
||||||
|
grid.prop(e, "is_selected", text=str(e[value_name]))
|
||||||
|
|
||||||
|
|
||||||
def get_active_pset_obj_name(context, obj_type):
|
def get_active_pset_obj_name(context, obj_type):
|
||||||
if obj_type == "Object":
|
if obj_type == "Object":
|
||||||
return context.active_object.name
|
return context.active_object.name
|
||||||
@@ -96,7 +134,7 @@ def draw_psetqto_ui(context, pset_id, pset, props, layout, obj_type):
|
|||||||
|
|
||||||
def draw_psetqto_editable_ui(box, props, prop):
|
def draw_psetqto_editable_ui(box, props, prop):
|
||||||
row = box.row(align=True)
|
row = box.row(align=True)
|
||||||
draw_attribute(prop, row, copy_operator="bim.copy_property_to_selection")
|
draw_property(prop, row, copy_operator="bim.copy_property_to_selection")
|
||||||
if (
|
if (
|
||||||
"length" in prop.name.lower()
|
"length" in prop.name.lower()
|
||||||
or "width" in prop.name.lower()
|
or "width" in prop.name.lower()
|
||||||
|
|||||||
@@ -28,31 +28,31 @@ from ifcopenshell.api.pset_template.data import Data
|
|||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
|
|
||||||
|
|
||||||
#This is just a temporary operator until
|
# This is just a temporary operator until
|
||||||
#@Moult performs some of his refactor-magic ;) - vulevukusej
|
# @Moult performs some of his refactor-magic ;) - vulevukusej
|
||||||
class RefreshPsetTemplates(bpy.types.Operator):
|
class RefreshPsetTemplates(bpy.types.Operator):
|
||||||
bl_idname = "bim.refresh_psettemplates"
|
bl_idname = "bim.refresh_psettemplates"
|
||||||
bl_label = "Refresh the data for PsetTemplates"
|
bl_label = "Refresh the data for PsetTemplates"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
purge_templates()
|
purge_templates()
|
||||||
purge_psets()
|
purge_psets()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class AddPsetFile(bpy.types.Operator):
|
class AddPsetFile(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_pset_file"
|
bl_idname = "bim.add_pset_file"
|
||||||
bl_label = "Add Pset File"
|
bl_label = "Add Pset File"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
return context.window_manager.invoke_props_dialog(self, width=250)
|
return context.window_manager.invoke_props_dialog(self, width=250)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
self.props = context.scene.BIMPsetTemplateProperties
|
self.props = context.scene.BIMPsetTemplateProperties
|
||||||
self.layout.prop(self.props, "new_template_filename", text="Filename:")
|
self.layout.prop(self.props, "new_template_filename", text="Filename:")
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
template = ifcopenshell.file()
|
template = ifcopenshell.file()
|
||||||
filepath = os.path.join(
|
filepath = os.path.join(
|
||||||
@@ -60,7 +60,7 @@ class AddPsetFile(bpy.types.Operator):
|
|||||||
"pset",
|
"pset",
|
||||||
self.props.new_template_filename + ".ifc",
|
self.props.new_template_filename + ".ifc",
|
||||||
)
|
)
|
||||||
|
|
||||||
template.create_entity(
|
template.create_entity(
|
||||||
"IFCPROPERTYSETTEMPLATE",
|
"IFCPROPERTYSETTEMPLATE",
|
||||||
**{
|
**{
|
||||||
@@ -68,14 +68,14 @@ class AddPsetFile(bpy.types.Operator):
|
|||||||
"Name": "Name",
|
"Name": "Name",
|
||||||
"Description": "Description",
|
"Description": "Description",
|
||||||
"TemplateType": "PSET_TYPEDRIVENONLY",
|
"TemplateType": "PSET_TYPEDRIVENONLY",
|
||||||
"ApplicableEntity": "IfcTypeObject"
|
"ApplicableEntity": "IfcTypeObject",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
template.write(filepath)
|
template.write(filepath)
|
||||||
self.props.new_template_filename = ""
|
self.props.new_template_filename = ""
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class AddPsetTemplate(bpy.types.Operator):
|
class AddPsetTemplate(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_pset_template"
|
bl_idname = "bim.add_pset_template"
|
||||||
bl_label = "Add Pset Template"
|
bl_label = "Add Pset Template"
|
||||||
@@ -190,33 +190,35 @@ class EnableEditingPropTemplate(bpy.types.Operator):
|
|||||||
props.active_prop_template.primary_measure_type = template["PrimaryMeasureType"]
|
props.active_prop_template.primary_measure_type = template["PrimaryMeasureType"]
|
||||||
props.active_prop_template.template_type = template["TemplateType"]
|
props.active_prop_template.template_type = template["TemplateType"]
|
||||||
props.active_prop_template.enum_values.clear()
|
props.active_prop_template.enum_values.clear()
|
||||||
|
|
||||||
if template["Enumerators"]:
|
if template["Enumerators"]:
|
||||||
props.active_prop_template.enum_values.clear()
|
props.active_prop_template.enum_values.clear()
|
||||||
data_type = props.active_prop_template.get_value_name()
|
data_type = props.active_prop_template.get_value_name()
|
||||||
for e in template["Enumerators"].EnumerationValues:
|
for e in template["Enumerators"].EnumerationValues:
|
||||||
new = props.active_prop_template.enum_values.add()
|
new = props.active_prop_template.enum_values.add()
|
||||||
setattr(new, data_type, e.wrappedValue)
|
setattr(new, data_type, e.wrappedValue)
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class DeletePropEnum(bpy.types.Operator):
|
class DeletePropEnum(bpy.types.Operator):
|
||||||
bl_idname = "bim.delete_prop_enum"
|
bl_idname = "bim.delete_prop_enum"
|
||||||
bl_label = "delete property enumeration"
|
bl_label = "delete property enumeration"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
index: bpy.props.IntProperty()
|
index: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
active_prop = context.scene.BIMPsetTemplateProperties.active_prop_template
|
active_prop = context.scene.BIMPsetTemplateProperties.active_prop_template
|
||||||
active_prop.enum_values.remove(self.index)
|
active_prop.enum_values.remove(self.index)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class AddPropEnum(bpy.types.Operator):
|
class AddPropEnum(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_prop_enum"
|
bl_idname = "bim.add_prop_enum"
|
||||||
bl_label = "add property enumeration"
|
bl_label = "add property enumeration"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
index: bpy.props.IntProperty()
|
index: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
active_prop = context.scene.BIMPsetTemplateProperties.active_prop_template
|
active_prop = context.scene.BIMPsetTemplateProperties.active_prop_template
|
||||||
active_prop.enum_values.add()
|
active_prop.enum_values.add()
|
||||||
@@ -380,26 +382,27 @@ class EditPropTemplate(bpy.types.Operator):
|
|||||||
"Description": props.active_prop_template.description,
|
"Description": props.active_prop_template.description,
|
||||||
"PrimaryMeasureType": props.active_prop_template.primary_measure_type,
|
"PrimaryMeasureType": props.active_prop_template.primary_measure_type,
|
||||||
"TemplateType": props.active_prop_template.template_type,
|
"TemplateType": props.active_prop_template.template_type,
|
||||||
"Enumerators": enumerator
|
"Enumerators": enumerator,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
Data.load(IfcStore.pset_template_file)
|
Data.load(IfcStore.pset_template_file)
|
||||||
bpy.ops.bim.disable_editing_prop_template()
|
bpy.ops.bim.disable_editing_prop_template()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
#TODO -This will need to go into the
|
# TODO -This will need to go into the
|
||||||
# api code at some point - vulevukusej
|
# api code at some point - vulevukusej
|
||||||
def generate_prop_enum(self, props):
|
def generate_prop_enum(self, props):
|
||||||
self.file = IfcStore.pset_template_file
|
self.file = IfcStore.pset_template_file
|
||||||
data_type = props.active_prop_template.get_value_name()
|
data_type = props.active_prop_template.get_value_name()
|
||||||
prop = props.active_prop_template
|
prop = props.active_prop_template
|
||||||
prop_enum = self.file.create_entity(
|
prop_enum = self.file.create_entity(
|
||||||
"IFCPROPERTYENUMERATION",
|
"IFCPROPERTYENUMERATION",
|
||||||
Name=prop.name,
|
Name=prop.name,
|
||||||
EnumerationValues=tuple(self.file.create_entity(
|
EnumerationValues=tuple(
|
||||||
prop.primary_measure_type, ev[data_type]) for ev in prop.enum_values)
|
self.file.create_entity(prop.primary_measure_type, ev[data_type]) for ev in prop.enum_values
|
||||||
)
|
),
|
||||||
|
)
|
||||||
return prop_enum
|
return prop_enum
|
||||||
|
|
||||||
def rollback(self, data):
|
def rollback(self, data):
|
||||||
|
|||||||
@@ -94,83 +94,84 @@ def get_primary_measure_type(self, context):
|
|||||||
return PsetTemplatesData.data["primary_measure_type"]
|
return PsetTemplatesData.data["primary_measure_type"]
|
||||||
|
|
||||||
|
|
||||||
|
def get_template_type(self, context):
|
||||||
|
return [
|
||||||
|
(
|
||||||
|
"PSET_TYPEDRIVENONLY",
|
||||||
|
"Pset - IfcTypeObject",
|
||||||
|
"The property sets defined by this IfcPropertySetTemplate can only be assigned to subtypes of IfcTypeObject.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"PSET_TYPEDRIVENOVERRIDE",
|
||||||
|
"Pset - IfcTypeObject - Override",
|
||||||
|
"The property sets defined by this IfcPropertySetTemplate can only be assigned to subtypes of IfcTypeObject.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"PSET_OCCURRENCEDRIVEN",
|
||||||
|
"Pset - IfcObject",
|
||||||
|
"The property sets defined by this IfcPropertySetTemplate can only be assigned to subtypes of IfcObject.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"PSET_PERFORMANCEDRIVEN",
|
||||||
|
"Pset - IfcPerformanceHistory",
|
||||||
|
"The property sets defined by this IfcPropertySetTemplate can only be assigned to IfcPerformanceHistory.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"QTO_TYPEDRIVENONLY",
|
||||||
|
"Qto - IfcTypeObject",
|
||||||
|
"The element quantity defined by this IfcPropertySetTemplate can only be assigned to subtypes of IfcTypeObject.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"QTO_TYPEDRIVENOVERRIDE",
|
||||||
|
"Qto - IfcTypeObject - Override",
|
||||||
|
"The element quantity defined by this IfcPropertySetTemplate can be assigned to subtypes of IfcTypeObject and can be overridden by an element quantity with same name at subtypes of IfcObject.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"QTO_OCCURRENCEDRIVEN",
|
||||||
|
"Qto - IfcObject",
|
||||||
|
"The element quantity defined by this IfcPropertySetTemplate can only be assigned to subtypes of IfcObject.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"NOTDEFINED",
|
||||||
|
"Not defined",
|
||||||
|
"No restriction provided, the property sets defined by this IfcPropertySetTemplate can be assigned to any entity, if not otherwise restricted by the ApplicableEntity attribute.",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class PsetTemplate(PropertyGroup):
|
class PsetTemplate(PropertyGroup):
|
||||||
global_id: StringProperty(name="Global ID")
|
global_id: StringProperty(name="Global ID")
|
||||||
name: StringProperty(name="Name")
|
name: StringProperty(name="Name")
|
||||||
description: StringProperty(name="Description")
|
description: StringProperty(name="Description")
|
||||||
template_type: EnumProperty(
|
template_type: EnumProperty(items=get_template_type, name="Template Type")
|
||||||
items=[
|
|
||||||
(
|
|
||||||
"PSET_TYPEDRIVENONLY",
|
|
||||||
"Pset - IfcTypeObject",
|
|
||||||
"The property sets defined by this IfcPropertySetTemplate can only be assigned to subtypes of IfcTypeObject.",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"PSET_TYPEDRIVENOVERRIDE",
|
|
||||||
"Pset - IfcTypeObject - Override",
|
|
||||||
"The property sets defined by this IfcPropertySetTemplate can only be assigned to subtypes of IfcTypeObject.",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"PSET_OCCURRENCEDRIVEN",
|
|
||||||
"Pset - IfcObject",
|
|
||||||
"The property sets defined by this IfcPropertySetTemplate can only be assigned to subtypes of IfcObject.",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"PSET_PERFORMANCEDRIVEN",
|
|
||||||
"Pset - IfcPerformanceHistory",
|
|
||||||
"The property sets defined by this IfcPropertySetTemplate can only be assigned to IfcPerformanceHistory.",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"QTO_TYPEDRIVENONLY",
|
|
||||||
"Qto - IfcTypeObject",
|
|
||||||
"The element quantity defined by this IfcPropertySetTemplate can only be assigned to subtypes of IfcTypeObject.",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"QTO_TYPEDRIVENOVERRIDE",
|
|
||||||
"Qto - IfcTypeObject - Override",
|
|
||||||
"The element quantity defined by this IfcPropertySetTemplate can be assigned to subtypes of IfcTypeObject and can be overridden by an element quantity with same name at subtypes of IfcObject.",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"QTO_OCCURRENCEDRIVEN",
|
|
||||||
"Qto - IfcObject",
|
|
||||||
"The element quantity defined by this IfcPropertySetTemplate can only be assigned to subtypes of IfcObject.",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"NOTDEFINED",
|
|
||||||
"Not defined",
|
|
||||||
"No restriction provided, the property sets defined by this IfcPropertySetTemplate can be assigned to any entity, if not otherwise restricted by the ApplicableEntity attribute.",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
name="Template Type",
|
|
||||||
)
|
|
||||||
applicable_entity: StringProperty(name="Applicable Entity")
|
applicable_entity: StringProperty(name="Applicable Entity")
|
||||||
|
|
||||||
|
getter_enum = {
|
||||||
|
"template_type": get_template_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class EnumerationValues(PropertyGroup):
|
class EnumerationValues(PropertyGroup):
|
||||||
string_value: StringProperty(name="Value")
|
string_value: StringProperty(name="Value")
|
||||||
bool_value: BoolProperty(name="Value")
|
bool_value: BoolProperty(name="Value")
|
||||||
int_value: IntProperty(name="Value")
|
int_value: IntProperty(name="Value")
|
||||||
float_value: FloatProperty(name="Value")
|
float_value: FloatProperty(name="Value")
|
||||||
|
|
||||||
|
|
||||||
class PropTemplate(PropertyGroup):
|
class PropTemplate(PropertyGroup):
|
||||||
global_id: StringProperty(name="Global ID")
|
global_id: StringProperty(name="Global ID")
|
||||||
name: StringProperty(name="Name")
|
name: StringProperty(name="Name")
|
||||||
description: StringProperty(name="Description")
|
description: StringProperty(name="Description")
|
||||||
primary_measure_type: EnumProperty(items=get_primary_measure_type, name="Primary Measure Type")
|
primary_measure_type: EnumProperty(items=get_primary_measure_type, name="Primary Measure Type")
|
||||||
template_type: EnumProperty(
|
template_type: EnumProperty(
|
||||||
items=[
|
items=[("P_SINGLEVALUE", "P_SINGLEVALUE", ""), ("P_ENUMERATEDVALUE", "P_ENUMERATEDVALUE", "")],
|
||||||
("P_SINGLEVALUE","P_SINGLEVALUE",""),
|
name="Template Type",
|
||||||
("P_ENUMERATEDVALUE","P_ENUMERATEDVALUE","")
|
|
||||||
],
|
|
||||||
name="Template Type"
|
|
||||||
)
|
)
|
||||||
enum_values: CollectionProperty(type=EnumerationValues)
|
enum_values: CollectionProperty(type=EnumerationValues)
|
||||||
getter_enum = {
|
getter_enum = {
|
||||||
"primary_measure_type": get_primary_measure_type,
|
"primary_measure_type": get_primary_measure_type,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_value_name(self):
|
def get_value_name(self):
|
||||||
ifc_data_type = IfcStore.get_schema().declaration_by_name(self.primary_measure_type)
|
ifc_data_type = IfcStore.get_schema().declaration_by_name(self.primary_measure_type)
|
||||||
data_type = ifcopenshell.util.attribute.get_primitive_type(ifc_data_type)
|
data_type = ifcopenshell.util.attribute.get_primitive_type(ifc_data_type)
|
||||||
@@ -194,7 +195,7 @@ class BIMPsetTemplateProperties(PropertyGroup):
|
|||||||
active_pset_template: PointerProperty(type=PsetTemplate)
|
active_pset_template: PointerProperty(type=PsetTemplate)
|
||||||
active_prop_template: PointerProperty(type=PropTemplate)
|
active_prop_template: PointerProperty(type=PropTemplate)
|
||||||
new_template_filename: StringProperty("New TemplateFileName")
|
new_template_filename: StringProperty("New TemplateFileName")
|
||||||
|
|
||||||
getter_enum = {
|
getter_enum = {
|
||||||
"pset_template_files": getPsetTemplateFiles,
|
"pset_template_files": getPsetTemplateFiles,
|
||||||
"pset_templates": getPsetTemplates,
|
"pset_templates": getPsetTemplates,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy.types import Panel
|
from bpy.types import Panel
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.ui import prop_with_search
|
from blenderbim.bim.helper import prop_with_search
|
||||||
from blenderbim.bim.module.pset_template.prop import (
|
from blenderbim.bim.module.pset_template.prop import (
|
||||||
getPsetTemplates,
|
getPsetTemplates,
|
||||||
)
|
)
|
||||||
@@ -38,13 +38,13 @@ class BIM_PT_pset_template(Panel):
|
|||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
props = context.scene.BIMPsetTemplateProperties
|
props = context.scene.BIMPsetTemplateProperties
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
prop_with_search(row, props, "pset_template_files", text="")
|
prop_with_search(row, props, "pset_template_files", text="")
|
||||||
row.operator("bim.save_pset_template_file", text="", icon="EXPORT")
|
row.operator("bim.save_pset_template_file", text="", icon="EXPORT")
|
||||||
row.operator("bim.add_pset_file",icon="ADD",text="")
|
row.operator("bim.add_pset_file", icon="ADD", text="")
|
||||||
row.operator("bim.refresh_psettemplates", icon="FILE_REFRESH", text="")
|
row.operator("bim.refresh_psettemplates", icon="FILE_REFRESH", text="")
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
|
|
||||||
if bool(getPsetTemplates(props, context)):
|
if bool(getPsetTemplates(props, context)):
|
||||||
@@ -72,11 +72,10 @@ class BIM_PT_pset_template(Panel):
|
|||||||
row.prop(props.active_pset_template, "name")
|
row.prop(props.active_pset_template, "name")
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(props.active_pset_template, "description")
|
row.prop(props.active_pset_template, "description")
|
||||||
row = layout.row()
|
prop_with_search(layout, props.active_pset_template, "template_type")
|
||||||
row.prop(props.active_pset_template, "template_type")
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.prop(props.active_pset_template, "applicable_entity")
|
row.prop(props.active_pset_template, "applicable_entity")
|
||||||
else:
|
else:
|
||||||
pset_template = Data.pset_templates[int(props.pset_templates)]
|
pset_template = Data.pset_templates[int(props.pset_templates)]
|
||||||
for name, value in pset_template.items():
|
for name, value in pset_template.items():
|
||||||
if name == "id" or name == "type" or name == "HasPropertyTemplates":
|
if name == "id" or name == "type" or name == "HasPropertyTemplates":
|
||||||
@@ -88,7 +87,7 @@ class BIM_PT_pset_template(Panel):
|
|||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text="Property Templates", icon="COPY_ID")
|
row.label(text="Property Templates", icon="COPY_ID")
|
||||||
row.operator("bim.add_prop_template", icon="ADD", text="")
|
row.operator("bim.add_prop_template", icon="ADD", text="")
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.label(text="Name | Description | PrimaryMeasureType | TemplateType")
|
row.label(text="Name | Description | PrimaryMeasureType | TemplateType")
|
||||||
|
|
||||||
@@ -101,26 +100,27 @@ class BIM_PT_pset_template(Panel):
|
|||||||
row.prop(props.active_prop_template, "description", text="")
|
row.prop(props.active_prop_template, "description", text="")
|
||||||
prop_with_search(row, props.active_prop_template, "primary_measure_type", text="")
|
prop_with_search(row, props.active_prop_template, "primary_measure_type", text="")
|
||||||
row.prop(props.active_prop_template, "template_type", text="")
|
row.prop(props.active_prop_template, "template_type", text="")
|
||||||
|
|
||||||
if props.active_prop_template.template_type == "P_ENUMERATEDVALUE":
|
if props.active_prop_template.template_type == "P_ENUMERATEDVALUE":
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
split = row.split(factor=0.2)
|
split = row.split(factor=0.2)
|
||||||
c=split.column()
|
c = split.column()
|
||||||
c.label(text="Enumerations:",)
|
c.label(
|
||||||
|
text="Enumerations:",
|
||||||
c=split.column()
|
)
|
||||||
|
|
||||||
|
c = split.column()
|
||||||
box = c.box()
|
box = c.box()
|
||||||
grid = box.column_flow(columns=4)
|
grid = box.column_flow(columns=4)
|
||||||
value_name = props.active_prop_template.get_value_name()
|
value_name = props.active_prop_template.get_value_name()
|
||||||
r = grid.row()
|
r = grid.row()
|
||||||
r.operator("bim.add_prop_enum", text="Add Enum")
|
r.operator("bim.add_prop_enum", text="Add Enum")
|
||||||
for k,v in enumerate(props.active_prop_template.enum_values):
|
for k, v in enumerate(props.active_prop_template.enum_values):
|
||||||
r = grid.row(align=True)
|
r = grid.row(align=True)
|
||||||
r.prop(v, value_name, text="")
|
r.prop(v, value_name, text="")
|
||||||
op = r.operator("bim.delete_prop_enum", icon="X", text="")
|
op = r.operator("bim.delete_prop_enum", icon="X", text="")
|
||||||
op.index = k
|
op.index = k
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
row.label(text=prop_template["Name"])
|
row.label(text=prop_template["Name"])
|
||||||
row.label(text=prop_template["Description"])
|
row.label(text=prop_template["Description"])
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ classes = (
|
|||||||
operator.EnableReassignClass,
|
operator.EnableReassignClass,
|
||||||
operator.ReassignClass,
|
operator.ReassignClass,
|
||||||
operator.UnlinkObject,
|
operator.UnlinkObject,
|
||||||
operator.BIM_OT_enum_property_search,
|
|
||||||
prop.BIMRootProperties,
|
prop.BIMRootProperties,
|
||||||
ui.BIM_PT_class,
|
ui.BIM_PT_class,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -31,8 +31,6 @@ import blenderbim.core.root as core
|
|||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from ifcopenshell.api.void.data import Data as VoidData
|
from ifcopenshell.api.void.data import Data as VoidData
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.module.root.prop import get_contexts
|
|
||||||
from blenderbim.bim.prop import StrProperty
|
|
||||||
|
|
||||||
|
|
||||||
class Operator:
|
class Operator:
|
||||||
@@ -128,12 +126,13 @@ class AssignClass(bpy.types.Operator, Operator):
|
|||||||
ifc_representation_class: bpy.props.StringProperty()
|
ifc_representation_class: bpy.props.StringProperty()
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
|
props = context.scene.BIMRootProperties
|
||||||
objects = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
objects = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||||
ifc_class = self.ifc_class or context.scene.BIMRootProperties.ifc_class
|
ifc_class = self.ifc_class or props.ifc_class
|
||||||
predefined_type = self.userdefined_type if self.predefined_type == "USERDEFINED" else self.predefined_type
|
predefined_type = self.userdefined_type if self.predefined_type == "USERDEFINED" else self.predefined_type
|
||||||
ifc_context = self.context_id
|
ifc_context = self.context_id
|
||||||
if not ifc_context and get_contexts(self, context):
|
if not ifc_context and props.getter_enum["contexts"](props, context):
|
||||||
ifc_context = int(context.scene.BIMRootProperties.contexts or "0") or None
|
ifc_context = int(props.contexts or "0") or None
|
||||||
if ifc_context:
|
if ifc_context:
|
||||||
ifc_context = tool.Ifc.get().by_id(ifc_context)
|
ifc_context = tool.Ifc.get().by_id(ifc_context)
|
||||||
active_object = context.active_object
|
active_object = context.active_object
|
||||||
@@ -190,27 +189,3 @@ class CopyClass(bpy.types.Operator, Operator):
|
|||||||
for obj in objects:
|
for obj in objects:
|
||||||
core.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=obj)
|
core.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=obj)
|
||||||
blenderbim.bim.handler.purge_module_data()
|
blenderbim.bim.handler.purge_module_data()
|
||||||
|
|
||||||
|
|
||||||
class BIM_OT_enum_property_search(bpy.types.Operator):
|
|
||||||
bl_idname = "bim.enum_property_search"
|
|
||||||
bl_label = "Search For Property"
|
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
|
||||||
prop_name: bpy.props.StringProperty()
|
|
||||||
collection: bpy.props.CollectionProperty(type=StrProperty)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
|
||||||
self.data = context.data
|
|
||||||
getter = self.data.getter_enum.get(self.prop_name, None)
|
|
||||||
if getter is None:
|
|
||||||
return {"FINISHED"}
|
|
||||||
self.collection.clear()
|
|
||||||
for item in getter(self.data, context):
|
|
||||||
self.collection.add().name = item[0]
|
|
||||||
return context.window_manager.invoke_props_dialog(self)
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
def draw(self, context):
|
|
||||||
self.layout.prop_search(self.data, self.prop_name, self, "collection")
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import ifcopenshell
|
|||||||
import ifcopenshell.util.schema
|
import ifcopenshell.util.schema
|
||||||
from blenderbim.bim.module.root.data import IfcClassData
|
from blenderbim.bim.module.root.data import IfcClassData
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.prop import StrProperty
|
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
from bpy.props import (
|
from bpy.props import (
|
||||||
PointerProperty,
|
PointerProperty,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import bpy
|
|||||||
import blenderbim.bim.module.root.prop as root_prop
|
import blenderbim.bim.module.root.prop as root_prop
|
||||||
from bpy.types import Panel
|
from bpy.types import Panel
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.ui import prop_with_search
|
from blenderbim.bim.helper import prop_with_search
|
||||||
from blenderbim.bim.module.root.data import IfcClassData
|
from blenderbim.bim.module.root.data import IfcClassData
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -624,6 +624,7 @@ class EditTaskTime(bpy.types.Operator):
|
|||||||
if prop.is_null:
|
if prop.is_null:
|
||||||
attributes[prop.name] = None
|
attributes[prop.name] = None
|
||||||
return True
|
return True
|
||||||
|
# TODO make this parse PT32 as P4D
|
||||||
attributes[prop.name] = helper.parse_duration(prop.string_value)
|
attributes[prop.name] = helper.parse_duration(prop.string_value)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class BIM_PT_styles(Panel):
|
|||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.alignment = "RIGHT"
|
row.alignment = "RIGHT"
|
||||||
|
|
||||||
#row.operator("bim.add_presentation_style", text="", icon="ADD")
|
# row.operator("bim.add_presentation_style", text="", icon="ADD")
|
||||||
if self.props.styles and self.props.active_style_index < len(self.props.styles):
|
if self.props.styles and self.props.active_style_index < len(self.props.styles):
|
||||||
style = self.props.styles[self.props.active_style_index]
|
style = self.props.styles[self.props.active_style_index]
|
||||||
op = row.operator("bim.select_by_style", text="", icon="RESTRICT_SELECT_OFF")
|
op = row.operator("bim.select_by_style", text="", icon="RESTRICT_SELECT_OFF")
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class UnitsData:
|
|||||||
"unit_classes": cls.unit_classes(),
|
"unit_classes": cls.unit_classes(),
|
||||||
"named_unit_types": cls.named_unit_types(),
|
"named_unit_types": cls.named_unit_types(),
|
||||||
"conversion_unit_types": cls.conversion_unit_types(),
|
"conversion_unit_types": cls.conversion_unit_types(),
|
||||||
"total_units": cls.get_total_units()
|
"total_units": cls.get_total_units(),
|
||||||
}
|
}
|
||||||
cls.is_loaded = True
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
import blenderbim.bim.helper
|
import blenderbim.bim.helper
|
||||||
from bpy.types import Panel, UIList
|
from bpy.types import Panel, UIList
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.ui import prop_with_search
|
from blenderbim.bim.helper import prop_with_search
|
||||||
from blenderbim.bim.module.unit.data import UnitsData
|
from blenderbim.bim.module.unit.data import UnitsData
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import blenderbim.bim.handler
|
|||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from . import schema
|
from . import schema
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
|
from blenderbim.bim.prop import StrProperty
|
||||||
from blenderbim.bim.ui import IFCFileSelector
|
from blenderbim.bim.ui import IFCFileSelector
|
||||||
from mathutils import Vector, Matrix, Euler
|
from mathutils import Vector, Matrix, Euler
|
||||||
from math import radians
|
from math import radians
|
||||||
@@ -523,3 +524,41 @@ class ConfigureVisibility(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
def update_enum_property_search_prop(self, context):
|
||||||
|
for i, prop in enumerate(self.collection_name):
|
||||||
|
if prop.name == self.dummy_name:
|
||||||
|
setattr(context.data, self.prop_name, self.collection_identifier[i].name)
|
||||||
|
|
||||||
|
|
||||||
|
class BIM_OT_enum_property_search(bpy.types.Operator):
|
||||||
|
bl_idname = "bim.enum_property_search"
|
||||||
|
bl_label = "Search For Property"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
dummy_name: bpy.props.StringProperty(name="Property", update=update_enum_property_search_prop)
|
||||||
|
collection_name: bpy.props.CollectionProperty(type=StrProperty)
|
||||||
|
collection_identifier: bpy.props.CollectionProperty(type=StrProperty)
|
||||||
|
prop_name: bpy.props.StringProperty()
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
self.data = context.data
|
||||||
|
getter = self.data.getter_enum.get(self.prop_name, None)
|
||||||
|
if getter is None:
|
||||||
|
return {"FINISHED"}
|
||||||
|
self.collection_name.clear()
|
||||||
|
self.collection_identifier.clear()
|
||||||
|
for item in getter(self.data, context):
|
||||||
|
self.collection_identifier.add().name = item[0]
|
||||||
|
if item[0] == getattr(self.data, self.prop_name):
|
||||||
|
self.dummy_name = item[1] # We found the current enum value
|
||||||
|
self.collection_name.add().name = item[1]
|
||||||
|
return context.window_manager.invoke_props_dialog(self)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
# Mandatory to access context.data in update :
|
||||||
|
self.layout.context_pointer_set(name="data", data=self.data)
|
||||||
|
self.layout.prop_search(self, "dummy_name", self, "collection_name")
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ class Attribute(PropertyGroup):
|
|||||||
is_null: BoolProperty(name="Is Null")
|
is_null: BoolProperty(name="Is Null")
|
||||||
is_optional: BoolProperty(name="Is Optional")
|
is_optional: BoolProperty(name="Is Optional")
|
||||||
is_uri: BoolProperty(name="Is Uri", default=False)
|
is_uri: BoolProperty(name="Is Uri", default=False)
|
||||||
|
is_selected: BoolProperty(name="Is Selected", default=False)
|
||||||
|
|
||||||
def get_value(self):
|
def get_value(self):
|
||||||
if self.is_null:
|
if self.is_null:
|
||||||
@@ -239,6 +240,10 @@ class Attribute(PropertyGroup):
|
|||||||
value = str(value)
|
value = str(value)
|
||||||
setattr(self, self.get_value_name(), value)
|
setattr(self, self.get_value_name(), value)
|
||||||
|
|
||||||
|
getter_enum = {
|
||||||
|
"enum_value": getAttributeEnumValues,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ModuleVisibility(PropertyGroup):
|
class ModuleVisibility(PropertyGroup):
|
||||||
name: StringProperty(name="Name")
|
name: StringProperty(name="Name")
|
||||||
|
|||||||
@@ -170,15 +170,6 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences):
|
|||||||
row.operator("bim.configure_visibility")
|
row.operator("bim.configure_visibility")
|
||||||
|
|
||||||
|
|
||||||
def prop_with_search(layout, data, prop_name, **kwargs): # Kwargs are layout.prop arguments (text, icon, etc.)
|
|
||||||
row = layout.row(align=True)
|
|
||||||
# Magick courtesy of https://blender.stackexchange.com/a/203443/86891
|
|
||||||
row.context_pointer_set(name="data", data=data)
|
|
||||||
row.prop(data, prop_name, **kwargs)
|
|
||||||
op = row.operator("bim.enum_property_search", text="", icon="VIEWZOOM")
|
|
||||||
op.prop_name = prop_name
|
|
||||||
|
|
||||||
|
|
||||||
def ifc_units(self, context):
|
def ifc_units(self, context):
|
||||||
scene = context.scene
|
scene = context.scene
|
||||||
props = scene.BIMProperties
|
props = scene.BIMProperties
|
||||||
|
|||||||
@@ -375,15 +375,11 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def open_spreadsheet(cls, uri):
|
def open_spreadsheet(cls, uri):
|
||||||
cls.open_with_user_command(
|
cls.open_with_user_command(bpy.context.preferences.addons["blenderbim"].preferences.spreadsheet_command, uri)
|
||||||
bpy.context.preferences.addons["blenderbim"].preferences.spreadsheet_command, uri
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def open_svg(cls, uri):
|
def open_svg(cls, uri):
|
||||||
cls.open_with_user_command(
|
cls.open_with_user_command(bpy.context.preferences.addons["blenderbim"].preferences.svg_command, uri)
|
||||||
bpy.context.preferences.addons["blenderbim"].preferences.svg_command, uri
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run_root_assign_class(
|
def run_root_assign_class(
|
||||||
|
|||||||
@@ -75,7 +75,9 @@ class Material(blenderbim.core.tool.Material):
|
|||||||
new = props.materials.add()
|
new = props.materials.add()
|
||||||
new.ifc_definition_id = material.id()
|
new.ifc_definition_id = material.id()
|
||||||
new.name = get_name(material)
|
new.name = get_name(material)
|
||||||
new.total_elements = len(ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material))
|
new.total_elements = len(
|
||||||
|
ifcopenshell.util.element.get_elements_by_material(tool.Ifc.get(), material)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
for material in materials:
|
for material in materials:
|
||||||
new = props.materials.add()
|
new = props.materials.add()
|
||||||
|
|||||||
@@ -18,11 +18,14 @@
|
|||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
py_exec = str(sys.executable)
|
py_exec = str(sys.executable)
|
||||||
|
lib = Path(py_exec).parent.parent / "lib"
|
||||||
|
|
||||||
subprocess.call([py_exec, "-m", "ensurepip", "--user"])
|
subprocess.call([py_exec, "-m", "ensurepip", "--user"])
|
||||||
subprocess.call([py_exec, "-m", "pip", "install", "--upgrade", "pip"])
|
subprocess.call([py_exec, "-m", "pip", "install", "--upgrade", "pip"])
|
||||||
subprocess.call([py_exec, "-m", "pip", "install", "pytest"])
|
subprocess.call([py_exec, "-m", "pip", "install", f"--target={str(lib)}", "pytest"])
|
||||||
subprocess.call([py_exec, "-m", "pip", "install", "pytest-blender"])
|
subprocess.call([py_exec, "-m", "pip", "install", f"--target={str(lib)}", "pytest-blender"])
|
||||||
subprocess.call([py_exec, "-m", "pip", "install", "pytest-bdd"])
|
subprocess.call([py_exec, "-m", "pip", "install", f"--target={str(lib)}", "pytest-bdd"])
|
||||||
subprocess.call([py_exec, "-m", "pip", "install", "pygments"])
|
subprocess.call([py_exec, "-m", "pip", "install", f"--target={str(lib)}", "pygments"])
|
||||||
|
|||||||
@@ -125,7 +125,6 @@ class TestHidePorts:
|
|||||||
system.delete_element_objects(["port"]).should_be_called()
|
system.delete_element_objects(["port"]).should_be_called()
|
||||||
subject.hide_ports(ifc, system, element="element")
|
subject.hide_ports(ifc, system, element="element")
|
||||||
|
|
||||||
|
|
||||||
def test_syncing_locations_if_objects_moved_prior_to_hiding_ports(self, ifc, system):
|
def test_syncing_locations_if_objects_moved_prior_to_hiding_ports(self, ifc, system):
|
||||||
ifc.get_object("element").should_be_called().will_return("obj")
|
ifc.get_object("element").should_be_called().will_return("obj")
|
||||||
ifc.is_moved("obj").should_be_called().will_return(True)
|
ifc.is_moved("obj").should_be_called().will_return(True)
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ class TestGetMapConversionAttributes(NewFile):
|
|||||||
"Scale": 6.0,
|
"Scale": 6.0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestGetTrueNorthAttributes(NewFile):
|
class TestGetTrueNorthAttributes(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
TestImportTrueNorth().test_run()
|
TestImportTrueNorth().test_run()
|
||||||
@@ -185,18 +186,18 @@ class TestDisableEditing(NewFile):
|
|||||||
|
|
||||||
class TestSetCoordinates(NewFile):
|
class TestSetCoordinates(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
subject.set_coordinates("input", [1., 2., 3.])
|
subject.set_coordinates("input", [1.0, 2.0, 3.0])
|
||||||
assert bpy.context.scene.BIMGeoreferenceProperties.coordinate_input == "1.0,2.0,3.0"
|
assert bpy.context.scene.BIMGeoreferenceProperties.coordinate_input == "1.0,2.0,3.0"
|
||||||
subject.set_coordinates("output", [4., 5., 6.])
|
subject.set_coordinates("output", [4.0, 5.0, 6.0])
|
||||||
assert bpy.context.scene.BIMGeoreferenceProperties.coordinate_output == "4.0,5.0,6.0"
|
assert bpy.context.scene.BIMGeoreferenceProperties.coordinate_output == "4.0,5.0,6.0"
|
||||||
|
|
||||||
|
|
||||||
class TestGetCoordinates(NewFile):
|
class TestGetCoordinates(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
bpy.context.scene.BIMGeoreferenceProperties.coordinate_input = "1.0,2.0,3.0"
|
bpy.context.scene.BIMGeoreferenceProperties.coordinate_input = "1.0,2.0,3.0"
|
||||||
assert subject.get_coordinates("input") == [1., 2., 3.]
|
assert subject.get_coordinates("input") == [1.0, 2.0, 3.0]
|
||||||
bpy.context.scene.BIMGeoreferenceProperties.coordinate_output = "4.0,5.0,6.0"
|
bpy.context.scene.BIMGeoreferenceProperties.coordinate_output = "4.0,5.0,6.0"
|
||||||
assert subject.get_coordinates("output") == [4., 5., 6.]
|
assert subject.get_coordinates("output") == [4.0, 5.0, 6.0]
|
||||||
|
|
||||||
|
|
||||||
class TestGetCursorLocation(NewFile):
|
class TestGetCursorLocation(NewFile):
|
||||||
@@ -207,8 +208,8 @@ class TestGetCursorLocation(NewFile):
|
|||||||
ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
|
ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
|
||||||
unit = ifcopenshell.api.run("unit.add_si_unit", ifc, unit_type="LENGTHUNIT", prefix="MILLI", name="METRE")
|
unit = ifcopenshell.api.run("unit.add_si_unit", ifc, unit_type="LENGTHUNIT", prefix="MILLI", name="METRE")
|
||||||
ifcopenshell.api.run("unit.assign_unit", ifc, units=[unit])
|
ifcopenshell.api.run("unit.assign_unit", ifc, units=[unit])
|
||||||
bpy.context.scene.cursor.location = (1., 2., 3.)
|
bpy.context.scene.cursor.location = (1.0, 2.0, 3.0)
|
||||||
assert subject.get_cursor_location() == [1000., 2000., 3000.]
|
assert subject.get_cursor_location() == [1000.0, 2000.0, 3000.0]
|
||||||
|
|
||||||
|
|
||||||
class TestSetCursorLocation(NewFile):
|
class TestSetCursorLocation(NewFile):
|
||||||
@@ -219,8 +220,8 @@ class TestSetCursorLocation(NewFile):
|
|||||||
ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
|
ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
|
||||||
unit = ifcopenshell.api.run("unit.add_si_unit", ifc, unit_type="LENGTHUNIT", prefix="MILLI", name="METRE")
|
unit = ifcopenshell.api.run("unit.add_si_unit", ifc, unit_type="LENGTHUNIT", prefix="MILLI", name="METRE")
|
||||||
ifcopenshell.api.run("unit.assign_unit", ifc, units=[unit])
|
ifcopenshell.api.run("unit.assign_unit", ifc, units=[unit])
|
||||||
subject.set_cursor_location([1000., 2000., 3000.])
|
subject.set_cursor_location([1000.0, 2000.0, 3000.0])
|
||||||
assert list(bpy.context.scene.cursor.location) == [1., 2., 3.]
|
assert list(bpy.context.scene.cursor.location) == [1.0, 2.0, 3.0]
|
||||||
|
|
||||||
|
|
||||||
class TestSetIfcTrueNorth(NewFile):
|
class TestSetIfcTrueNorth(NewFile):
|
||||||
@@ -258,13 +259,13 @@ class TestGetMapConversion(NewFile):
|
|||||||
|
|
||||||
class TestXyz2Enh(NewFile):
|
class TestXyz2Enh(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
assert subject.xyz2enh([0., 0., 0.], None) == [0., 0., 0.]
|
assert subject.xyz2enh([0.0, 0.0, 0.0], None) == [0.0, 0.0, 0.0]
|
||||||
|
|
||||||
def test_using_the_blender_offset(self):
|
def test_using_the_blender_offset(self):
|
||||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||||
props.has_blender_offset = True
|
props.has_blender_offset = True
|
||||||
props.blender_eastings = "1.0"
|
props.blender_eastings = "1.0"
|
||||||
assert subject.xyz2enh([0., 0., 0.], None) == (1., 0., 0.)
|
assert subject.xyz2enh([0.0, 0.0, 0.0], None) == (1.0, 0.0, 0.0)
|
||||||
|
|
||||||
def test_using_the_map_conversion(self):
|
def test_using_the_map_conversion(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
@@ -274,7 +275,7 @@ class TestXyz2Enh(NewFile):
|
|||||||
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
|
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
|
||||||
map_conversion = ifc.by_type("IfcMapConversion")[0]
|
map_conversion = ifc.by_type("IfcMapConversion")[0]
|
||||||
map_conversion.Eastings = 1.0
|
map_conversion.Eastings = 1.0
|
||||||
assert subject.xyz2enh([0., 0., 0.], map_conversion) == (1., 0., 0.)
|
assert subject.xyz2enh([0.0, 0.0, 0.0], map_conversion) == (1.0, 0.0, 0.0)
|
||||||
|
|
||||||
def test_applying_both_blender_offset_and_map_conversion(self):
|
def test_applying_both_blender_offset_and_map_conversion(self):
|
||||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||||
@@ -287,18 +288,18 @@ class TestXyz2Enh(NewFile):
|
|||||||
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
|
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
|
||||||
map_conversion = ifc.by_type("IfcMapConversion")[0]
|
map_conversion = ifc.by_type("IfcMapConversion")[0]
|
||||||
map_conversion.Northings = 1.0
|
map_conversion.Northings = 1.0
|
||||||
assert subject.xyz2enh([0., 0., 0.], map_conversion) == (1., 1., 0.)
|
assert subject.xyz2enh([0.0, 0.0, 0.0], map_conversion) == (1.0, 1.0, 0.0)
|
||||||
|
|
||||||
|
|
||||||
class TestEnh2Xyz(NewFile):
|
class TestEnh2Xyz(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
assert subject.enh2xyz([0., 0., 0.], None) == [0., 0., 0.]
|
assert subject.enh2xyz([0.0, 0.0, 0.0], None) == [0.0, 0.0, 0.0]
|
||||||
|
|
||||||
def test_using_the_blender_offset(self):
|
def test_using_the_blender_offset(self):
|
||||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||||
props.has_blender_offset = True
|
props.has_blender_offset = True
|
||||||
props.blender_eastings = "1.0"
|
props.blender_eastings = "1.0"
|
||||||
assert subject.enh2xyz([0., 0., 0.], None) == (-1., 0., 0.)
|
assert subject.enh2xyz([0.0, 0.0, 0.0], None) == (-1.0, 0.0, 0.0)
|
||||||
|
|
||||||
def test_using_the_map_conversion(self):
|
def test_using_the_map_conversion(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
@@ -308,7 +309,7 @@ class TestEnh2Xyz(NewFile):
|
|||||||
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
|
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
|
||||||
map_conversion = ifc.by_type("IfcMapConversion")[0]
|
map_conversion = ifc.by_type("IfcMapConversion")[0]
|
||||||
map_conversion.Eastings = 1.0
|
map_conversion.Eastings = 1.0
|
||||||
assert subject.enh2xyz([0., 0., 0.], map_conversion) == (-1., 0., 0.)
|
assert subject.enh2xyz([0.0, 0.0, 0.0], map_conversion) == (-1.0, 0.0, 0.0)
|
||||||
|
|
||||||
def test_applying_both_blender_offset_and_map_conversion(self):
|
def test_applying_both_blender_offset_and_map_conversion(self):
|
||||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||||
@@ -321,7 +322,7 @@ class TestEnh2Xyz(NewFile):
|
|||||||
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
|
ifcopenshell.api.run("georeference.add_georeferencing", ifc)
|
||||||
map_conversion = ifc.by_type("IfcMapConversion")[0]
|
map_conversion = ifc.by_type("IfcMapConversion")[0]
|
||||||
map_conversion.Northings = 1.0
|
map_conversion.Northings = 1.0
|
||||||
assert subject.enh2xyz([0., 0., 0.], map_conversion) == (-1., -1., 0.)
|
assert subject.enh2xyz([0.0, 0.0, 0.0], map_conversion) == (-1.0, -1.0, 0.0)
|
||||||
|
|
||||||
|
|
||||||
class TestSetIfcGridNorth(NewFile):
|
class TestSetIfcGridNorth(NewFile):
|
||||||
|
|||||||
@@ -106,7 +106,12 @@ class Usecase:
|
|||||||
properties.append(value)
|
properties.append(value)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
nominal_value = value
|
properties.append(
|
||||||
|
self.file.create_entity(
|
||||||
|
"IfcPropertySingleValue",
|
||||||
|
**{"Name": name, "NominalValue": value},
|
||||||
|
)
|
||||||
|
)
|
||||||
#TODO-The following "elif" is temporary code, will need to refactor at some point - vulevukusej
|
#TODO-The following "elif" is temporary code, will need to refactor at some point - vulevukusej
|
||||||
elif isinstance(value, list):
|
elif isinstance(value, list):
|
||||||
for pset_template in self.settings["pset_template"].HasPropertyTemplates:
|
for pset_template in self.settings["pset_template"].HasPropertyTemplates:
|
||||||
@@ -130,12 +135,12 @@ class Usecase:
|
|||||||
value = self.cast_value_to_primary_measure_type(value, primary_measure_type)
|
value = self.cast_value_to_primary_measure_type(value, primary_measure_type)
|
||||||
nominal_value = self.file.create_entity(primary_measure_type, value)
|
nominal_value = self.file.create_entity(primary_measure_type, value)
|
||||||
|
|
||||||
properties.append(
|
properties.append(
|
||||||
self.file.create_entity(
|
self.file.create_entity(
|
||||||
"IfcPropertySingleValue",
|
"IfcPropertySingleValue",
|
||||||
**{"Name": name, "NominalValue": nominal_value},
|
**{"Name": name, "NominalValue": nominal_value},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
return properties
|
return properties
|
||||||
|
|
||||||
def extend_pset_with_new_properties(self, new_properties):
|
def extend_pset_with_new_properties(self, new_properties):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
lxml==4.6.5
|
lxml==4.9.1
|
||||||
numpy==1.22.0
|
numpy==1.22.0
|
||||||
regex==2021.4.4
|
regex==2021.4.4
|
||||||
xmlschema==1.6.4
|
xmlschema==1.6.4
|
||||||
Submodule src/ifcopenshell-python/test/Sample-BIM-Files updated: 2daf6c46ed...adadc7740b
@@ -145,6 +145,7 @@ def create_case(fn, openings):
|
|||||||
|
|
||||||
|
|
||||||
class TestWallOpenings:
|
class TestWallOpenings:
|
||||||
|
@pytest.mark.skipif(shutil.which("IfcConvert") is None, reason="Requires IfcConvert in path")
|
||||||
def test_all(self):
|
def test_all(self):
|
||||||
|
|
||||||
cases = [
|
cases = [
|
||||||
@@ -244,4 +245,4 @@ class TestWallOpenings:
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
TestWallOpenings().test_all()
|
pytest.main(["-x", __file__])
|
||||||
|
|||||||
@@ -483,6 +483,15 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ifc_representation) {
|
||||||
|
if (reps->size()) {
|
||||||
|
// Return a random representation
|
||||||
|
ifc_representation = *reps->begin();
|
||||||
|
} else {
|
||||||
|
throw IfcParse::IfcException("No suitable IfcRepresentation found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Read precision for found representation's context
|
// Read precision for found representation's context
|
||||||
auto context = ifc_representation->ContextOfItems();
|
auto context = ifc_representation->ContextOfItems();
|
||||||
if (context->template as<typename Schema::IfcGeometricRepresentationSubContext>()) {
|
if (context->template as<typename Schema::IfcGeometricRepresentationSubContext>()) {
|
||||||
@@ -499,15 +508,6 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
|
|||||||
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, p);
|
kernel.setValue(IfcGeom::Kernel::GV_PRECISION, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ifc_representation) {
|
|
||||||
if (reps->size()) {
|
|
||||||
// Return a random representation
|
|
||||||
ifc_representation = *reps->begin();
|
|
||||||
} else {
|
|
||||||
throw IfcParse::IfcException("No suitable IfcRepresentation found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IfcGeom::BRepElement* brep = kernel.convert(settings, ifc_representation, product);
|
IfcGeom::BRepElement* brep = kernel.convert(settings, ifc_representation, product);
|
||||||
if (!brep) {
|
if (!brep) {
|
||||||
throw IfcParse::IfcException("Failed to process shape");
|
throw IfcParse::IfcException("Failed to process shape");
|
||||||
|
|||||||
@@ -808,7 +808,7 @@ void SvgSerializer::write(const geometry_data& data) {
|
|||||||
const std::string& ty_entity_name = ty->declaration().name();
|
const std::string& ty_entity_name = ty->declaration().name();
|
||||||
// Damn you, IFC
|
// Damn you, IFC
|
||||||
if (ty_entity_name == "IfcDoorStyle" || ty_entity_name == "IfcDoorType") {
|
if (ty_entity_name == "IfcDoorStyle" || ty_entity_name == "IfcDoorType") {
|
||||||
operation_type = *((IfcUtil::IfcBaseEntity*)ty)->get("OperationType");
|
operation_type = (std::string)*((IfcUtil::IfcBaseEntity*)ty)->get("OperationType");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user