mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 16:01:36 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c62ed5d3b6 | |||
| ffb6c82541 | |||
| a9e366b238 | |||
| 1ca0dfb1e0 | |||
| c11ba23a3d | |||
| 556c769b40 | |||
| 78173dd546 | |||
| 2196c16097 | |||
| 7af5db7cd4 | |||
| c58672cc25 | |||
| 85e022d76e | |||
| 872f40933f | |||
| 4491018f5e | |||
| a21c440b5b | |||
| 143e094db8 | |||
| 94e9e945d7 | |||
| 5e56115050 | |||
| 1ad654aab3 | |||
| 596ffb093b | |||
| 3576362fd8 | |||
| 2c949bb39a | |||
| 34faa0617b | |||
| 15f6b3803f | |||
| 8514a426bb | |||
| 2062324294 | |||
| 90c6218210 | |||
| 321bb7178d | |||
| 42dda0a07a | |||
| adb17d91f9 | |||
| 646cc59687 | |||
| 38759348cd | |||
| ff44f4f395 | |||
| a31051a937 | |||
| 5cfd69f337 | |||
| f4100f7951 | |||
| 785d5118d0 | |||
| fddd85817a | |||
| a689fc6377 | |||
| 8e5a7ed24e | |||
| 788217c73c | |||
| 1abc3a1422 | |||
| c31c34b7d2 | |||
| b22ecba179 |
@@ -35,7 +35,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [py39, py310, py311, py312]
|
||||
pyver: [py310, py311, py312]
|
||||
config:
|
||||
- {
|
||||
name: "Windows Build",
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [py39, py310, py311, py312]
|
||||
pyver: [py310, py311, py312]
|
||||
config:
|
||||
- {
|
||||
name: "Windows Build",
|
||||
|
||||
@@ -221,10 +221,11 @@ endif()
|
||||
|
||||
if(GLTF_SUPPORT OR CITYJSON_SUPPORT)
|
||||
UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR)
|
||||
find_file(json_hpp "json.hpp" ${JSON_INCLUDE_DIR}/nlohmann)
|
||||
find_path(json_header_path "json.hpp" ${JSON_INCLUDE_DIR} PATH_SUFFIXES "nlohmann")
|
||||
set(JSON_INCLUDE_DIR ${json_header_path})
|
||||
|
||||
if(json_hpp)
|
||||
message(STATUS "JSON for Modern C++ header file found")
|
||||
if(json_header_path)
|
||||
message(STATUS "JSON for Modern C++ header file found in ${JSON_INCLUDE_DIR}")
|
||||
else()
|
||||
message(FATAL_ERROR "Unable to find JSON for Modern C++ header file, aborting")
|
||||
endif()
|
||||
|
||||
+13
-8
@@ -49,11 +49,6 @@ LAST_COMMIT_HASH:=$(shell git rev-parse HEAD)
|
||||
PYVERSION:=py310
|
||||
PYPI_IMP:=cp
|
||||
|
||||
ifeq ($(PYVERSION), py39)
|
||||
PYLIBDIR:=python3.9
|
||||
PYNUMBER:=39
|
||||
PYPI_VERSION:=3.9
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
PYLIBDIR:=python3.10
|
||||
PYNUMBER:=310
|
||||
@@ -189,6 +184,10 @@ else ifeq ($(PLATFORM), macos)
|
||||
else
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pyradiance $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
endif
|
||||
# tomllib replacement for < Python 3.11, used to parse blender_manifest
|
||||
ifeq ($(PYVERSION), py310)
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download tomli --dest=./wheels
|
||||
endif
|
||||
|
||||
# Provides jsgantt-improved supports for web-based construction sequencing gantt charts
|
||||
cd build/blenderbim/bim/data/gantt/ && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js
|
||||
@@ -347,9 +346,15 @@ endif
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
make test-core
|
||||
make test-tool
|
||||
make test-bim
|
||||
@echo "Running all tests..."
|
||||
@ERROR=0; \
|
||||
make test-core || ERROR=1; \
|
||||
make test-tool || ERROR=1; \
|
||||
make test-bim || ERROR=1; \
|
||||
if [ $$ERROR -ne 0 ]; then \
|
||||
echo "One or more tests failed"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
.PHONY: test-core
|
||||
test-core:
|
||||
|
||||
@@ -68,11 +68,14 @@ def initialize_bbim_semver():
|
||||
in `addon_utils.modules()->bl_info['version']`,
|
||||
therefore we just parse it from .toml.
|
||||
"""
|
||||
import tomllib
|
||||
if sys.version_info >= (3, 11):
|
||||
import tomllib as toml
|
||||
else:
|
||||
import tomli as toml
|
||||
|
||||
toml_path = Path(__file__).parent / "blender_manifest.toml"
|
||||
with open(toml_path, "rb") as f:
|
||||
manifest = tomllib.load(f)
|
||||
manifest = toml.load(f)
|
||||
semver_pattern = r"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"
|
||||
version_str = manifest["version"]
|
||||
re_version = re.match(semver_pattern, version_str)
|
||||
@@ -82,9 +85,6 @@ def initialize_bbim_semver():
|
||||
bbim_semver["version"] = version_str
|
||||
|
||||
|
||||
initialize_bbim_semver()
|
||||
|
||||
|
||||
def get_debug_info():
|
||||
bbim_version = bbim_semver["version"]
|
||||
|
||||
@@ -177,6 +177,7 @@ def clean_up_dlls_safe_links() -> None:
|
||||
|
||||
|
||||
if IN_BLENDER:
|
||||
initialize_bbim_semver()
|
||||
|
||||
def get_binary_info() -> dict[str, Any]:
|
||||
info = {}
|
||||
|
||||
@@ -103,6 +103,7 @@ classes = [
|
||||
operator.BIM_OT_show_description,
|
||||
operator.BIM_OT_multiple_file_selector,
|
||||
operator.ClippingPlaneCutWithCappings,
|
||||
operator.CloseBlendWarning,
|
||||
operator.CloseError,
|
||||
operator.EditBlenderCollection,
|
||||
operator.FileAssociate,
|
||||
|
||||
@@ -24,7 +24,6 @@ import numpy as np
|
||||
import datetime
|
||||
import zipfile
|
||||
import tempfile
|
||||
import addon_utils
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.placement
|
||||
|
||||
@@ -18,10 +18,9 @@
|
||||
|
||||
import os
|
||||
import bpy
|
||||
import json
|
||||
import addon_utils
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.api.owner.settings
|
||||
import blenderbim.bim
|
||||
import blenderbim.tool as tool
|
||||
@@ -304,3 +303,6 @@ def load_post(scene):
|
||||
continue
|
||||
tool.Blender.override_scene_panel(panel)
|
||||
tool.Blender.setup_tabs()
|
||||
|
||||
if tool.Ifc.get() and bpy.data.is_saved:
|
||||
bpy.context.scene.BIMProperties.has_blend_warning = True
|
||||
|
||||
@@ -23,6 +23,7 @@ import math
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.attribute
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.unit
|
||||
from ifcopenshell.util.doc import get_attribute_doc, get_predefined_type_doc, get_property_doc
|
||||
from mathutils import geometry
|
||||
from mathutils import Vector
|
||||
|
||||
@@ -551,7 +551,7 @@ class IfcImporter:
|
||||
for axis in axes:
|
||||
shape = tool.Loader.create_generic_shape(axis.AxisCurve)
|
||||
mesh = self.create_mesh(axis, shape)
|
||||
obj = bpy.data.objects.new(f"IfcGridAxis/{axis.AxisTag}", mesh)
|
||||
obj = bpy.data.objects.new(tool.Loader.get_name(axis), mesh)
|
||||
if tool.Blender.get_addon_preferences().lock_grids_on_import:
|
||||
obj.lock_location = (True, True, True)
|
||||
obj.lock_rotation = (True, True, True)
|
||||
@@ -781,7 +781,7 @@ class IfcImporter:
|
||||
mesh = bpy.data.meshes.new(mesh_name)
|
||||
mesh.from_pydata([mathutils.Vector(vertex) * self.unit_scale], [], [])
|
||||
|
||||
obj = bpy.data.objects.new("{}/{}".format(product.is_a(), product.Name), mesh)
|
||||
obj = bpy.data.objects.new(tool.Loader.get_name(product), mesh)
|
||||
self.set_matrix_world(obj, tool.Loader.apply_blender_offset_to_matrix_world(obj, placement_matrix))
|
||||
self.link_element(product, obj)
|
||||
|
||||
@@ -847,7 +847,7 @@ class IfcImporter:
|
||||
mesh.from_pydata(vertex_list, [], [])
|
||||
tool.Ifc.link(representation, mesh)
|
||||
|
||||
obj = bpy.data.objects.new("{}/{}".format(product.is_a(), product.Name), mesh)
|
||||
obj = bpy.data.objects.new(tool.Loader.get_name(product), mesh)
|
||||
self.set_matrix_world(obj, tool.Loader.apply_blender_offset_to_matrix_world(obj, placement_matrix))
|
||||
self.link_element(product, obj)
|
||||
return product
|
||||
@@ -1261,7 +1261,7 @@ class IfcImporter:
|
||||
def place_objects_in_collections(self) -> None:
|
||||
for ifc_definition_id, obj in self.added_data.items():
|
||||
if isinstance(obj, bpy.types.Object):
|
||||
tool.Collector.assign(obj)
|
||||
tool.Collector.assign(obj, should_clean_users_collection=False)
|
||||
|
||||
def is_curve_annotation(self, element: ifcopenshell.entity_instance) -> bool:
|
||||
object_type = element.ObjectType
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.aggregate as core
|
||||
|
||||
@@ -18,14 +18,12 @@
|
||||
|
||||
import os
|
||||
import bpy
|
||||
import json
|
||||
import string
|
||||
import random
|
||||
import shutil
|
||||
import requests
|
||||
import tempfile
|
||||
import datetime
|
||||
import addon_utils
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import numpy as np
|
||||
import tempfile
|
||||
import webbrowser
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.geolocation
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.bim.module.bcf.prop as bcf_prop
|
||||
from . import bcfstore
|
||||
|
||||
@@ -22,7 +22,6 @@ import bpy
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
import platform
|
||||
import subprocess
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
@@ -30,6 +29,7 @@ import ifcopenshell.geom
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.placement
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.debug as core
|
||||
import blenderbim.bim.handler
|
||||
|
||||
@@ -21,6 +21,7 @@ import bpy
|
||||
import json
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.tool as tool
|
||||
from pathlib import Path
|
||||
from typing import Any, Union
|
||||
|
||||
@@ -25,6 +25,7 @@ import bmesh
|
||||
import shapely
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.module.drawing.helper as helper
|
||||
from math import pi, sin, cos, tan, acos, atan, degrees, radians, ceil
|
||||
|
||||
@@ -1513,46 +1513,56 @@ class ActivateDrawing(bpy.types.Operator):
|
||||
bl_idname = "bim.activate_drawing"
|
||||
bl_label = "Activate Drawing"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Activates the selected drawing view.\n\n" + "ALT+CLICK to keep the viewport position"
|
||||
bl_description = "Activates the selected drawing view.\n\n" + "ALT+CLICK to keep the viewport position.\n\n" + "SHIFT+CLICK activiate drawing without turning objects on/off."
|
||||
|
||||
drawing: bpy.props.IntProperty()
|
||||
camera_view_point: bpy.props.BoolProperty(name="Camera View Point", default=True, options={"SKIP_SAVE"})
|
||||
switch_camera_only: bpy.props.BoolProperty(name="Only Changes Camera View", default=False, options={"SKIP_SAVE"})
|
||||
|
||||
def invoke(self, context, event):
|
||||
# keep the viewport position on alt+click
|
||||
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
||||
if event.type == "LEFTMOUSE" and event.alt:
|
||||
self.camera_view_point = False
|
||||
# Only activates the camera view on shift+click. Does not turn on/off objects in scene
|
||||
if event.type == "LEFTMOUSE" and event.shift:
|
||||
self.switch_camera_only = True
|
||||
return self.execute(context)
|
||||
|
||||
def execute(self, context):
|
||||
if bpy.context.scene.DocProperties.is_editing_drawings == False:
|
||||
bpy.ops.bim.load_drawings()
|
||||
drawing = tool.Ifc.get().by_id(self.drawing)
|
||||
dprops = bpy.context.scene.DocProperties
|
||||
|
||||
if not self.camera_view_point:
|
||||
viewport_position = tool.Blender.get_viewport_position()
|
||||
if self.switch_camera_only:
|
||||
camera = tool.Drawing.import_drawing(drawing)
|
||||
tool.Blender.activate_camera(camera)
|
||||
else:
|
||||
if not self.camera_view_point:
|
||||
viewport_position = tool.Blender.get_viewport_position()
|
||||
|
||||
core.activate_drawing_view(tool.Ifc, tool.Blender, tool.Drawing, drawing=drawing)
|
||||
core.activate_drawing_view(tool.Ifc, tool.Blender, tool.Drawing, drawing=drawing)
|
||||
|
||||
if not self.camera_view_point:
|
||||
tool.Blender.set_viewport_position(viewport_position)
|
||||
if not self.camera_view_point:
|
||||
tool.Blender.set_viewport_position(viewport_position)
|
||||
|
||||
dprops.active_drawing_id = self.drawing
|
||||
# reset DrawingsData to reload_drawing_styles work correctly
|
||||
DrawingsData.is_loaded = False
|
||||
dprops.drawing_styles.clear()
|
||||
if ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing", "HasUnderlay"):
|
||||
bpy.ops.bim.reload_drawing_styles()
|
||||
bpy.ops.bim.activate_drawing_style()
|
||||
core.sync_references(tool.Ifc, tool.Collector, tool.Drawing, drawing=tool.Ifc.get().by_id(self.drawing))
|
||||
CutDecorator.install(context)
|
||||
tool.Drawing.show_decorations()
|
||||
dprops.active_drawing_id = self.drawing
|
||||
# reset DrawingsData to reload_drawing_styles work correctly
|
||||
DrawingsData.is_loaded = False
|
||||
dprops.drawing_styles.clear()
|
||||
if ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing", "HasUnderlay"):
|
||||
bpy.ops.bim.reload_drawing_styles()
|
||||
bpy.ops.bim.activate_drawing_style()
|
||||
core.sync_references(tool.Ifc, tool.Collector, tool.Drawing, drawing=tool.Ifc.get().by_id(self.drawing))
|
||||
CutDecorator.install(context)
|
||||
tool.Drawing.show_decorations()
|
||||
|
||||
# Save drawing bounds to the .ifc file
|
||||
camera = context.scene.camera
|
||||
camera_props = camera.data.BIMCameraProperties
|
||||
if camera_props.update_representation(camera):
|
||||
bpy.ops.bim.update_representation(obj=camera.name, ifc_representation_class="")
|
||||
# Save drawing bounds to the .ifc file
|
||||
camera = context.scene.camera
|
||||
camera_props = camera.data.BIMCameraProperties
|
||||
if camera_props.update_representation(camera):
|
||||
bpy.ops.bim.update_representation(obj=camera.name, ifc_representation_class="")
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ import bpy
|
||||
import json
|
||||
import enum
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.drawing as core
|
||||
import blenderbim.bim.module.drawing.annotation as annotation
|
||||
|
||||
@@ -29,6 +29,7 @@ import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.selector
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.module.drawing.helper as helper
|
||||
import blenderbim.bim.module.drawing.annotation as annotation
|
||||
|
||||
@@ -430,6 +430,19 @@ class BIM_PT_sheets(Panel):
|
||||
active_sheet = self.props.sheets[self.props.active_sheet_index]
|
||||
row = self.layout.row(align=True)
|
||||
row.alignment = "RIGHT"
|
||||
|
||||
if active_sheet.reference_type == "DRAWING":
|
||||
drawingnamesvg = active_sheet.name
|
||||
drawingname = drawingnamesvg.split('.')[0]
|
||||
ifc_file = tool.Ifc.get()
|
||||
ifc_annotations = ifc_file.by_type('IfcAnnotation')
|
||||
for annotation in ifc_annotations:
|
||||
if annotation.Name == drawingname:
|
||||
drawingid = annotation.id()
|
||||
drawing_button = row.row(align=True)
|
||||
op = drawing_button.operator("bim.activate_drawing", icon="OUTLINER_OB_CAMERA", text="")
|
||||
op.drawing = drawingid
|
||||
|
||||
row.operator("bim.edit_sheet", icon="GREASEPENCIL", text="")
|
||||
row.operator("bim.open_sheet", icon="URL", text="")
|
||||
row.operator("bim.add_drawing_to_sheet", icon="IMAGE_PLANE", text="")
|
||||
|
||||
@@ -18,8 +18,11 @@
|
||||
|
||||
import bpy
|
||||
import ifcopenshell.util.element
|
||||
import blenderbim.tool as tool
|
||||
import ifcopenshell.util.geolocation
|
||||
import ifcopenshell.util.placement
|
||||
import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.tool as tool
|
||||
from mathutils import Vector
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.AddGeoreferencing,
|
||||
operator.ConvertAngleToCoordinates,
|
||||
operator.DisableEditingGeoreferencing,
|
||||
operator.DisableEditingTrueNorth,
|
||||
operator.DisableEditingWCS,
|
||||
|
||||
@@ -20,7 +20,10 @@
|
||||
import bpy
|
||||
import numpy as np
|
||||
import blenderbim.tool as tool
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.geolocation
|
||||
import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.unit
|
||||
from mathutils import Matrix, Vector
|
||||
from ifcopenshell.util.doc import get_entity_doc
|
||||
|
||||
|
||||
@@ -87,23 +87,6 @@ class GetCursorLocation(bpy.types.Operator, tool.Ifc.Operator):
|
||||
core.get_cursor_location(tool.Georeference)
|
||||
|
||||
|
||||
class ConvertAngleToCoordinates(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.convert_angle_to_coord"
|
||||
bl_label = "Convert Angle To Y Axis"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Convert angle to Y axis"
|
||||
type: bpy.props.StringProperty()
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
file = tool.Ifc.get()
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
return file and (props.angle_degree_input_x or props.angle_degree_input_y)
|
||||
|
||||
def _execute(self, context):
|
||||
core.convert_angle_to_coord(tool.Georeference, type=self.type)
|
||||
|
||||
|
||||
class ImportPlot(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.import_plot"
|
||||
bl_label = "Import Plot"
|
||||
@@ -138,7 +121,7 @@ class EditWCS(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_description = "Edit the WCS"
|
||||
|
||||
def _execute(self, context):
|
||||
core.edit_wcs(tool.Ifc, tool.Georeference)
|
||||
core.edit_wcs(tool.Georeference)
|
||||
|
||||
|
||||
class DisableEditingWCS(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
{
|
||||
skymap.cal - Map a pre swewd sky picture onto a hemisphere
|
||||
|
||||
###########################################
|
||||
#
|
||||
# SKY PICTURE MAP
|
||||
#
|
||||
# Copyright (C) 1992 by Curtin University
|
||||
# School of Architecture
|
||||
#
|
||||
# Curtin University of Technology
|
||||
# Department of Architecture
|
||||
# GPO Box U 1987
|
||||
# Perth, Western Australia
|
||||
#
|
||||
# Version 1.1 October 1993.
|
||||
# Fixed NaN errors.
|
||||
#
|
||||
# Simon Crone
|
||||
# email: crones@puffin.curtin.edu.au
|
||||
#
|
||||
###########################################
|
||||
|
||||
A1 = aspect ratio ( height / width )
|
||||
}
|
||||
|
||||
u_scale = if( A1 -1, 1, A1);
|
||||
v_scale = if( A1 -1, A1, 1);
|
||||
|
||||
hang = if( abs( Dx) - FTINY,
|
||||
atan2( Dy, Dx),
|
||||
if( Dy, PI/2, -PI/2 )
|
||||
);
|
||||
|
||||
map_u = ( (hang + PI ) / (PI*2) ) / u_scale;
|
||||
map_v = ( (asin( Dz) + (PI/2) ) / PI ) / v_scale;
|
||||
|
||||
@@ -25,8 +25,9 @@ from pathlib import Path
|
||||
import importlib
|
||||
import pyradiance
|
||||
|
||||
|
||||
def get_pyradiance_path():
|
||||
return importlib.util.find_spec('pyradiance').submodule_search_locations[0]
|
||||
return importlib.util.find_spec("pyradiance").submodule_search_locations[0]
|
||||
|
||||
|
||||
classes = (
|
||||
|
||||
@@ -34,10 +34,15 @@ class SolarData:
|
||||
def load(cls):
|
||||
cls.is_loaded = True
|
||||
cls.data = {
|
||||
"sun_position": cls.sun_position(),
|
||||
"sites": cls.sites(),
|
||||
"true_north": cls.true_north(),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def sun_position(cls):
|
||||
return tool.Blender.get_sun_position_addon()
|
||||
|
||||
@classmethod
|
||||
def sites(cls):
|
||||
results = []
|
||||
|
||||
@@ -28,8 +28,6 @@ from gpu_extras.batch import batch_for_shader
|
||||
from bpy_extras.view3d_utils import location_3d_to_region_2d
|
||||
from blenderbim.bim.module.light.data import SolarData
|
||||
|
||||
sun_position = tool.Blender.get_sun_position_addon()
|
||||
|
||||
|
||||
class SolarDecorator:
|
||||
is_installed = False
|
||||
@@ -149,7 +147,7 @@ class SolarDecorator:
|
||||
indices = []
|
||||
coord_offset = 0
|
||||
for h in range(24):
|
||||
analemma_verts = sun_position.sun_calc.calc_analemma(context, h)
|
||||
analemma_verts = SolarData.data["sun_position"].sun_calc.calc_analemma(context, h)
|
||||
coords.extend([origin @ v for v in analemma_verts])
|
||||
for i in range(len(analemma_verts) - 1):
|
||||
indices.append((coord_offset + i, coord_offset + i + 1))
|
||||
|
||||
@@ -127,7 +127,7 @@ class RadianceRender(bpy.types.Operator):
|
||||
return {"CANCELLED"}
|
||||
|
||||
# Get the resolution from the user input
|
||||
|
||||
|
||||
props = context.scene.radiance_exporter_properties
|
||||
resolution_x, resolution_y = props.radiance_resolution_x, props.radiance_resolution_y
|
||||
quality = props.radiance_quality.upper()
|
||||
@@ -136,7 +136,16 @@ class RadianceRender(bpy.types.Operator):
|
||||
output_dir = props.output_dir
|
||||
output_file_name = props.output_file_name
|
||||
output_file_format = props.output_file_format
|
||||
os.chdir(output_dir)
|
||||
use_hdr = props.use_hdr
|
||||
choose_hdr_image = props.choose_hdr_image
|
||||
if use_hdr:
|
||||
hdr_image = "noon_grass_2k.hdr"
|
||||
hdr_mask = "noon_grass_2k_mask.hdr"
|
||||
sky_map_cal = "skymap.cal"
|
||||
hdr_image_path = os.path.join(os.path.dirname(__file__), "HDRs", hdr_image)
|
||||
hdr_mask_path = os.path.join(os.path.dirname(__file__), "HDRs", hdr_mask)
|
||||
sky_map_cal_path = os.path.join(os.path.dirname(__file__), "HDRs", sky_map_cal)
|
||||
# os.chdir(output_dir)
|
||||
|
||||
obj_file_path = os.path.join(output_dir, "model.obj")
|
||||
|
||||
@@ -150,7 +159,6 @@ class RadianceRender(bpy.types.Operator):
|
||||
hour = sun_props.hour
|
||||
minute = sun_props.minute
|
||||
|
||||
|
||||
camera = self.get_active_camera(context)
|
||||
if camera is None:
|
||||
self.report({"ERROR"}, "No active camera found in the scene. Please add a camera and set it as active.")
|
||||
@@ -159,7 +167,6 @@ class RadianceRender(bpy.types.Operator):
|
||||
# Get camera position and direction
|
||||
camera_position, camera_direction = self.get_camera_data(camera)
|
||||
|
||||
|
||||
dt = datetime(2024, month, day, hour, minute)
|
||||
|
||||
sky_description = pr.gensky(
|
||||
@@ -171,10 +178,10 @@ class RadianceRender(bpy.types.Operator):
|
||||
sunny_without_sun=False,
|
||||
cloudy=True,
|
||||
ground_reflectance=0.2,
|
||||
turbidity=3.0
|
||||
)
|
||||
turbidity=3.0,
|
||||
)
|
||||
|
||||
sky_description_str = sky_description.decode('utf-8')
|
||||
sky_description_str = sky_description.decode("utf-8")
|
||||
|
||||
# Write all this to file
|
||||
# skyfunc glow sky_glow
|
||||
@@ -196,18 +203,24 @@ class RadianceRender(bpy.types.Operator):
|
||||
# 0
|
||||
# 0
|
||||
# 4 0 0 -1 180
|
||||
with open(sky_file_path, 'w') as f:
|
||||
f.write(sky_description_str)
|
||||
f.write("\n")
|
||||
# f.write("skyfunc glow sky_glow\n0\n0\n4 .9 .9 1.15 0\n")
|
||||
# f.write("sky_glow source sky\n0\n0\n4 0 0 1 180\n")
|
||||
# f.write("skyfunc glow ground_glow\n0\n0\n4 1.4 .9 .6 0\n")
|
||||
# f.write("ground_glow source ground\n0\n0\n4 0 0 -1 180\n")
|
||||
# File write
|
||||
# 2k version is packaged with the repo
|
||||
|
||||
f.write("""void colorpict env_map
|
||||
7 red green blue noon_grass_16k.hdr skymap.cal map_u map_v
|
||||
if choose_hdr_image == "Noon":
|
||||
|
||||
with open(sky_file_path, "w") as f:
|
||||
f.write(sky_description_str)
|
||||
f.write("\n")
|
||||
# f.write("skyfunc glow sky_glow\n0\n0\n4 .9 .9 1.15 0\n")
|
||||
# f.write("sky_glow source sky\n0\n0\n4 0 0 1 180\n")
|
||||
# f.write("skyfunc glow ground_glow\n0\n0\n4 1.4 .9 .6 0\n")
|
||||
# f.write("ground_glow source ground\n0\n0\n4 0 0 -1 180\n")
|
||||
|
||||
f.write(
|
||||
'''void colorpict env_map
|
||||
7 red green blue "'''
|
||||
+ hdr_image_path
|
||||
+ '''" "'''
|
||||
+ sky_map_cal_path
|
||||
+ '''" map_u map_v
|
||||
0
|
||||
1 0.5
|
||||
|
||||
@@ -226,7 +239,11 @@ skyfunc colorfunc sky_colour
|
||||
0
|
||||
|
||||
void mixpict composite
|
||||
7 env_colour sky_colour grey noon_grass_2k_mask.hdr skymap.cal map_u map_v
|
||||
7 env_colour sky_colour grey "'''
|
||||
+ hdr_mask_path
|
||||
+ '''" "'''
|
||||
+ sky_map_cal_path
|
||||
+ """" map_u map_v
|
||||
0
|
||||
2 0.5 1
|
||||
|
||||
@@ -248,8 +265,17 @@ env_colour glow ground_glow
|
||||
ground_glow source ground
|
||||
0
|
||||
0
|
||||
4 0 0 -1 180""")
|
||||
4 0 0 -1 180"""
|
||||
)
|
||||
|
||||
else:
|
||||
with open(sky_file_path, "w") as f:
|
||||
f.write(sky_description_str)
|
||||
f.write("\n")
|
||||
f.write("skyfunc glow sky_glow\n0\n0\n4 .9 .9 1.15 0\n")
|
||||
f.write("sky_glow source sky\n0\n0\n4 0 0 1 180\n")
|
||||
f.write("skyfunc glow ground_glow\n0\n0\n4 1.4 .9 .6 0\n")
|
||||
f.write("ground_glow source ground\n0\n0\n4 0 0 -1 180\n")
|
||||
|
||||
props = context.scene.radiance_exporter_properties
|
||||
|
||||
@@ -258,7 +284,7 @@ ground_glow source ground
|
||||
data = json.load(file)
|
||||
else:
|
||||
data = props.get_mappings_dict()
|
||||
|
||||
|
||||
materials_file = os.path.join(output_dir, "materials.rad")
|
||||
with open(materials_file, "w") as file:
|
||||
file.write("void plastic white\n0\n0\n5 0.8 0.8 0.8 0 0\n")
|
||||
@@ -270,7 +296,7 @@ ground_glow source ground
|
||||
file.write("void trans olive_trans\n0\n0\n7 0.6 0.7 0.4 0.05 0.05 0.7 0.2\n")
|
||||
|
||||
for style_id, radiance_material in data.items():
|
||||
print(style_id, radiance_material)
|
||||
# print(style_id, radiance_material)
|
||||
file.write("inherit alias " + style_id + " " + data.get(style_id, "white") + "\n")
|
||||
|
||||
self.report({"INFO"}, "Exported Materials Rad file to: {}".format(materials_file))
|
||||
@@ -307,21 +333,20 @@ ground_glow source ground
|
||||
detail=detail,
|
||||
variability=variability,
|
||||
)
|
||||
|
||||
hdr_path = os.path.join(output_dir, f"render123.{output_file_format.lower()}")
|
||||
|
||||
output_hdr_path = os.path.join(output_dir, f"render123.{output_file_format.lower()}")
|
||||
|
||||
if output_file_format == "HDR":
|
||||
with open(hdr_path, "wb") as wtr:
|
||||
with open(output_hdr_path, "wb") as wtr:
|
||||
wtr.write(image)
|
||||
else:
|
||||
pass
|
||||
|
||||
pcond_image = pr.pcond(hdr=hdr_path, human=True)
|
||||
|
||||
pcond_image = pr.pcond(hdr=output_hdr_path, human=True)
|
||||
|
||||
tiff_path = os.path.join(output_dir, f"{output_file_name}.tiff")
|
||||
|
||||
pr.ra_tiff(inp = pcond_image, out = tiff_path, lzw=True)
|
||||
|
||||
pr.ra_tiff(inp=pcond_image, out=tiff_path, lzw=True)
|
||||
|
||||
self.report({"INFO"}, "Radiance rendering completed. Output: {}".format(tiff_path))
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -23,13 +23,19 @@ import datetime
|
||||
import blenderbim.tool as tool
|
||||
from math import radians, pi
|
||||
from mathutils import Euler, Vector, Matrix, Quaternion
|
||||
from bpy.props import IntProperty, StringProperty, EnumProperty, FloatProperty, FloatVectorProperty, BoolProperty, CollectionProperty
|
||||
from bpy.props import (
|
||||
IntProperty,
|
||||
StringProperty,
|
||||
EnumProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty,
|
||||
BoolProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
from bpy.types import PropertyGroup
|
||||
from blenderbim.bim.module.light.data import SolarData
|
||||
from blenderbim.bim.module.light.decorator import SolarDecorator
|
||||
|
||||
sun_position = tool.Blender.get_sun_position_addon()
|
||||
|
||||
|
||||
def get_sites(self, context):
|
||||
if not SolarData.is_loaded:
|
||||
@@ -95,6 +101,12 @@ def update_display_sun_path(self, context):
|
||||
|
||||
|
||||
def update_sun_path():
|
||||
if not SolarData.is_loaded:
|
||||
SolarData.load()
|
||||
|
||||
if (sun_position := SolarData.data["sun_position"]) is None:
|
||||
return
|
||||
|
||||
props = bpy.context.scene.BIMSolarProperties
|
||||
sun_props = bpy.context.scene.sun_pos_properties
|
||||
props.timezone = tzfpy.get_tz(props.longitude, props.latitude)
|
||||
@@ -247,11 +259,26 @@ class RadianceExporterProperties(PropertyGroup):
|
||||
name="Output File Format",
|
||||
description="Format of the output image file",
|
||||
items=[
|
||||
("HDR", "HDR", "High Dynamic Range"),
|
||||
("HDR", "HDR + Tiff", "High Dynamic Range"),
|
||||
],
|
||||
default="HDR",
|
||||
)
|
||||
|
||||
use_hdr: BoolProperty(
|
||||
name="Use HDR",
|
||||
description="Use HDR image format",
|
||||
default=True,
|
||||
)
|
||||
|
||||
choose_hdr_image: EnumProperty(
|
||||
name="HDR Image",
|
||||
description="Choose an HDR image to use",
|
||||
items=[
|
||||
("Noon", "Noon", "Noon"),
|
||||
],
|
||||
default="Noon",
|
||||
)
|
||||
|
||||
|
||||
class BIMSolarProperties(PropertyGroup):
|
||||
sites: EnumProperty(items=get_sites, name="Sites")
|
||||
|
||||
@@ -21,9 +21,6 @@ import blenderbim.tool as tool
|
||||
from blenderbim.bim.module.light.data import SolarData
|
||||
|
||||
|
||||
sun_position = tool.Blender.get_sun_position_addon()
|
||||
|
||||
|
||||
class BIM_PT_radiance_exporter(bpy.types.Panel):
|
||||
"""Creates a Panel in the render properties window"""
|
||||
|
||||
@@ -95,6 +92,12 @@ class BIM_PT_radiance_exporter(bpy.types.Panel):
|
||||
row.prop(props, "output_file_format")
|
||||
layout.separator()
|
||||
|
||||
row = layout.row()
|
||||
row.prop(props, "use_hdr")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(props, "choose_hdr_image")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("export_scene.radiance", text="Export Geometry for Simulation")
|
||||
|
||||
@@ -115,13 +118,13 @@ class BIM_PT_solar(bpy.types.Panel):
|
||||
bl_options = {"HIDE_HEADER"}
|
||||
|
||||
def draw(self, context):
|
||||
if sun_position is None:
|
||||
self.layout.label(text="Enable 'Sun Position' addon to continue.")
|
||||
return
|
||||
|
||||
if not SolarData.is_loaded:
|
||||
SolarData.load()
|
||||
|
||||
if (sun_position := SolarData.data["sun_position"]) is None:
|
||||
self.layout.label(text="Enable 'Sun Position' Add-on To Continue", icon="ERROR")
|
||||
return
|
||||
|
||||
props = context.scene.BIMSolarProperties
|
||||
|
||||
if SolarData.data["sites"]:
|
||||
|
||||
@@ -22,6 +22,7 @@ import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.attribute
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.style
|
||||
|
||||
@@ -21,6 +21,7 @@ import json
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.tool as tool
|
||||
from mathutils import Vector, Matrix
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import math
|
||||
import json
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.schema
|
||||
from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc
|
||||
import blenderbim.tool as tool
|
||||
from math import degrees
|
||||
|
||||
@@ -25,6 +25,8 @@ import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.unit
|
||||
from ifcopenshell.util.shape_builder import V
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.geometry
|
||||
|
||||
@@ -21,6 +21,7 @@ import json
|
||||
import bmesh
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.core.root
|
||||
|
||||
@@ -1874,8 +1874,7 @@ class AppendInspectedLinkedElement(AppendLibraryElement):
|
||||
)
|
||||
self.import_product_from_ifc(element, context)
|
||||
element_type = ifcopenshell.util.element.get_type(element)
|
||||
obj = tool.Ifc.get_object(element_type)
|
||||
if obj is None:
|
||||
if element_type and tool.Ifc.get_object(element_type) is None:
|
||||
self.import_type_from_ifc(element_type, context)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import os
|
||||
import bpy
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.placement
|
||||
from blenderbim.bim.module.project.data import ProjectData
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
@@ -128,6 +128,15 @@ class BIM_PT_project(Panel):
|
||||
if pprops.is_loading:
|
||||
self.draw_advanced_loading_ui(context)
|
||||
elif self.file or props.ifc_file:
|
||||
if props.has_blend_warning:
|
||||
box = self.layout.box()
|
||||
box.alert = True
|
||||
row = box.row(align=True)
|
||||
row.label(text="Your Model May Be Outdated", icon="ERROR")
|
||||
op = row.operator("bim.open_uri", text="", icon="QUESTION")
|
||||
op.uri = "https://docs.blenderbim.org/users/troubleshooting.html#saving-and-loading-blend-files"
|
||||
row.operator("bim.close_blend_warning", text="", icon="CANCEL")
|
||||
|
||||
if props.ifc_file:
|
||||
self.draw_loaded_project_ui(context)
|
||||
else:
|
||||
|
||||
@@ -19,9 +19,10 @@
|
||||
import bpy
|
||||
import json
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.pset
|
||||
import ifcopenshell.util.attribute
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.pset
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.bim.schema
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.bim.handler
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
import bpy
|
||||
import blenderbim.tool as tool
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.constraint
|
||||
import ifcopenshell.util.cost
|
||||
import ifcopenshell.util.date
|
||||
import ifcopenshell.util.resource
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.schema
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.module.root.data import IfcClassData
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
import bpy
|
||||
import blenderbim.tool as tool
|
||||
from ifcopenshell import util
|
||||
import ifcopenshell.util.schema
|
||||
from blenderbim.bim.prop import ObjProperty, BIMFilterGroup
|
||||
from blenderbim.bim.module.search.data import SearchData, ColourByPropertyData, SelectSimilarData
|
||||
from bpy.types import PropertyGroup
|
||||
@@ -134,6 +134,6 @@ class BIMSearchProperties(PropertyGroup):
|
||||
|
||||
def get_classes(self, ifc_product):
|
||||
declaration = tool.Ifc.schema().declaration_by_name(ifc_product)
|
||||
declarations = util.schema.get_subtypes(declaration)
|
||||
declarations = ifcopenshell.util.schema.get_subtypes(declaration)
|
||||
names = [d.name() for d in declarations]
|
||||
return [(c, c, "") for c in sorted(names)]
|
||||
|
||||
@@ -20,6 +20,7 @@ import bpy
|
||||
import isodate
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.attribute
|
||||
import ifcopenshell.util.date
|
||||
from ifcopenshell.util.doc import get_predefined_type_doc
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.sequence as core
|
||||
|
||||
@@ -83,7 +83,8 @@ class AssignContainer(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
if container := tool.Root.get_default_container():
|
||||
props = context.active_object.BIMObjectSpatialProperties
|
||||
if (container_obj := props.container_obj) and (container := tool.Ifc.get_entity(container_obj)):
|
||||
for element_obj in context.selected_objects:
|
||||
core.assign_container(
|
||||
tool.Ifc, tool.Collector, tool.Spatial, container=container, element_obj=element_obj
|
||||
|
||||
@@ -64,34 +64,32 @@ def update_should_include_children(self, context):
|
||||
tool.Spatial.load_contained_elements()
|
||||
|
||||
|
||||
def update_relating_container_from_object(self, context):
|
||||
if self.relating_container_object is None or context.active_object is None:
|
||||
def update_container_obj(self, context):
|
||||
if self.container_obj is None or not (obj := context.active_object):
|
||||
return
|
||||
element = tool.Ifc.get_entity(self.relating_container_object)
|
||||
if not element:
|
||||
if not (element := tool.Ifc.get_entity(self.container_obj)):
|
||||
self.container_obj = None
|
||||
return
|
||||
container = ifcopenshell.util.element.get_container(element)
|
||||
if container:
|
||||
# TODO: currently broken and relating_container_object is not used in UI.
|
||||
bpy.ops.bim.assign_container(structure=container.id())
|
||||
else:
|
||||
bpy.ops.bim.disable_editing_container()
|
||||
bpy.ops.bim.remove_container()
|
||||
if tool.Spatial.can_contain(element, obj):
|
||||
return
|
||||
if (
|
||||
(container := ifcopenshell.util.element.get_container(element))
|
||||
and (container_obj := tool.Ifc.get_object(container))
|
||||
and tool.Spatial.can_contain(container, obj)
|
||||
):
|
||||
self.container_obj = container_obj
|
||||
return
|
||||
self.container_obj = None
|
||||
|
||||
|
||||
def is_object_applicable(self, obj):
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
return bool(element)
|
||||
def poll_container_obj(self, obj):
|
||||
return obj is None or tool.Ifc.get_entity(obj)
|
||||
|
||||
|
||||
class BIMObjectSpatialProperties(PropertyGroup):
|
||||
is_editing: BoolProperty(name="Is Editing")
|
||||
relating_container_object: PointerProperty(
|
||||
type=bpy.types.Object,
|
||||
name="Copy Container",
|
||||
update=update_relating_container_from_object,
|
||||
poll=is_object_applicable,
|
||||
description="Copy the target object's container to the active object",
|
||||
container_obj: PointerProperty(
|
||||
type=bpy.types.Object, name="Container", update=update_container_obj, poll=poll_container_obj
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -36,10 +36,6 @@ class BIM_PT_spatial(Panel):
|
||||
return SpatialData.data["poll"]
|
||||
|
||||
def draw(self, context):
|
||||
# TODO: expose relating_container_object so users could
|
||||
# assign container without switching default container back and forth
|
||||
# just for 1 operation.
|
||||
|
||||
if not SpatialData.is_loaded:
|
||||
SpatialData.load()
|
||||
|
||||
@@ -48,8 +44,8 @@ class BIM_PT_spatial(Panel):
|
||||
if osprops.is_editing:
|
||||
if SpatialData.data["default_container"]:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"Target: {SpatialData.data['default_container']}", icon="OUTLINER_COLLECTION")
|
||||
row.operator("bim.assign_container", icon="CHECKMARK", text="Reassign Container")
|
||||
row.prop(osprops, "container_obj", text="", icon="OUTLINER_COLLECTION")
|
||||
row.operator("bim.assign_container", icon="CHECKMARK", text="")
|
||||
row.operator("bim.disable_editing_container", icon="CANCEL", text="")
|
||||
|
||||
if SpatialData.data["selected_containers"]:
|
||||
@@ -82,14 +78,14 @@ class BIM_PT_spatial(Panel):
|
||||
row.label(text="No Spatial Container")
|
||||
row.operator("bim.enable_editing_container", icon="GREASEPENCIL", text="")
|
||||
|
||||
references = SpatialData.data["references"]
|
||||
if references:
|
||||
self.layout.label(text="Referenced In Structures:")
|
||||
if references := SpatialData.data["references"]:
|
||||
self.layout.label(text=f"{len(references)} References:")
|
||||
else:
|
||||
self.layout.label(text="No References Found")
|
||||
|
||||
for reference in references:
|
||||
row = self.layout.row()
|
||||
row.label(text=reference, icon="LINKED")
|
||||
else:
|
||||
self.layout.label(text="No References In Structures")
|
||||
|
||||
|
||||
class BIM_PT_spatial_decomposition(Panel):
|
||||
|
||||
@@ -25,6 +25,7 @@ import blenderbim.core.style as core
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.api.style
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.unit
|
||||
from pathlib import Path
|
||||
from mathutils import Vector
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.system
|
||||
import ifcopenshell.util.unit
|
||||
from ifcopenshell.util.doc import get_entity_doc
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
@@ -441,7 +441,7 @@ class AddType(bpy.types.Operator, tool.Ifc.Operator):
|
||||
tool.Root,
|
||||
obj=obj,
|
||||
predefined_type=predefined_type,
|
||||
ifc_class="IfcStairFlightType",
|
||||
ifc_class=ifc_class,
|
||||
should_add_representation=False,
|
||||
)
|
||||
tool.Blender.select_and_activate_single_object(context, obj)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.type
|
||||
from blenderbim.bim.module.type.data import TypeData
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
|
||||
@@ -100,7 +100,26 @@ class CloseError(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
def draw(self, context):
|
||||
self.layout.label(text="Warning: your model may be damaged. Really continue?")
|
||||
col = self.layout.column()
|
||||
col.label(text="Warning: your model may be damaged.")
|
||||
col.label(text="Really continue?")
|
||||
|
||||
|
||||
|
||||
def invoke(self, context, event):
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
|
||||
class CloseBlendWarning(bpy.types.Operator):
|
||||
bl_idname = "bim.close_blend_warning"
|
||||
bl_label = "Close Blend Warning"
|
||||
|
||||
def execute(self, context):
|
||||
bpy.context.scene.BIMProperties.has_blend_warning = False
|
||||
return {"FINISHED"}
|
||||
|
||||
def draw(self, context):
|
||||
self.layout.label(text="Warning: you may experience errors. Really continue?")
|
||||
|
||||
def invoke(self, context, event):
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
@@ -23,6 +23,7 @@ import json
|
||||
import importlib
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.pset
|
||||
import ifcopenshell.util.unit
|
||||
from ifcopenshell.util.doc import (
|
||||
get_entity_doc,
|
||||
get_attribute_doc,
|
||||
@@ -385,6 +386,7 @@ class BIMProperties(PropertyGroup):
|
||||
data_dir: StringProperty(
|
||||
default=os.path.join(cwd, "data") + os.path.sep, name="Data Directory", update=update_data_dir
|
||||
)
|
||||
has_blend_warning: BoolProperty(name="Has Blend Warning", default=False)
|
||||
pset_dir: StringProperty(default=os.path.join("psets") + os.path.sep, name="Default Psets Directory")
|
||||
ifc_file: StringProperty(name="IFC File", update=update_ifc_file)
|
||||
last_transaction: StringProperty(name="Last Transaction")
|
||||
|
||||
@@ -38,8 +38,8 @@ def disable_editing_georeferencing(georeference):
|
||||
def edit_georeferencing(ifc, georeference):
|
||||
ifc.run(
|
||||
"georeference.edit_georeferencing",
|
||||
projected_crs=georeference.get_projected_crs_attributes(),
|
||||
coordinate_operation=georeference.get_coordinate_operation_attributes(),
|
||||
projected_crs=georeference.export_projected_crs(),
|
||||
coordinate_operation=georeference.export_coordinate_operation(),
|
||||
)
|
||||
georeference.disable_editing()
|
||||
georeference.set_model_origin()
|
||||
@@ -47,17 +47,12 @@ def edit_georeferencing(ifc, georeference):
|
||||
|
||||
def get_cursor_location(georeference):
|
||||
location = georeference.get_cursor_location()
|
||||
if georeference.has_blender_offset:
|
||||
if georeference.has_blender_offset():
|
||||
georeference.set_coordinates("blender", location)
|
||||
else:
|
||||
georeference.set_coordinates("local", location)
|
||||
|
||||
|
||||
def convert_angle_to_coord(georeference, type):
|
||||
vector_coordinates = georeference.angle2coords(georeference.get_angle(type), type)
|
||||
georeference.set_vector_coordinates(vector_coordinates, type)
|
||||
|
||||
|
||||
def import_plot(georeference, filepath):
|
||||
georeference.import_plot(filepath)
|
||||
|
||||
@@ -71,7 +66,7 @@ def disable_editing_wcs(georeference):
|
||||
georeference.disable_editing_wcs()
|
||||
|
||||
|
||||
def edit_wcs(ifc, georeference):
|
||||
def edit_wcs(georeference):
|
||||
wcs = georeference.export_wcs()
|
||||
georeference.set_wcs(wcs)
|
||||
georeference.disable_editing_wcs()
|
||||
|
||||
@@ -62,6 +62,7 @@ def assign_container(
|
||||
|
||||
|
||||
def enable_editing_container(spatial: tool.Spatial, obj: bpy.types.Object) -> None:
|
||||
spatial.set_target_container_as_default()
|
||||
spatial.enable_editing(obj)
|
||||
|
||||
|
||||
|
||||
@@ -430,31 +430,27 @@ class Geometry:
|
||||
|
||||
@interface
|
||||
class Georeference:
|
||||
def angle2coords(cls, angle, type): pass
|
||||
def add_georeferencing(cls): pass
|
||||
def disable_editing(cls): pass
|
||||
def disable_editing_true_north(cls): pass
|
||||
def disable_editing_wcs(cls): pass
|
||||
def enable_editing(cls): pass
|
||||
def enable_editing_true_north(cls): pass
|
||||
def enable_editing_wcs(cls): pass
|
||||
def enh2xyz(cls, coordinates): pass
|
||||
def export_coordinate_operation(cls): pass
|
||||
def export_projected_crs(cls): pass
|
||||
def export_wcs(cls): pass
|
||||
def get_angle(cls, type): pass
|
||||
def get_coordinate_operation_attributes(cls): pass
|
||||
def get_coordinates(cls, io): pass
|
||||
def get_cursor_location(cls): pass
|
||||
def get_projected_crs_attributes(cls): pass
|
||||
def get_true_north_attributes(cls): pass
|
||||
def import_map_conversion(cls): pass
|
||||
def has_blender_offset(cls): pass
|
||||
def import_coordinate_operation(cls): pass
|
||||
def import_projected_crs(cls): pass
|
||||
def import_true_north(cls): pass
|
||||
def import_wcs(cls): pass
|
||||
def set_blender_grid_north(cls): pass
|
||||
def set_blender_true_north(cls): pass
|
||||
def set_coordinates(cls, io, coordinates): pass
|
||||
def set_cursor_location(cls, coordinates): pass
|
||||
def set_ifc_grid_north(cls): pass
|
||||
def set_ifc_true_north(cls): pass
|
||||
def set_model_origin(cls): pass
|
||||
def set_vector_coordinates(cls, vector_coordinates, type): pass
|
||||
def set_wcs(cls, matrix): pass
|
||||
def xyz2enh(cls, coordinates): pass
|
||||
|
||||
@@ -884,6 +880,7 @@ class Spatial:
|
||||
def select_products(cls, products, unhide=False): pass
|
||||
def set_active_object(cls, obj): pass
|
||||
def set_relative_object_matrix(cls, target_obj, relative_to_obj, matrix): pass
|
||||
def set_target_container_as_default(cls): pass
|
||||
def show_scene_objects(cls): pass
|
||||
|
||||
# HERE STARTS SPATIAL TOOL
|
||||
|
||||
@@ -20,6 +20,7 @@ import bpy
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
from typing import Union
|
||||
|
||||
|
||||
|
||||
@@ -822,7 +822,9 @@ class Blender(blenderbim.core.tool.Blender):
|
||||
|
||||
@classmethod
|
||||
def is_eligible_for_stair_modifier(cls, obj):
|
||||
return tool.Blender.is_object_an_ifc_class(obj, ("IfcStairFlight", "IfcStairFlightType"))
|
||||
return tool.Blender.is_object_an_ifc_class(
|
||||
obj, ("IfcStairFlight", "IfcStairFlightType", "IfcMember", "IfcMemberType")
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def is_eligible_for_window_modifier(cls, obj):
|
||||
|
||||
@@ -21,6 +21,8 @@ import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.guid
|
||||
import ifcopenshell.util.brick
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.system
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
from contextlib import contextmanager
|
||||
|
||||
@@ -25,8 +25,20 @@ from typing import Union
|
||||
|
||||
class Collector(blenderbim.core.tool.Collector):
|
||||
@classmethod
|
||||
def assign(cls, obj: bpy.types.Object) -> None:
|
||||
def assign(cls, obj: bpy.types.Object, should_clean_users_collection=True) -> None:
|
||||
"""Links an object to an appropriate Blender collection."""
|
||||
if should_clean_users_collection:
|
||||
for users_collection in obj.users_collection:
|
||||
if obj.BIMObjectProperties.collection == users_collection:
|
||||
continue
|
||||
# Users are free to user extra collections for their own
|
||||
# purposes except for the reserved keyword "Ifc" and
|
||||
# "Collection" (which is the default collection that comes with
|
||||
# a Blender session)
|
||||
if "Ifc" in users_collection.name or users_collection.name == "Collection":
|
||||
print('removing', users_collection, 'from', obj)
|
||||
users_collection.objects.unlink(obj)
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
|
||||
if element.is_a("IfcGridAxis"):
|
||||
|
||||
@@ -2,6 +2,7 @@ import os
|
||||
import bpy
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.date
|
||||
import ifcopenshell.util.cost
|
||||
|
||||
@@ -700,7 +700,7 @@ class Geometry(blenderbim.core.tool.Geometry):
|
||||
|
||||
@classmethod
|
||||
def link(cls, element: ifcopenshell.entity_instance, obj: bpy.types.Mesh) -> None:
|
||||
obj.BIMMeshProperties.ifc_definition_id = element.id()
|
||||
tool.Ifc.link(element, obj)
|
||||
|
||||
@classmethod
|
||||
def record_object_materials(cls, obj: bpy.types.Object) -> None:
|
||||
|
||||
@@ -27,7 +27,6 @@ import ifcopenshell.util.unit
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.helper
|
||||
from math import radians, cos, sin
|
||||
|
||||
|
||||
class Georeference(blenderbim.core.tool.Georeference):
|
||||
@@ -151,7 +150,7 @@ class Georeference(blenderbim.core.tool.Georeference):
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def get_projected_crs_attributes(cls):
|
||||
def export_projected_crs(cls):
|
||||
def callback(attributes, prop):
|
||||
if not prop.is_null and prop.name == "MapUnit":
|
||||
attributes[prop.name] = tool.Ifc.get().by_id(int(prop.enum_value))
|
||||
@@ -161,7 +160,7 @@ class Georeference(blenderbim.core.tool.Georeference):
|
||||
return blenderbim.bim.helper.export_attributes(props.projected_crs, callback=callback)
|
||||
|
||||
@classmethod
|
||||
def get_coordinate_operation_attributes(cls):
|
||||
def export_coordinate_operation(cls):
|
||||
measure_type = None
|
||||
|
||||
def callback(attributes, prop):
|
||||
@@ -238,12 +237,6 @@ class Georeference(blenderbim.core.tool.Georeference):
|
||||
scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
return [o / scale for o in bpy.context.scene.cursor.location]
|
||||
|
||||
@classmethod
|
||||
def set_cursor_location(cls):
|
||||
coordinates = cls.get_coordinates("local")
|
||||
scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
bpy.context.scene.cursor.location = [co * scale for co in coordinates]
|
||||
|
||||
@classmethod
|
||||
def xyz2enh(cls, coordinates, should_return_in_map_units=True):
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
@@ -279,30 +272,6 @@ class Georeference(blenderbim.core.tool.Georeference):
|
||||
)
|
||||
return coordinates
|
||||
|
||||
@classmethod
|
||||
def angle2coords(cls, angle, type):
|
||||
if type == "rel_x":
|
||||
return ifcopenshell.util.geolocation.angle2xaxis(angle)
|
||||
elif type == "rel_y":
|
||||
return ifcopenshell.util.geolocation.angle2yaxis(angle)
|
||||
|
||||
@classmethod
|
||||
def get_angle(cls, type):
|
||||
if type == "rel_x":
|
||||
return bpy.context.scene.BIMGeoreferenceProperties.angle_degree_input_x
|
||||
elif type == "rel_y":
|
||||
return bpy.context.scene.BIMGeoreferenceProperties.angle_degree_input_y
|
||||
|
||||
@classmethod
|
||||
def set_vector_coordinates(cls, vector_coordinates, type):
|
||||
x, y = vector_coordinates
|
||||
if type == "rel_x":
|
||||
bpy.context.scene.BIMGeoreferenceProperties.x_axis_abscissa_output = str(x)
|
||||
bpy.context.scene.BIMGeoreferenceProperties.x_axis_ordinate_output = str(y)
|
||||
elif type == "rel_y":
|
||||
bpy.context.scene.BIMGeoreferenceProperties.y_axis_abscissa_output = str(x)
|
||||
bpy.context.scene.BIMGeoreferenceProperties.y_axis_ordinate_output = str(y)
|
||||
|
||||
@classmethod
|
||||
def import_plot(cls, filepath):
|
||||
import bmesh
|
||||
|
||||
@@ -94,10 +94,18 @@ class Ifc(blenderbim.core.tool.Ifc):
|
||||
Return None if object is not linked to IFC or it's linked to non-existent element.
|
||||
"""
|
||||
ifc = IfcStore.get_file()
|
||||
props = getattr(obj, "BIMObjectProperties", None)
|
||||
if ifc and props and props.ifc_definition_id:
|
||||
if not ifc:
|
||||
return
|
||||
|
||||
props = None
|
||||
if isinstance(obj, bpy.types.Object):
|
||||
props = obj.BIMObjectProperties
|
||||
elif isinstance(obj, bpy.types.Material):
|
||||
props = obj.BIMStyleProperties
|
||||
|
||||
if props and (ifc_definition_id := props.ifc_definition_id):
|
||||
try:
|
||||
return ifc.by_id(props.ifc_definition_id)
|
||||
return ifc.by_id(ifc_definition_id)
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ import bpy
|
||||
import bmesh
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.geolocation
|
||||
import ifcopenshell.util.placement
|
||||
import ifcopenshell.util.shape
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.core.tool
|
||||
@@ -91,6 +93,8 @@ class Loader(blenderbim.core.tool.Loader):
|
||||
|
||||
@classmethod
|
||||
def get_name(cls, element: ifcopenshell.entity_instance) -> str:
|
||||
if element.is_a("IfcGridAxis"):
|
||||
return "{}/{}".format(element.is_a(), element.AxisTag)
|
||||
return "{}/{}".format(element.is_a(), getattr(element, "Name", "None"))
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -173,7 +173,7 @@ class Root(blenderbim.core.tool.Root):
|
||||
|
||||
@classmethod
|
||||
def is_containable(cls, element: ifcopenshell.entity_instance) -> bool:
|
||||
return element.is_a("IfcElement") or element.is_a("IfcGrid")
|
||||
return element.is_a("IfcElement") or element.is_a("IfcAnnotation") or element.is_a("IfcGrid")
|
||||
|
||||
@classmethod
|
||||
def is_element_a(cls, element: ifcopenshell.entity_instance, ifc_class: str) -> bool:
|
||||
|
||||
@@ -887,3 +887,13 @@ class Spatial(blenderbim.core.tool.Spatial):
|
||||
if (element := tool.Ifc.get_entity(obj)) and not tool.Root.is_spatial_element(element):
|
||||
results.append(obj)
|
||||
return results
|
||||
|
||||
@classmethod
|
||||
def set_target_container_as_default(cls) -> None:
|
||||
if (
|
||||
(container := tool.Root.get_default_container())
|
||||
and (obj := tool.Ifc.get_object(container))
|
||||
and bpy.context.active_object
|
||||
):
|
||||
props = bpy.context.active_object.BIMObjectSpatialProperties
|
||||
props.container_obj = obj
|
||||
|
||||
@@ -21,11 +21,12 @@ import ifcopenshell.api
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
import numpy as np
|
||||
from mathutils import Matrix
|
||||
|
||||
|
||||
class Surveyor(blenderbim.core.tool.Surveyor):
|
||||
@classmethod
|
||||
def get_absolute_matrix(cls, obj):
|
||||
def get_absolute_matrix(cls, obj: bpy.types.Object) -> Matrix:
|
||||
matrix = np.array(obj.matrix_world)
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
if props.has_blender_offset and obj.BIMObjectProperties.blender_offset_type != "NOT_APPLICABLE":
|
||||
|
||||
@@ -14,19 +14,29 @@ Unstable installation
|
||||
**Unstable installation** is almost the same as **Stable installation**, except
|
||||
that they are typically updated every day. Simply download a daily build from
|
||||
the `GitHub releases page
|
||||
<https://github.com/IfcOpenShell/IfcOpenShell/releases>`__, then follow the
|
||||
usual :doc:`installation instructions</users/quickstart/installation>`.
|
||||
<https://github.com/IfcOpenShell/IfcOpenShell/releases?q=blenderbim&expanded=true>`__,
|
||||
then follow the usual :doc:`installation
|
||||
instructions</users/quickstart/installation>`.
|
||||
|
||||
You will need to choose which build to download.
|
||||
The BlenderBIM Add-on officially supports all major 64-bit platforms, as well as
|
||||
the Python version shipped by the Blender Foundation for the most recent three
|
||||
major Blender versions:
|
||||
|
||||
- If you are on Blender >=4.1, choose py311
|
||||
- If you are on Blender >=3.1 and <=4.0, choose py310
|
||||
- If you are on Blender >=2.93 and <3.1, choose py39
|
||||
- Choose ``linux-x64``, ``macos-x64`` (Apple Intel), ``macos-arm64`` (Apple Silicon), or
|
||||
``windows-x64`` depending on your operating system
|
||||
- 64-bit Linux (``linux-x64``)
|
||||
- 64-bit MacOS Intel (``macos-x64``)
|
||||
- 64-bit MacOS Silicon (``macos-arm64``)
|
||||
- 64-bit Windows (``windows-x64``)
|
||||
- Blender 4.2 with Python 3.11
|
||||
|
||||
For users who don't follow the `VFX Platform <https://vfxplatform.com/>`_
|
||||
standard, we also provide py312 builds.
|
||||
Due to significant changes in the Blender extensions system, Blender versions
|
||||
<4.2 are not supported.
|
||||
|
||||
Developer builds may exist for different versions of Python but there will be
|
||||
no guarantee of the uptime or stability of these builds.
|
||||
|
||||
Other system specifications match the `Blender Requirements
|
||||
<https://www.blender.org/download/requirements/>`_ and the `VFX Platform
|
||||
<https://vfxplatform.com/>`_ standard.
|
||||
|
||||
Sometimes, a build may be delayed, or contain broken code. We try to avoid this,
|
||||
but it happens.
|
||||
@@ -46,7 +56,9 @@ compile IfcOpenShell is out of scope of this document.
|
||||
|
||||
You can create your own package by using the Makefile as shown below. You can
|
||||
choose between a ``PLATFORM`` of ``linux``, ``macos``, ``macosm1``, and ``win``.
|
||||
You can choose between a ``PYVERSION`` of ``py311``, ``py310``, or ``py39``.
|
||||
You can choose between a ``PYVERSION`` of ``py312``, ``py311``, ``py310``, or
|
||||
``py39``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd src/blenderbim
|
||||
@@ -60,18 +72,17 @@ Live development environment
|
||||
----------------------------
|
||||
|
||||
One option for developers who want to actively develop from source is to follow
|
||||
the instructions from **Bundling for Blender**. However, creating a build,
|
||||
uninstalling the old add-on, and installing a new build is a slow process.
|
||||
Although it works, it is very slow, so we do not recommend it.
|
||||
the instructions from :ref:`devs/installation:Bundling for Blender`. However,
|
||||
creating a build, uninstalling the old add-on, and installing a new build is a
|
||||
slow process. Although it works, it is very slow, so we do not recommend it.
|
||||
|
||||
A more rapid approach is to follow the **Unstable installation** method, as this
|
||||
provides all dependencies for you out of the box.
|
||||
A more rapid approach is to follow the :ref:`devs/installation:Unstable
|
||||
installation` method, as this provides all dependencies for you out of the box.
|
||||
|
||||
Once you've done this, you can replace certain Python files that tend to be
|
||||
updated frequently with those from the Git repository. We're going to use
|
||||
symlinks (Windows users can use ``mklink``), so we can code in our Git
|
||||
repository, and see the changes in our Blender installation (you will need to
|
||||
restart Blender to see changes).
|
||||
symbolic links, so we can code in our Git repository, and see the changes in
|
||||
our Blender installation (you will need to restart Blender to see changes).
|
||||
|
||||
For Linux or Mac:
|
||||
|
||||
@@ -117,19 +128,17 @@ Packaged installation
|
||||
Tips for package managers
|
||||
-------------------------
|
||||
|
||||
If you are interested in packaging the BlenderBIM Add-on for a packaging
|
||||
manager, read on.
|
||||
|
||||
The BlenderBIM Add-on is fully contained in the ``blenderbim/`` subfolder of the
|
||||
Blender add-ons directory. This is typically distributed as a zipfile as per
|
||||
Blender add-on conventions. Within this folder, you'll find the following file
|
||||
structure:
|
||||
::
|
||||
|
||||
core/ (Blender agnostic core code)
|
||||
tool/ (Blender specific logic)
|
||||
core/ (Blender agnostic core logic)
|
||||
tool/ (Blender specific shared functionality)
|
||||
bim/ (Blender specific UI)
|
||||
libs/ (dependencies)
|
||||
libs/ (other assets)
|
||||
wheels/ (dependencies)
|
||||
__init__.py
|
||||
|
||||
This corresponds to the structure found in the source code `here
|
||||
@@ -142,50 +151,29 @@ dependencies are bundled with the add-on for convenience.
|
||||
If you choose to install the BlenderBIM Add-on and use your own system
|
||||
dependencies, the source of truth for how dependencies are bundled are found in
|
||||
the `Makefile
|
||||
<https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.8.0/src/blenderbim/Makefile>`__.
|
||||
<https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.8.0/src/blenderbim/Makefile>`__
|
||||
in the ``dist`` target.
|
||||
|
||||
Required Python modules to be stored in ``libs/site/packages/`` are:
|
||||
::
|
||||
Add-on compatibility
|
||||
--------------------
|
||||
|
||||
ifcopenshell
|
||||
bcf
|
||||
ifcclash
|
||||
ifccobie
|
||||
ifccsv
|
||||
ifcdiff
|
||||
ifc4d
|
||||
ifc5d
|
||||
ifcpatch
|
||||
ifctester
|
||||
pystache
|
||||
svgwrite
|
||||
dateutil
|
||||
isodate
|
||||
networkx
|
||||
https://github.com/Andrej730/aud/archive/refs/heads/master-reduced-size.zip
|
||||
deepdiff
|
||||
jsonpickle
|
||||
ordered_set
|
||||
pyparsing
|
||||
xmlschema
|
||||
elementpath
|
||||
six
|
||||
lark-parser
|
||||
parse
|
||||
parse_type
|
||||
xlsxwriter
|
||||
odfpy
|
||||
defusedxml
|
||||
jmespath
|
||||
ifcjson
|
||||
The BlenderBIM Add-on is a non-trivial add-on. By turning Blender into a
|
||||
graphical front-end to a native IFC authoring platform, some fundamental Blender
|
||||
features (such as hotkeys for basic functionality like object deletion or
|
||||
duplication) have been patched and many dependencies have been introduced.
|
||||
|
||||
Notes:
|
||||
Other add-ons may no longer work as intended when the BlenderBIM Add-on is
|
||||
enabled, or vice versa, the BlenderBIM Add-on may no longer work as intended
|
||||
when other add-ons are enabled.
|
||||
|
||||
1. ``ifcopenshell`` almost always requires the latest version due to the fast paced nature of the add-on development.
|
||||
2. ``ifcjson`` can be found `here <https://github.com/IFCJSON-Team/IFC2JSON_python/tree/master/file_converters>`__.
|
||||
Known scenarios which will lead to add-on incompatibility include:
|
||||
|
||||
Required static assets are:
|
||||
::
|
||||
|
||||
bim/data/gantt/jsgantt.js (from jsgantt-improved)
|
||||
bim/data/gantt/jsgantt.css (from jsgantt-improved)
|
||||
- The add-on also overrides the same hotkeys. For example, if an add-on
|
||||
overrides the "X" key to delete an object, you will need to manually trigger
|
||||
(either via menu or custom hotkey) the BlenderBIM Add-on equivalent operator
|
||||
(e.g. IFC Delete).
|
||||
- The add-on uses object deletion or duplication macros with dictionary
|
||||
override. Note that this is also deprecated in Blender, so the other add-on
|
||||
should be updated to fix this.
|
||||
- The add-on requires a conflicting dependency, or a conflicting version of the
|
||||
same dependency. Neither add-on may work simultaneously.
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
System support
|
||||
==============
|
||||
|
||||
The BlenderBIM Add-on officially supports all major 64-bit platforms, as well as
|
||||
the Python version shipped by the Blender Foundation for the most recent three
|
||||
major Blender versions:
|
||||
|
||||
- 64-bit Linux on Python 3.10
|
||||
- 64-bit Linux on Python 3.11
|
||||
- 64-bit MacOS Intel on Python 3.10
|
||||
- 64-bit MacOS Intel on Python 3.11
|
||||
- 64-bit MacOS Silicon on Python 3.10
|
||||
- 64-bit MacOS Silicon on Python 3.11
|
||||
- 64-bit Windows on Python 3.10
|
||||
- 64-bit Windows on Python 3.11
|
||||
|
||||
Note that developer builds may exist for older versions of Python but there will
|
||||
be no guarantee of the uptime or stability of these builds.
|
||||
|
||||
Other system specifications match the `Blender Requirements
|
||||
<https://www.blender.org/download/requirements/>`_.
|
||||
|
||||
Add-on compatibility
|
||||
--------------------
|
||||
|
||||
The BlenderBIM Add-on is a non-trivial add-on. By turning Blender into a
|
||||
graphical front-end to a native IFC authoring platform, some fundamental Blender
|
||||
features (such as hotkeys for basic functionality like object deletion or
|
||||
duplication) have been patched and many dependencies have been introduced.
|
||||
|
||||
Other add-ons may no longer work as intended when the BlenderBIM Add-on is
|
||||
enabled, or vice versa, the BlenderBIM Add-on may no longer work as intended
|
||||
when other add-ons are enabled.
|
||||
|
||||
Known scenarios which will lead to add-on incompatibility include:
|
||||
|
||||
- The add-on also overrides the same hotkeys. For example, if an add-on
|
||||
overrides the "X" key to delete an object, you will need to manually trigger
|
||||
(either via menu or custom hotkey) the BlenderBIM Add-on equivalent operator
|
||||
(e.g. IFC Delete).
|
||||
- The add-on uses object deletion or duplication macros with dictionary
|
||||
override. Note that this is also deprecated in Blender, so the other add-on
|
||||
should be updated to fix this.
|
||||
- The add-on requires a conflicting dependency, or a conflicting version of the
|
||||
same dependency. Neither add-on may work simultaneously.
|
||||
@@ -193,11 +193,6 @@ suggesting new features, or contributing code, your involvement is highly encour
|
||||
:doc:`/devs/running_tests`
|
||||
Testing and quality assurance.
|
||||
|
||||
.. container:: card
|
||||
|
||||
:doc:`/devs/system_support`
|
||||
Multiplatform compatibility.
|
||||
|
||||
.. container:: card
|
||||
|
||||
:doc:`/devs/ux_guidelines`
|
||||
@@ -216,5 +211,4 @@ suggesting new features, or contributing code, your involvement is highly encour
|
||||
devs/undo_system
|
||||
devs/code_style
|
||||
devs/running_tests
|
||||
devs/system_support
|
||||
devs/ux_guidelines
|
||||
|
||||
@@ -28,10 +28,6 @@ Installation
|
||||
|
||||
`Download BlenderBIM Add-on <https://blenderbim.org/download.html>`__
|
||||
|
||||
.. warning::
|
||||
|
||||
If you are not using Blender version >=4.1, please follow the **Unstable installation** instructions. :doc:`Read more </devs/installation>`
|
||||
|
||||
3. **Install the BlenderBIM Add-on**
|
||||
|
||||
Open up Blender, and click on ``Edit > Preferences``.
|
||||
@@ -89,14 +85,10 @@ installed>`.
|
||||
If you do not restart Blender, the add-on will fail to remove correctly, and you
|
||||
will need to uninstall manually.
|
||||
|
||||
|
||||
.. _installation_location:
|
||||
|
||||
Where is the add-on installed?
|
||||
------------------------------
|
||||
|
||||
Upon installation, the BlenderBIM Add-on is stored in the
|
||||
``scripts/addons/blenderbim/`` directory, within your Blender configuration
|
||||
Upon installation, the BlenderBIM Add-on is stored in Blender configuration
|
||||
folder. However, the location of your Blender configuration folder depends on
|
||||
how you have installed Blender.
|
||||
|
||||
@@ -106,7 +98,7 @@ is the Blender version:
|
||||
|
||||
::
|
||||
|
||||
/path/to/blender/X.XX/scripts/addons/blenderbim/
|
||||
/path/to/blender/X.XX/
|
||||
|
||||
Otherwise, if you installed Blender using an installation package, the Blender
|
||||
configuration folder depends on which operating system you use.
|
||||
@@ -115,29 +107,34 @@ On Linux, if you are installing the add-on as a user:
|
||||
|
||||
::
|
||||
|
||||
~/.config/blender/X.XX/scripts/addons/blenderbim/
|
||||
~/.config/blender/X.XX/
|
||||
|
||||
On Linux, if you are deploying the add-on system-wide (this may also depend on
|
||||
your Linux distribution):
|
||||
|
||||
::
|
||||
|
||||
/usr/share/blender/X.XX/scripts/addons/blenderbim/
|
||||
/usr/share/blender/X.XX/
|
||||
|
||||
On Mac, if you are installing the add-on as a user:
|
||||
|
||||
::
|
||||
|
||||
/Users/{YOUR_USER}/Library/Application Support/Blender/X.XX/scripts/addons/blenderbim/
|
||||
/Users/{YOUR_USER}/Library/Application Support/Blender/X.XX/
|
||||
|
||||
On Mac, if you are deploying the add-on system-wide:
|
||||
|
||||
::
|
||||
|
||||
/Library/Application Support/Blender/X.XX/scripts/addons/blenderbim/
|
||||
/Library/Application Support/Blender/X.XX/
|
||||
|
||||
On Windows:
|
||||
|
||||
::
|
||||
|
||||
C:\Users\{YOUR_USER}\AppData\Roaming\Blender Foundation\X.XX\scripts\addons\blenderbim\
|
||||
C:\Users\{YOUR_USER}\AppData\Roaming\Blender Foundation\X.XX\
|
||||
|
||||
Inside the Blender configuration folder, the BlenderBIM Add-on is stored in two
|
||||
different locations. The extension itself is stored in
|
||||
``extensions/blender_org/blenderbim`` whereas the Python packages are installed
|
||||
into ``extensions/.local/lib/pythonX.XX/site-packages/``.
|
||||
|
||||
@@ -29,8 +29,8 @@ Installation issues
|
||||
-------------------
|
||||
|
||||
If you are unable to install the BlenderBIM Add-on, make sure you are using
|
||||
**Blender 4.1** installed from https://blender.org/ and are installing the
|
||||
latest version from https://blenderbim.org.
|
||||
**Blender 4.2** installed from https://blender.org/ and have
|
||||
:ref:`updated to the latest version <users/quickstart/installation:Updating>`.
|
||||
|
||||
Other common solutions are listed below. If none of these fix the problem, you
|
||||
can `report a bug <https://github.com/ifcopenshell/ifcopenshell/issues>`_ or
|
||||
@@ -44,50 +44,43 @@ can `report a bug <https://github.com/ifcopenshell/ifcopenshell/issues>`_ or
|
||||
enabled with factory settings.
|
||||
|
||||
To quickly test in a clean environment, first :ref:`find your Blender
|
||||
configuration folder<installation_location>`.
|
||||
Rename the folder from ``X.XX`` to something else like ``X.XX_backup``, then
|
||||
restart Blender and try follow the :doc:`installation
|
||||
configuration folder<users/quickstart/installation:Where is the add-on
|
||||
installed?>`. Rename the folder from ``X.XX`` to something else like
|
||||
``X.XX_backup``, then restart Blender and try follow the :doc:`installation
|
||||
instructions</users/quickstart/installation>` again.
|
||||
|
||||
If this fixes your issue, consider disabling other add-ons one by one until
|
||||
you find a conflict as a next step to isolating the issue.
|
||||
|
||||
2. **I get an error similar to "ImportError: IfcOpenShell not built for 'linux/64bit/python3.10'"**
|
||||
|
||||
If you are using a Mac, be sure to use the Mac Silicon version if you have a
|
||||
newer Mac. The only exception is if you have installed Blender using Steam
|
||||
on a Mac, in which case you need to use the Mac Intel download.
|
||||
|
||||
For all other scenarios, check the BlenderBIM Add-on zip file which you
|
||||
downloaded. The zip will have either ``py39``, ``py310``, or ``py311`` in
|
||||
the name. See the instructions in the :ref:`devs/installation:unstable
|
||||
installation` section to check that you have installed the correct version.
|
||||
|
||||
3. **I am on Ubuntu and get an error similar to "ImportError:
|
||||
2. **I am on Ubuntu and get an error similar to "ImportError:
|
||||
/lib/x86_64-linux-gnu/libm.so.6: version GLIBC_2.29 not found"**
|
||||
|
||||
Our latest package which uses IfcOpenShell v0.8.0 is built using Ubuntu 20 LTS.
|
||||
If you have an older Ubuntu version, you can either upgrade to 19.10 or above,
|
||||
or you'll need to compile IfcOpenShell yourself.
|
||||
|
||||
4. **I get an error saying "ModuleNotFoundError: No module named 'numpy'"**"
|
||||
3. **I get an error saying "ModuleNotFoundError: No module named 'numpy'"**"
|
||||
|
||||
If you have installed Blender from another source instead of from
|
||||
`Blender.org <https://www.blender.org/download/>`__, such as from your
|
||||
distro's package repositories, then you may be missing some modules like
|
||||
``numpy``. Try installing it manually like ``apt install python-numpy``.
|
||||
|
||||
Common issues
|
||||
-------------
|
||||
Saving and loading blend files
|
||||
------------------------------
|
||||
|
||||
1. **I get an error similar to RuntimeError: Instance #1234 not found**
|
||||
The BlenderBIM Add-on transform Blender into a native IFC authoring platform.
|
||||
This means that you can open and save IFC files directly without using
|
||||
Blender's ``.blend`` format.
|
||||
|
||||
Blender saves and loads projects to a ``.blend`` file. However. the
|
||||
BlenderBIM Add-on works with native IFC, and this means instead of saving
|
||||
and loading ``.blend`` files, you should instead save and load the ``.ifc``
|
||||
project.
|
||||
All data about your model is saved in your IFC. No data is stored in the
|
||||
``.blend`` format. This means that if you save or open a ``.blend`` file, you
|
||||
are **not** saving and loading your model. At best, you are saving and loading
|
||||
Blender geometry that represents what the model might've looked at at some
|
||||
point. At worst, you might be looking at a completely wrong model.
|
||||
|
||||
If you have opened a ``.blend`` file, there is a risk that the contents of
|
||||
the ``.blend`` session do not correlate to the contents of the ``.ifc``,
|
||||
which can cause this error. Unless you are an advanced user, only save and
|
||||
load ``.ifc`` files.
|
||||
If you continue to open and save ``.blend`` files, you will run the risk of
|
||||
editing something that doesn't actually exist in your IFC model. This will
|
||||
create unpredictable, and sometimes unrecoverable errors.
|
||||
|
||||
To avoid this issue, only open and save IFCs.
|
||||
|
||||
@@ -34,4 +34,5 @@ markers =
|
||||
type
|
||||
unit
|
||||
void
|
||||
web
|
||||
addopts = --color=yes --code-highlight=yes
|
||||
|
||||
@@ -1,70 +1,72 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
|
||||
|
||||
rem Uncomment setting REPO_PATH to use custom path for IfcOpenShell repository.
|
||||
rem Otherwise by default it is assumed script is executed from IfcOpenShell directory.
|
||||
rem SET REPO_PATH=%HOMEDRIVE%\Users\%USERNAME%\Where\Your\Git\Repository\Is\Cloned\IfcOpenShell
|
||||
SET BLENDER_PATH=%HOMEDRIVE%\Users\%USERNAME%\AppData\Roaming\Blender Foundation\Blender\4.2
|
||||
SET PACKAGE_PATH=%BLENDER_PATH%\extensions\.local\lib\python3.11\site-packages
|
||||
SET BLENDERBIM_PATH=%BLENDER_PATH%\extensions\user_default\blenderbim
|
||||
|
||||
|
||||
echo SETUP BLENDERBIM ADD-ON LIVE DEVELOPMENT ENVIRONMENT
|
||||
echo Update BLENDER, BLENDER_VERSION, PYTHON_VERSION, BBIM_REPO, BLENDER_USER_NAME in the script bellow.
|
||||
echo Put the script at the root of your IfcOpenShell git repository
|
||||
echo Update REPO_PATH, BLENDER_PATH, PACKAGE_PATH, BLENDERBIM_PATH in the script above.
|
||||
echo This script needs to be run as administrator (to create symbolic links)
|
||||
echo Make sure you have followed these steps before proceeding :)
|
||||
|
||||
echo.
|
||||
echo Currently set paths:
|
||||
if not defined REPO_PATH (
|
||||
echo REPO_PATH is not set, assuming we're already in IfcOpenShell directory.
|
||||
set REPO_PATH=%cd%
|
||||
)
|
||||
echo REPO_PATH=%REPO_PATH%
|
||||
echo BLENDER_PATH=%BLENDER_PATH%
|
||||
echo PACKAGE_PATH=%PACKAGE_PATH%
|
||||
echo BLENDERBIM_PATH=%BLENDERBIM_PATH%
|
||||
pause
|
||||
|
||||
SET BLENDER_VERSION=4.2
|
||||
SET PYTHON_VERSION=3.11
|
||||
SET BBIM_REPO=user_default
|
||||
rem Can be useful e.g. if you're running script from administrator account
|
||||
rem and need to setup dev environment for some other user.
|
||||
SET BLENDER_USER_NAME=%USERNAME%
|
||||
|
||||
SET BLENDER=%HOMEDRIVE%\Users\%BLENDER_USER_NAME%\AppData\Roaming\Blender Foundation\Blender\%BLENDER_VERSION%
|
||||
SET BLENDER_LOCAL=%BLENDER%\extensions\.local\lib\python%PYTHON_VERSION%\site-packages
|
||||
SET BLENDERBIM=%BLENDER_LOCAL%\blenderbim
|
||||
SET BLENDER_EXT=%BLENDER%\extensions\%BBIM_REPO%\blenderbim
|
||||
|
||||
echo Removing the Blender add-on Python code...
|
||||
del "%BLENDER_EXT%\__init__.py"
|
||||
rd /S /Q "%BLENDERBIM%"
|
||||
|
||||
echo Replacing them with links to the Git repository...
|
||||
mklink "%BLENDER_EXT%\__init__.py" "%CD%\src\blenderbim\blenderbim\__init__.py"
|
||||
mklink /D "%BLENDERBIM%" "%CD%\src\blenderbim\blenderbim"
|
||||
echo Changing to the Git repository directory...
|
||||
cd %REPO_PATH%
|
||||
|
||||
echo Copy over compiled IfcOpenShell files...
|
||||
copy "%BLENDER_LOCAL%\ifcopenshell\*_wrapper*" "%CD%\src\ifcopenshell-python\ifcopenshell\"
|
||||
copy "%PACKAGE_PATH%\ifcopenshell\*_wrapper*" "%CD%\src\ifcopenshell-python\ifcopenshell\"
|
||||
|
||||
echo Remove the IfcOpenShell dependency...
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifcopenshell"
|
||||
echo Remove extension and link to Git...
|
||||
del "%BLENDERBIM_PATH%\__init__.py"
|
||||
rd /S /Q "%PACKAGE_PATH%\blenderbim"
|
||||
rd /S /Q "%PACKAGE_PATH%\ifcopenshell"
|
||||
del "%PACKAGE_PATH%\ifccsv.py"
|
||||
del "%PACKAGE_PATH%\ifcdiff.py"
|
||||
del "%PACKAGE_PATH%\bsdd.py"
|
||||
rd /S /Q "%PACKAGE_PATH%\bcf"
|
||||
rd /S /Q "%PACKAGE_PATH%\ifc4d"
|
||||
rd /S /Q "%PACKAGE_PATH%\ifc5d"
|
||||
rd /S /Q "%PACKAGE_PATH%\ifccityjson"
|
||||
rd /S /Q "%PACKAGE_PATH%\ifcclash"
|
||||
rd /S /Q "%PACKAGE_PATH%\ifcpatch"
|
||||
rd /S /Q "%PACKAGE_PATH%\ifctester"
|
||||
rd /S /Q "%PACKAGE_PATH%\ifcfm"
|
||||
|
||||
echo Replace them with links to the Git repository...
|
||||
mklink /D "%BLENDER_LOCAL%\ifcopenshell" "%CD%\src\ifcopenshell-python\ifcopenshell"
|
||||
|
||||
echo Remove and link other IfcOpenShell utilities...
|
||||
del "%BLENDER_LOCAL%\ifccsv.py"
|
||||
del "%BLENDER_LOCAL%\ifcdiff.py"
|
||||
del "%BLENDER_LOCAL%\bsdd.py"
|
||||
rd /S /Q "%BLENDER_LOCAL%\bcf"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifc4d"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifc5d"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifccityjson"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifcclash"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifcpatch"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifctester"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifcfm"
|
||||
|
||||
mklink "%BLENDER_LOCAL%\ifccsv.py" "%CD%\src\ifccsv\ifccsv.py"
|
||||
mklink "%BLENDER_LOCAL%\ifcdiff.py" "%CD%\src\ifcdiff\ifcdiff.py"
|
||||
mklink "%BLENDER_LOCAL%\bsdd.py" "%CD%\src\bsdd\bsdd.py"
|
||||
mklink /D "%BLENDER_LOCAL%\bcf" "%CD%\src\bcf\bcf"
|
||||
mklink /D "%BLENDER_LOCAL%\ifc4d" "%CD%\src\ifc4d\ifc4d"
|
||||
mklink /D "%BLENDER_LOCAL%\ifc5d" "%CD%\src\ifc5d\ifc5d"
|
||||
mklink /D "%BLENDER_LOCAL%\ifccityjson" "%CD%\src\ifccityjson\ifccityjson"
|
||||
mklink /D "%BLENDER_LOCAL%\ifcclash" "%CD%\src\ifcclash\ifcclash"
|
||||
mklink /D "%BLENDER_LOCAL%\ifcpatch" "%CD%\src\ifcpatch\ifcpatch"
|
||||
mklink /D "%BLENDER_LOCAL%\ifctester" "%CD%\src\ifctester\ifctester"
|
||||
mklink /D "%BLENDER_LOCAL%\ifcfm" "%CD%\src\ifcfm\ifcfm"
|
||||
mklink "%BLENDERBIM_PATH%\__init__.py" "%CD%\src\blenderbim\blenderbim\__init__.py"
|
||||
mklink /D "%PACKAGE_PATH%\blenderbim" "%CD%\src\blenderbim\blenderbim"
|
||||
mklink /D "%PACKAGE_PATH%\ifcopenshell" "%CD%\src\ifcopenshell-python\ifcopenshell"
|
||||
mklink "%PACKAGE_PATH%\ifccsv.py" "%CD%\src\ifccsv\ifccsv.py"
|
||||
mklink "%PACKAGE_PATH%\ifcdiff.py" "%CD%\src\ifcdiff\ifcdiff.py"
|
||||
mklink "%PACKAGE_PATH%\bsdd.py" "%CD%\src\bsdd\bsdd.py"
|
||||
mklink /D "%PACKAGE_PATH%\bcf" "%CD%\src\bcf\bcf"
|
||||
mklink /D "%PACKAGE_PATH%\ifc4d" "%CD%\src\ifc4d\ifc4d"
|
||||
mklink /D "%PACKAGE_PATH%\ifc5d" "%CD%\src\ifc5d\ifc5d"
|
||||
mklink /D "%PACKAGE_PATH%\ifccityjson" "%CD%\src\ifccityjson\ifccityjson"
|
||||
mklink /D "%PACKAGE_PATH%\ifcclash" "%CD%\src\ifcclash\ifcclash"
|
||||
mklink /D "%PACKAGE_PATH%\ifcpatch" "%CD%\src\ifcpatch\ifcpatch"
|
||||
mklink /D "%PACKAGE_PATH%\ifctester" "%CD%\src\ifctester\ifctester"
|
||||
mklink /D "%PACKAGE_PATH%\ifcfm" "%CD%\src\ifcfm\ifcfm"
|
||||
|
||||
echo Manually downloading some third party dependencies...
|
||||
curl https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js -o "%BLENDERBIM%\bim\data\gantt\jsgantt.js"
|
||||
curl https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css -o "%BLENDERBIM%\bim\data\gantt\jsgantt.css"
|
||||
curl -L https://github.com/BrickSchema/Brick/releases/download/nightly/Brick.ttl -o "%BLENDERBIM%\bim\schema\Brick.ttl"
|
||||
curl https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js -o "%PACKAGE_PATH%\blenderbim\bim\data\gantt\jsgantt.js"
|
||||
curl https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css -o "%PACKAGE_PATH%\blenderbim\bim\data\gantt\jsgantt.css"
|
||||
curl -L https://github.com/BrickSchema/Brick/releases/download/nightly/Brick.ttl -o "%PACKAGE_PATH%\blenderbim\bim\schema\Brick.ttl"
|
||||
|
||||
pause
|
||||
|
||||
@@ -1,60 +1,52 @@
|
||||
git clone https://github.com/IfcOpenShell/IfcOpenShell.git
|
||||
cd IfcOpenShell
|
||||
# Please update REPO_PATH, BLENDER_PATH, PACKAGE_PATH, BLENDERBIM_PATH in the script below.
|
||||
# Default BLENDER_PATH on Mac: "/Users/$USER/Library/Application Support/Blender/4.2/"
|
||||
# Default BLENDER_PATH on Linux: "$HOME/.config/blender/4.2/"
|
||||
# REPO_PATH="/path/to/where/your/git/repository/is/cloned/IfcOpenShell"
|
||||
REPO_PATH="/home/dion/Projects/ifcopenshell/"
|
||||
BLENDER_PATH="${HOME}/.config/blender/4.2"
|
||||
PACKAGE_PATH="${BLENDER_PATH}/extensions/.local/lib/python3.11/site-packages"
|
||||
BLENDERBIM_PATH="${BLENDER_PATH}/extensions/user_default/blenderbim"
|
||||
|
||||
# path to BlenderBIM addon
|
||||
# default path on Mac: "/Users/$USER/Library/Application Support/Blender/X.X/scripts/addons/blenderbim"
|
||||
# default path on Linux: "$HOME/.config/blender/X.X/"
|
||||
BLENDER_ADDON_PATH="/path/to/blender/X.XX/scripts/addons/blenderbim"
|
||||
|
||||
# Remove the Blender add-on Python code
|
||||
rm -r $BLENDER_ADDON_PATH/core/
|
||||
rm -r $BLENDER_ADDON_PATH/tool/
|
||||
rm -r $BLENDER_ADDON_PATH/bim/
|
||||
|
||||
# Replace them with links to the Git repository
|
||||
ln -s $PWD/src/blenderbim/blenderbim/core $BLENDER_ADDON_PATH/core
|
||||
ln -s $PWD/src/blenderbim/blenderbim/tool $BLENDER_ADDON_PATH/tool
|
||||
ln -s $PWD/src/blenderbim/blenderbim/bim $BLENDER_ADDON_PATH/bim
|
||||
# Changing to the Git repository directory
|
||||
cd $REPO_PATH
|
||||
|
||||
# Copy over compiled IfcOpenShell files
|
||||
cp $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell/*_wrapper* $PWD/src/ifcopenshell-python/ifcopenshell/
|
||||
cp $PACKAGE_PATH/ifcopenshell/*_wrapper* $PWD/src/ifcopenshell-python/ifcopenshell/
|
||||
|
||||
# Remove the IfcOpenShell dependency
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell
|
||||
# Remove extension and link to Git
|
||||
rm $BLENDERBIM_PATH/__init__.py
|
||||
rm -r $PACKAGE_PATH/blenderbim
|
||||
rm -r $PACKAGE_PATH/ifcopenshell
|
||||
rm -r $PACKAGE_PATH/ifccsv.py
|
||||
rm -r $PACKAGE_PATH/ifcdiff.py
|
||||
rm -r $PACKAGE_PATH/bsdd.py
|
||||
rm -r $PACKAGE_PATH/bcf
|
||||
rm -r $PACKAGE_PATH/ifc4d
|
||||
rm -r $PACKAGE_PATH/ifc5d
|
||||
rm -r $PACKAGE_PATH/ifccityjson
|
||||
rm -r $PACKAGE_PATH/ifcclash
|
||||
rm -r $PACKAGE_PATH/ifcpatch
|
||||
rm -r $PACKAGE_PATH/ifctester
|
||||
rm -r $PACKAGE_PATH/ifcfm
|
||||
|
||||
# Replace them with links to the Git repository
|
||||
ln -s $PWD/src/ifcopenshell-python/ifcopenshell $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell
|
||||
|
||||
# Remove and link other IfcOpenShell utilities
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifccsv.py
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcdiff.py
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/bsdd.py
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/bcf
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifc4d
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifc5d
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifccityjson
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcclash
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcpatch
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifctester
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcfm
|
||||
rm -r $BLENDER_ADDON_PATH/libs/Desktop
|
||||
|
||||
ln -s $PWD/src/ifccsv/ifccsv.py $BLENDER_ADDON_PATH/libs/site/packages/ifccsv.py
|
||||
ln -s $PWD/src/ifcdiff/ifcdiff.py $BLENDER_ADDON_PATH/libs/site/packages/ifcdiff.py
|
||||
ln -s $PWD/src/bsdd/bsdd.py $BLENDER_ADDON_PATH/libs/site/packages/bsdd.py
|
||||
ln -s $PWD/src/bcf/bcf $BLENDER_ADDON_PATH/libs/site/packages/bcf
|
||||
ln -s $PWD/src/ifc4d/ifc4d $BLENDER_ADDON_PATH/libs/site/packages/ifc4d
|
||||
ln -s $PWD/src/ifc5d/ifc5d $BLENDER_ADDON_PATH/libs/site/packages/ifc5d
|
||||
ln -s $PWD/src/ifccityjson/ifccityjson $BLENDER_ADDON_PATH/libs/site/packages/ifccityjson
|
||||
ln -s $PWD/src/ifcclash/ifcclash $BLENDER_ADDON_PATH/libs/site/packages/ifcclash
|
||||
ln -s $PWD/src/ifcpatch/ifcpatch $BLENDER_ADDON_PATH/libs/site/packages/ifcpatch
|
||||
ln -s $PWD/src/ifctester/ifctester $BLENDER_ADDON_PATH/libs/site/packages/ifctester
|
||||
ln -s $PWD/src/ifcfm/ifcfm $BLENDER_ADDON_PATH/libs/site/packages/ifcfm
|
||||
ln -s $PWD/src/blenderbim/blenderbim/libs/desktop $BLENDER_ADDON_PATH/libs/Desktop
|
||||
ln -s $PWD/src/blenderbim/blenderbim/__init__.py $BLENDERBIM_PATH/__init__.py
|
||||
ln -s $PWD/src/blenderbim/blenderbim $PACKAGE_PATH/blenderbim
|
||||
ln -s $PWD/src/ifcopenshell-python/ifcopenshell $PACKAGE_PATH/ifcopenshell
|
||||
ln -s $PWD/src/ifccsv/ifccsv.py $PACKAGE_PATH/ifccsv.py
|
||||
ln -s $PWD/src/ifcdiff/ifcdiff.py $PACKAGE_PATH/ifcdiff.py
|
||||
ln -s $PWD/src/bsdd/bsdd.py $PACKAGE_PATH/bsdd.py
|
||||
ln -s $PWD/src/bcf/bcf $PACKAGE_PATH/bcf
|
||||
ln -s $PWD/src/ifc4d/ifc4d $PACKAGE_PATH/ifc4d
|
||||
ln -s $PWD/src/ifc5d/ifc5d $PACKAGE_PATH/ifc5d
|
||||
ln -s $PWD/src/ifccityjson/ifccityjson $PACKAGE_PATH/ifccityjson
|
||||
ln -s $PWD/src/ifcclash/ifcclash $PACKAGE_PATH/ifcclash
|
||||
ln -s $PWD/src/ifcpatch/ifcpatch $PACKAGE_PATH/ifcpatch
|
||||
ln -s $PWD/src/ifctester/ifctester $PACKAGE_PATH/ifctester
|
||||
ln -s $PWD/src/ifcfm/ifcfm $PACKAGE_PATH/ifcfm
|
||||
|
||||
# Manually download some third party dependencies
|
||||
cd $BLENDER_ADDON_PATH/bim/data/gantt
|
||||
cd $PACKAGE_PATH/blenderbim/bim/data/gantt
|
||||
wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js
|
||||
wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css
|
||||
cd $BLENDER_ADDON_PATH/bim/schema
|
||||
cd $PACKAGE_PATH/blenderbim/bim/schema
|
||||
wget https://github.com/BrickSchema/Brick/releases/download/nightly/Brick.ttl
|
||||
|
||||
@@ -24,6 +24,7 @@ import pytest
|
||||
import webbrowser
|
||||
import blenderbim
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from mathutils import Vector
|
||||
|
||||
@@ -32,45 +32,17 @@ Scenario: Disable editing georeferencing
|
||||
When I press "bim.disable_editing_georeferencing"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Set IFC grid north
|
||||
Given an empty IFC project
|
||||
And I press "bim.add_georeferencing"
|
||||
And I press "bim.enable_editing_georeferencing"
|
||||
When I press "bim.set_ifc_grid_north"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Set Blender grid north
|
||||
Given an empty IFC project
|
||||
And I press "bim.add_georeferencing"
|
||||
And I press "bim.enable_editing_georeferencing"
|
||||
And I press "bim.set_ifc_grid_north"
|
||||
When I press "bim.set_blender_grid_north"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Get cursor location
|
||||
Given an empty IFC project
|
||||
When I press "bim.get_cursor_location"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Set IFC true north
|
||||
Given an empty IFC project
|
||||
When I press "bim.set_ifc_true_north"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Set Blender true north
|
||||
Given an empty IFC project
|
||||
And I press "bim.set_ifc_true_north"
|
||||
When I press "bim.set_blender_true_north"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Convert local to global
|
||||
Scenario: Convert local to map
|
||||
Given an empty IFC project
|
||||
When I set "scene.BIMGeoreferenceProperties.local_coordinates" to "0,0,0"
|
||||
And I press "bim.convert_local_to_global"
|
||||
Then "scene.BIMGeoreferenceProperties.map_coordinates" is "0.0,0.0,0.0"
|
||||
|
||||
Scenario: Convert global to local
|
||||
Scenario: Convert map to local
|
||||
Given an empty IFC project
|
||||
When I set "scene.BIMGeoreferenceProperties.map_coordinates" to "0,0,0"
|
||||
And I press "bim.convert_global_to_local"
|
||||
Then "scene.BIMGeoreferenceProperties.local_coordinates" is "0.0,0.0,0.0"
|
||||
|
||||
@@ -25,9 +25,9 @@ Scenario: Assign container
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||
And I press "bim.assign_class"
|
||||
And the object "IfcWall/Cube" is selected
|
||||
And I press "bim.enable_editing_container"
|
||||
And the variable "site" is "tool.Ifc.get().by_type('IfcSite')[0].id()"
|
||||
And I press "bim.set_default_container(container={site})"
|
||||
And I press "bim.enable_editing_container"
|
||||
When I press "bim.assign_container()"
|
||||
Then the object "IfcWall/Cube" is in the collection "IfcSite/My Site"
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
@web
|
||||
Feature: Web
|
||||
Web interface to complement Blender UI
|
||||
|
||||
Scenario: Start server
|
||||
Given an empty Blender session
|
||||
When I press "bim.connect_websocket_server"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Kill server
|
||||
Given an empty Blender session
|
||||
And I press "bim.connect_websocket_server"
|
||||
When I press "bim.kill_websocket_server"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Open web browser
|
||||
Given an empty Blender session
|
||||
And I press "bim.connect_websocket_server"
|
||||
When I press "bim.open_web_browser"
|
||||
Then nothing happens
|
||||
@@ -23,6 +23,7 @@ import webbrowser
|
||||
import numpy as np
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
@@ -20,7 +20,8 @@ import sys
|
||||
import json
|
||||
import pytest
|
||||
import blenderbim.core.tool
|
||||
from typing import Any, Self, Optional
|
||||
from typing import Any, Optional
|
||||
from typing_extensions import Self
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -21,16 +21,15 @@ from test.core.bootstrap import ifc, georeference
|
||||
|
||||
|
||||
class TestAddGeoreferencing:
|
||||
def test_run(self, ifc):
|
||||
ifc.run("georeference.add_georeferencing").should_be_called()
|
||||
subject.add_georeferencing(ifc)
|
||||
def test_run(self, georeference):
|
||||
georeference.add_georeferencing().should_be_called()
|
||||
subject.add_georeferencing(georeference)
|
||||
|
||||
|
||||
class TestEnableGeoreferencing:
|
||||
class TestEnableEditingGeoreferencing:
|
||||
def test_run(self, georeference):
|
||||
georeference.import_projected_crs().should_be_called()
|
||||
georeference.import_map_conversion().should_be_called()
|
||||
georeference.import_true_north().should_be_called()
|
||||
georeference.import_coordinate_operation().should_be_called()
|
||||
georeference.enable_editing().should_be_called()
|
||||
subject.enable_editing_georeferencing(georeference)
|
||||
|
||||
@@ -41,72 +40,84 @@ class TestRemoveGeoreferencing:
|
||||
subject.remove_georeferencing(ifc)
|
||||
|
||||
|
||||
class TestDisableEditingGeoreferencing:
|
||||
def test_run(self, georeference):
|
||||
georeference.disable_editing().should_be_called()
|
||||
subject.disable_editing_georeferencing(georeference)
|
||||
|
||||
|
||||
class TestEditGeoreferencing:
|
||||
def test_run(self, ifc, georeference):
|
||||
georeference.get_projected_crs_attributes().should_be_called().will_return("projected_crs_attributes")
|
||||
georeference.get_map_conversion_attributes().should_be_called().will_return("map_conversion_attributes")
|
||||
georeference.get_true_north_attributes().should_be_called().will_return("true_north_attributes")
|
||||
georeference.export_projected_crs().should_be_called().will_return("projected_crs_attributes")
|
||||
georeference.export_coordinate_operation().should_be_called().will_return("coordinate_operation_attributes")
|
||||
ifc.run(
|
||||
"georeference.edit_georeferencing",
|
||||
projected_crs="projected_crs_attributes",
|
||||
map_conversion="map_conversion_attributes",
|
||||
true_north="true_north_attributes",
|
||||
coordinate_operation="coordinate_operation_attributes",
|
||||
).should_be_called()
|
||||
georeference.disable_editing().should_be_called()
|
||||
georeference.set_model_origin().should_be_called()
|
||||
subject.edit_georeferencing(ifc, georeference)
|
||||
|
||||
|
||||
class TestSetIfcGridNorth:
|
||||
def test_run(self, georeference):
|
||||
georeference.set_ifc_grid_north().should_be_called()
|
||||
subject.set_ifc_grid_north(georeference)
|
||||
|
||||
|
||||
class TestSetBlenderGridNorth:
|
||||
def test_run(self, georeference):
|
||||
georeference.set_blender_grid_north().should_be_called()
|
||||
subject.set_blender_grid_north(georeference)
|
||||
|
||||
|
||||
class TestSetIfcTrueNorth:
|
||||
def test_run(self, georeference):
|
||||
georeference.set_ifc_true_north().should_be_called()
|
||||
subject.set_ifc_true_north(georeference)
|
||||
|
||||
|
||||
class TestSetBlenderTrueNorth:
|
||||
def test_run(self, georeference):
|
||||
georeference.set_blender_true_north().should_be_called()
|
||||
subject.set_blender_true_north(georeference)
|
||||
|
||||
|
||||
class TestGetCursorLocation:
|
||||
def test_run(self, georeference):
|
||||
georeference.get_cursor_location().should_be_called().will_return("coordinates")
|
||||
georeference.set_coordinates("input", "coordinates").should_be_called()
|
||||
georeference.has_blender_offset().should_be_called().will_return(False)
|
||||
georeference.set_coordinates("local", "coordinates").should_be_called()
|
||||
subject.get_cursor_location(georeference)
|
||||
|
||||
def test_with_a_blender_offset(self, georeference):
|
||||
georeference.get_cursor_location().should_be_called().will_return("coordinates")
|
||||
georeference.has_blender_offset().should_be_called().will_return(True)
|
||||
georeference.set_coordinates("blender", "coordinates").should_be_called()
|
||||
subject.get_cursor_location(georeference)
|
||||
|
||||
|
||||
class TestSetCursorLocation:
|
||||
class TestEnableEditingWCS:
|
||||
def test_run(self, georeference):
|
||||
georeference.get_coordinates("output").should_be_called().will_return("coordinates")
|
||||
georeference.set_cursor_location("coordinates").should_be_called()
|
||||
subject.set_cursor_location(georeference)
|
||||
georeference.import_wcs().should_be_called()
|
||||
georeference.enable_editing_wcs().should_be_called()
|
||||
subject.enable_editing_wcs(georeference)
|
||||
|
||||
|
||||
class TestConvertLocalToGlobal:
|
||||
class TestDisableEditingWCS:
|
||||
def test_run(self, georeference):
|
||||
georeference.get_coordinates("input").should_be_called().will_return("coordinates")
|
||||
georeference.xyz2enh("coordinates").should_be_called().will_return("enh")
|
||||
georeference.set_coordinates("output", "enh").should_be_called()
|
||||
georeference.set_cursor_location("enh").should_be_called()
|
||||
subject.convert_local_to_global(georeference)
|
||||
georeference.disable_editing_wcs().should_be_called()
|
||||
subject.disable_editing_wcs(georeference)
|
||||
|
||||
|
||||
class TestConvertGlobalToLocal:
|
||||
class TestEditWCS:
|
||||
def test_run(self, georeference):
|
||||
georeference.get_coordinates("input").should_be_called().will_return("coordinates")
|
||||
georeference.enh2xyz("coordinates").should_be_called().will_return("xyz")
|
||||
georeference.set_coordinates("output", "xyz").should_be_called()
|
||||
georeference.set_cursor_location("xyz").should_be_called()
|
||||
subject.convert_global_to_local(georeference)
|
||||
georeference.export_wcs().should_be_called().will_return("wcs")
|
||||
georeference.set_wcs("wcs").should_be_called()
|
||||
georeference.disable_editing_wcs().should_be_called()
|
||||
georeference.set_model_origin().should_be_called()
|
||||
subject.edit_wcs(georeference)
|
||||
|
||||
|
||||
class TestEnableEditingTrueNorth:
|
||||
def test_run(self, georeference):
|
||||
georeference.import_true_north().should_be_called()
|
||||
georeference.enable_editing_true_north().should_be_called()
|
||||
subject.enable_editing_true_north(georeference)
|
||||
|
||||
|
||||
class TestDisableEditingTrueNorth:
|
||||
def test_run(self, georeference):
|
||||
georeference.disable_editing_true_north().should_be_called()
|
||||
subject.disable_editing_true_north(georeference)
|
||||
|
||||
|
||||
class TestEditTrueNorth:
|
||||
def test_run(self, ifc, georeference):
|
||||
georeference.get_true_north_attributes().should_be_called().will_return("true_north")
|
||||
ifc.run("georeference.edit_true_north", true_north="true_north").should_be_called()
|
||||
georeference.disable_editing_true_north().should_be_called()
|
||||
subject.edit_true_north(ifc, georeference)
|
||||
|
||||
|
||||
class TestRemoveTrueNorth:
|
||||
def test_run(self, ifc):
|
||||
ifc.run("georeference.edit_true_north", true_north=None).should_be_called()
|
||||
subject.remove_true_north(ifc)
|
||||
|
||||
@@ -52,6 +52,7 @@ class TestAssignContainer:
|
||||
|
||||
class TestEnableEditingContainer:
|
||||
def test_run(self, spatial):
|
||||
spatial.set_target_container_as_default().should_be_called()
|
||||
spatial.enable_editing("obj").should_be_called()
|
||||
subject.enable_editing_container(spatial, obj="obj")
|
||||
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.api.unit
|
||||
import ifcopenshell.api.context
|
||||
import ifcopenshell.util.shape_builder
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
from test.bim.bootstrap import NewFile
|
||||
|
||||
@@ -22,6 +22,7 @@ import brickschema
|
||||
import brickschema.persistent
|
||||
from brickschema.namespaces import REF, A
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.guid
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
|
||||
@@ -173,18 +173,14 @@ class TestGetCartesianPointCoordinateOffset(NewFile):
|
||||
obj.BIMObjectProperties.blender_offset_type = "CARTESIAN_POINT"
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
props.has_blender_offset = True
|
||||
props.blender_eastings = "1"
|
||||
props.blender_northings = "2"
|
||||
props.blender_orthogonal_height = "3"
|
||||
obj.BIMObjectProperties.cartesian_point_offset = "1,2,3"
|
||||
assert subject.get_cartesian_point_coordinate_offset(obj) == Vector((1.0, 2.0, 3.0))
|
||||
|
||||
def test_get_null_if_not_a_cartesian_point_offset_type(self):
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
props.has_blender_offset = True
|
||||
props.blender_eastings = "1"
|
||||
props.blender_northings = "2"
|
||||
props.blender_orthogonal_height = "3"
|
||||
obj.BIMObjectProperties.cartesian_point_offset = "1,2,3"
|
||||
assert subject.get_cartesian_point_coordinate_offset(obj) is None
|
||||
|
||||
def test_get_null_if_no_blender_offset(self):
|
||||
@@ -242,8 +238,9 @@ class TestImportRepresentation(NewFile):
|
||||
material.BIMStyleProperties.ifc_definition_id = 101
|
||||
element = ifc.by_type("IfcWall")[0]
|
||||
tool.Ifc.link(element, obj)
|
||||
representation = element.Representation.Representations[0]
|
||||
representation = element.Representation.Representations[1]
|
||||
mesh = subject.import_representation(obj, representation)
|
||||
assert isinstance(mesh, bpy.types.Mesh)
|
||||
assert len(mesh.polygons) == 12
|
||||
assert mesh.materials[0] == material
|
||||
|
||||
|
||||
@@ -75,17 +75,17 @@ class TestImportProjectedCRS(NewFile):
|
||||
assert len(props.projected_crs) == 0
|
||||
|
||||
|
||||
class TestImportMapConversion(NewFile):
|
||||
class TestImportCoordinateOperation(NewFile):
|
||||
def test_importing_nothing_with_no_georeferencing(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
|
||||
ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
|
||||
subject.import_map_conversion()
|
||||
subject.import_coordinate_operation()
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
assert len(props.map_conversion) == 0
|
||||
assert len(props.coordinate_operation) == 0
|
||||
|
||||
def test_importing_map_conversion(self):
|
||||
def test_importing_coordinate_operation(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
|
||||
@@ -98,21 +98,22 @@ class TestImportMapConversion(NewFile):
|
||||
map_conversion.XAxisAbscissa = 4
|
||||
map_conversion.XAxisOrdinate = 5
|
||||
map_conversion.Scale = 6
|
||||
subject.import_map_conversion()
|
||||
subject.import_coordinate_operation()
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
assert props.map_conversion.get("Eastings").string_value == "1.0"
|
||||
assert props.map_conversion.get("Northings").string_value == "2.0"
|
||||
assert props.map_conversion.get("OrthogonalHeight").string_value == "3.0"
|
||||
assert props.map_conversion.get("XAxisAbscissa").string_value == "4.0"
|
||||
assert props.map_conversion.get("XAxisOrdinate").string_value == "5.0"
|
||||
assert props.map_conversion.get("Scale").string_value == "6.0"
|
||||
assert props.coordinate_operation.get("Eastings").string_value == "1.0"
|
||||
assert props.coordinate_operation.get("Northings").string_value == "2.0"
|
||||
assert props.coordinate_operation.get("OrthogonalHeight").string_value == "3.0"
|
||||
assert props.x_axis_abscissa == "4.0"
|
||||
assert props.x_axis_ordinate == "5.0"
|
||||
assert props.grid_north_angle == "-51.3401917"
|
||||
assert props.coordinate_operation.get("Scale").string_value == "6.0"
|
||||
|
||||
def test_run_ifc2x3(self):
|
||||
ifc = ifcopenshell.file(schema="IFC2X3")
|
||||
tool.Ifc.set(ifc)
|
||||
subject.import_map_conversion()
|
||||
subject.import_coordinate_operation()
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
assert len(props.map_conversion) == 0
|
||||
assert len(props.coordinate_operation) == 0
|
||||
|
||||
|
||||
class TestImportTrueNorth(NewFile):
|
||||
@@ -120,10 +121,12 @@ class TestImportTrueNorth(NewFile):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
|
||||
context = ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
|
||||
ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
|
||||
subject.import_true_north()
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
assert props.has_true_north is False
|
||||
assert props.true_north_abscissa == "0"
|
||||
assert props.true_north_ordinate == "1"
|
||||
assert props.true_north_angle == "0"
|
||||
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.file()
|
||||
@@ -135,13 +138,13 @@ class TestImportTrueNorth(NewFile):
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
assert props.true_north_abscissa == "1.0"
|
||||
assert props.true_north_ordinate == "2.0"
|
||||
assert props.has_true_north is True
|
||||
assert props.true_north_angle == "-26.5650512"
|
||||
|
||||
|
||||
class TestGetProjectedCRSAttributes(NewFile):
|
||||
class TestExportProjectedCRS(NewFile):
|
||||
def test_run(self):
|
||||
TestImportProjectedCRS().test_importing_projected_crs()
|
||||
assert subject.get_projected_crs_attributes() == {
|
||||
assert subject.export_projected_crs() == {
|
||||
"Name": "Name",
|
||||
"Description": "Description",
|
||||
"GeodeticDatum": "GeodeticDatum",
|
||||
@@ -152,10 +155,10 @@ class TestGetProjectedCRSAttributes(NewFile):
|
||||
}
|
||||
|
||||
|
||||
class TestGetMapConversionAttributes(NewFile):
|
||||
class TestExportCoordinateOperation(NewFile):
|
||||
def test_run(self):
|
||||
TestImportMapConversion().test_importing_map_conversion()
|
||||
assert subject.get_map_conversion_attributes() == {
|
||||
TestImportCoordinateOperation().test_importing_coordinate_operation()
|
||||
assert subject.export_coordinate_operation() == {
|
||||
"Eastings": 1.0,
|
||||
"Northings": 2.0,
|
||||
"OrthogonalHeight": 3.0,
|
||||
@@ -187,18 +190,22 @@ class TestDisableEditing(NewFile):
|
||||
|
||||
class TestSetCoordinates(NewFile):
|
||||
def test_run(self):
|
||||
subject.set_coordinates("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.0, 5.0, 6.0])
|
||||
assert bpy.context.scene.BIMGeoreferenceProperties.coordinate_output == "4.0,5.0,6.0"
|
||||
subject.set_coordinates("local", [1.0, 2.0, 3.0])
|
||||
assert bpy.context.scene.BIMGeoreferenceProperties.local_coordinates == "1.0,2.0,3.0"
|
||||
subject.set_coordinates("blender", [4.0, 5.0, 6.0])
|
||||
assert bpy.context.scene.BIMGeoreferenceProperties.blender_coordinates == "4.0,5.0,6.0"
|
||||
subject.set_coordinates("map", [7.0, 8.0, 9.0])
|
||||
assert bpy.context.scene.BIMGeoreferenceProperties.map_coordinates == "7.0,8.0,9.0"
|
||||
|
||||
|
||||
class TestGetCoordinates(NewFile):
|
||||
def test_run(self):
|
||||
bpy.context.scene.BIMGeoreferenceProperties.coordinate_input = "1.0,2.0,3.0"
|
||||
assert subject.get_coordinates("input") == [1.0, 2.0, 3.0]
|
||||
bpy.context.scene.BIMGeoreferenceProperties.coordinate_output = "4.0,5.0,6.0"
|
||||
assert subject.get_coordinates("output") == [4.0, 5.0, 6.0]
|
||||
bpy.context.scene.BIMGeoreferenceProperties.local_coordinates = "1.0,2.0,3.0"
|
||||
assert subject.get_coordinates("local") == [1.0, 2.0, 3.0]
|
||||
bpy.context.scene.BIMGeoreferenceProperties.blender_coordinates = "4.0,5.0,6.0"
|
||||
assert subject.get_coordinates("blender") == [4.0, 5.0, 6.0]
|
||||
bpy.context.scene.BIMGeoreferenceProperties.map_coordinates = "7.0,8.0,9.0"
|
||||
assert subject.get_coordinates("map") == [7.0, 8.0, 9.0]
|
||||
|
||||
|
||||
class TestGetCursorLocation(NewFile):
|
||||
@@ -213,41 +220,6 @@ class TestGetCursorLocation(NewFile):
|
||||
assert subject.get_cursor_location() == [1000.0, 2000.0, 3000.0]
|
||||
|
||||
|
||||
class TestSetCursorLocation(NewFile):
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
|
||||
ifcopenshell.api.run("context.add_context", ifc, context_type="Model")
|
||||
unit = ifcopenshell.api.run("unit.add_si_unit", ifc, unit_type="LENGTHUNIT", prefix="MILLI")
|
||||
ifcopenshell.api.run("unit.assign_unit", ifc, units=[unit])
|
||||
subject.set_cursor_location([1000.0, 2000.0, 3000.0])
|
||||
assert list(bpy.context.scene.cursor.location) == [1.0, 2.0, 3.0]
|
||||
|
||||
|
||||
class TestSetIfcTrueNorth(NewFile):
|
||||
def test_run(self):
|
||||
subject.set_ifc_true_north()
|
||||
assert round(float(bpy.context.scene.BIMGeoreferenceProperties.true_north_abscissa), 3) == 0.0
|
||||
assert round(float(bpy.context.scene.BIMGeoreferenceProperties.true_north_ordinate), 3) == 1.0
|
||||
bpy.context.scene.sun_pos_properties.north_offset = math.radians(45)
|
||||
subject.set_ifc_true_north()
|
||||
assert round(float(bpy.context.scene.BIMGeoreferenceProperties.true_north_abscissa), 3) == 0.707
|
||||
assert round(float(bpy.context.scene.BIMGeoreferenceProperties.true_north_ordinate), 3) == 0.707
|
||||
|
||||
|
||||
class TestSetBlenderTrueNorth(NewFile):
|
||||
def test_run(self):
|
||||
bpy.context.scene.BIMGeoreferenceProperties.true_north_abscissa = "0.0"
|
||||
bpy.context.scene.BIMGeoreferenceProperties.true_north_ordinate = "1.0"
|
||||
subject.set_blender_true_north()
|
||||
assert bpy.context.scene.sun_pos_properties.north_offset == 0
|
||||
bpy.context.scene.BIMGeoreferenceProperties.true_north_abscissa = "0.707"
|
||||
bpy.context.scene.BIMGeoreferenceProperties.true_north_ordinate = "0.707"
|
||||
subject.set_blender_true_north()
|
||||
assert round(math.degrees(bpy.context.scene.sun_pos_properties.north_offset)) == 45
|
||||
|
||||
|
||||
class TestXyz2Enh(NewFile):
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.file()
|
||||
@@ -261,7 +233,7 @@ class TestXyz2Enh(NewFile):
|
||||
tool.Ifc.set(ifc)
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
props.has_blender_offset = True
|
||||
props.blender_eastings = "1.0"
|
||||
props.blender_offset_x = "1.0"
|
||||
assert subject.xyz2enh([0.0, 0.0, 0.0]) == (1.0, 0.0, 0.0)
|
||||
|
||||
def test_using_the_map_conversion(self):
|
||||
@@ -277,7 +249,7 @@ class TestXyz2Enh(NewFile):
|
||||
def test_applying_both_blender_offset_and_map_conversion(self):
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
props.has_blender_offset = True
|
||||
props.blender_eastings = "1.0"
|
||||
props.blender_offset_x = "1.0"
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
|
||||
@@ -301,7 +273,7 @@ class TestEnh2Xyz(NewFile):
|
||||
tool.Ifc.set(ifc)
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
props.has_blender_offset = True
|
||||
props.blender_eastings = "1.0"
|
||||
props.blender_offset_x = "1.0"
|
||||
assert subject.enh2xyz([0.0, 0.0, 0.0]) == (-1.0, 0.0, 0.0)
|
||||
|
||||
def test_using_the_map_conversion(self):
|
||||
@@ -317,7 +289,7 @@ class TestEnh2Xyz(NewFile):
|
||||
def test_applying_both_blender_offset_and_map_conversion(self):
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
props.has_blender_offset = True
|
||||
props.blender_eastings = "1.0"
|
||||
props.blender_offset_x = "1.0"
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
|
||||
@@ -326,60 +298,3 @@ class TestEnh2Xyz(NewFile):
|
||||
map_conversion = ifc.by_type("IfcMapConversion")[0]
|
||||
map_conversion.Northings = 1.0
|
||||
assert subject.enh2xyz([0.0, 0.0, 0.0]) == (-1.0, -1.0, 0.0)
|
||||
|
||||
|
||||
class TestSetIfcGridNorth(NewFile):
|
||||
def test_run(self):
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
new = props.map_conversion.add()
|
||||
new.name = "XAxisAbscissa"
|
||||
new = props.map_conversion.add()
|
||||
new.name = "XAxisOrdinate"
|
||||
subject.set_ifc_grid_north()
|
||||
assert round(float(props.map_conversion.get("XAxisAbscissa").string_value), 3) == 1.0
|
||||
assert round(float(props.map_conversion.get("XAxisOrdinate").string_value), 3) == 0.0
|
||||
bpy.context.scene.sun_pos_properties.north_offset = math.radians(-45)
|
||||
subject.set_ifc_grid_north()
|
||||
assert round(float(props.map_conversion.get("XAxisAbscissa").string_value), 3) == 0.707
|
||||
assert round(float(props.map_conversion.get("XAxisOrdinate").string_value), 3) == -0.707
|
||||
bpy.context.scene.sun_pos_properties.north_offset = math.radians(45)
|
||||
subject.set_ifc_grid_north()
|
||||
assert round(float(props.map_conversion.get("XAxisAbscissa").string_value), 3) == 0.707
|
||||
assert round(float(props.map_conversion.get("XAxisOrdinate").string_value), 3) == 0.707
|
||||
bpy.context.scene.sun_pos_properties.north_offset = math.radians(135)
|
||||
subject.set_ifc_grid_north()
|
||||
assert round(float(props.map_conversion.get("XAxisAbscissa").string_value), 3) == -0.707
|
||||
assert round(float(props.map_conversion.get("XAxisOrdinate").string_value), 3) == 0.707
|
||||
bpy.context.scene.sun_pos_properties.north_offset = math.radians(-135)
|
||||
subject.set_ifc_grid_north()
|
||||
assert round(float(props.map_conversion.get("XAxisAbscissa").string_value), 3) == -0.707
|
||||
assert round(float(props.map_conversion.get("XAxisOrdinate").string_value), 3) == -0.707
|
||||
|
||||
|
||||
class TestSetBlenderGridNorth(NewFile):
|
||||
def test_run(self):
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
new = props.map_conversion.add()
|
||||
new.name = "XAxisAbscissa"
|
||||
new = props.map_conversion.add()
|
||||
new.name = "XAxisOrdinate"
|
||||
props.map_conversion.get("XAxisAbscissa").string_value = "1.0"
|
||||
props.map_conversion.get("XAxisOrdinate").string_value = "0.0"
|
||||
subject.set_blender_grid_north()
|
||||
assert bpy.context.scene.sun_pos_properties.north_offset == 0
|
||||
props.map_conversion.get("XAxisAbscissa").string_value = "0.707"
|
||||
props.map_conversion.get("XAxisOrdinate").string_value = "-0.707"
|
||||
subject.set_blender_grid_north()
|
||||
assert round(math.degrees(bpy.context.scene.sun_pos_properties.north_offset)) == -45
|
||||
props.map_conversion.get("XAxisAbscissa").string_value = "0.707"
|
||||
props.map_conversion.get("XAxisOrdinate").string_value = "0.707"
|
||||
subject.set_blender_grid_north()
|
||||
assert round(math.degrees(bpy.context.scene.sun_pos_properties.north_offset)) == 45
|
||||
props.map_conversion.get("XAxisAbscissa").string_value = "-0.707"
|
||||
props.map_conversion.get("XAxisOrdinate").string_value = "0.707"
|
||||
subject.set_blender_grid_north()
|
||||
assert round(math.degrees(bpy.context.scene.sun_pos_properties.north_offset)) == 135
|
||||
props.map_conversion.get("XAxisAbscissa").string_value = "-0.707"
|
||||
props.map_conversion.get("XAxisOrdinate").string_value = "-0.707"
|
||||
subject.set_blender_grid_north()
|
||||
assert round(math.degrees(bpy.context.scene.sun_pos_properties.north_offset)) == -135
|
||||
|
||||
@@ -21,6 +21,7 @@ import ifcopenshell
|
||||
import test.bim.bootstrap
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
import pytest
|
||||
from blenderbim.tool.ifc import Ifc as subject
|
||||
|
||||
|
||||
@@ -69,28 +70,32 @@ class TestIsMoved(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
element = ifc.createIfcWall()
|
||||
element = ifc.create_entity("IfcWall")
|
||||
subject.link(element, obj)
|
||||
obj.BIMObjectProperties.ifc_definition_id = element.id()
|
||||
assert subject.is_moved(obj) is True
|
||||
|
||||
tool.Geometry.record_object_position(obj)
|
||||
assert subject.is_moved(obj) is False
|
||||
|
||||
obj.matrix_world[0][2] += 1
|
||||
assert subject.is_moved(obj) is True
|
||||
|
||||
def test_that_a_type_or_project_never_moves_but_a_grid_axis_does(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
element = ifc.createIfcWallType()
|
||||
subject.link(element, obj)
|
||||
obj.BIMObjectProperties.ifc_definition_id = element.id()
|
||||
assert subject.is_moved(obj) is False
|
||||
element = ifc.createIfcProject()
|
||||
element = ifc.create_entity("IfcWallType")
|
||||
subject.link(element, obj)
|
||||
assert subject.is_moved(obj) is False
|
||||
element = ifc.createIfcGridAxis()
|
||||
|
||||
element = ifc.create_entity("IfcProject")
|
||||
subject.link(element, obj)
|
||||
assert subject.is_moved(obj) is False
|
||||
|
||||
element = ifc.create_entity("IfcGridAxis")
|
||||
subject.link(element, obj)
|
||||
assert subject.is_moved(obj) is True
|
||||
|
||||
@@ -100,8 +105,8 @@ class TestGetEntity(test.bim.bootstrap.NewFile):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
element = ifc.createIfcWall()
|
||||
obj.BIMObjectProperties.ifc_definition_id = element.id()
|
||||
element = ifc.create_entity("IfcWall")
|
||||
subject.link(element, obj)
|
||||
assert subject.get_entity(obj) == element
|
||||
|
||||
def test_attempting_to_get_an_unlinked_object(self):
|
||||
@@ -122,117 +127,97 @@ class TestGetEntity(test.bim.bootstrap.NewFile):
|
||||
|
||||
|
||||
class TestGetObject(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
def test_get_object(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
element = ifc.createIfcWall()
|
||||
element = ifc.create_entity("IfcWall")
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.link(element, obj)
|
||||
assert subject.get_object(element) == obj
|
||||
|
||||
def test_get_material(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
element = ifc.create_entity("IfcSurfaceStyle")
|
||||
obj = bpy.data.materials.new("Style")
|
||||
subject.link(element, obj)
|
||||
assert subject.get_object(element) == obj
|
||||
|
||||
|
||||
class TestLink(test.bim.bootstrap.NewFile):
|
||||
def test_link_an_object(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
element = ifc.createIfcWall()
|
||||
element = ifc.create_entity("IfcWall")
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.link(element, obj)
|
||||
assert subject.get_entity(obj) == element
|
||||
assert subject.get_object(element) == obj
|
||||
|
||||
def test_link_a_material(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
element = ifc.createIfcMaterial()
|
||||
obj = bpy.data.materials.new("Material")
|
||||
subject.link(element, obj)
|
||||
assert subject.get_entity(obj) == element
|
||||
assert subject.get_object(element) == obj
|
||||
|
||||
def test_link_a_style(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
element = ifc.createIfcSurfaceStyle()
|
||||
element = ifc.create_entity("IfcSurfaceStyle")
|
||||
obj = bpy.data.materials.new("Material")
|
||||
subject.link(element, obj)
|
||||
assert subject.get_entity(obj) == element
|
||||
assert subject.get_object(element) == obj
|
||||
|
||||
def test_link_a_material_and_style(self):
|
||||
def test_link_not_a_style_to_blender_material(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
style = ifc.createIfcSurfaceStyle()
|
||||
material = ifc.createIfcMaterial()
|
||||
element = ifc.create_entity("IfcMaterial")
|
||||
obj = bpy.data.materials.new("Material")
|
||||
subject.link(style, obj)
|
||||
subject.link(material, obj)
|
||||
assert subject.get_entity(obj) == material
|
||||
assert subject.get_object(style) == obj
|
||||
assert subject.get_object(material) == obj
|
||||
with pytest.raises(AttributeError):
|
||||
subject.link(element, obj)
|
||||
|
||||
def test_link_a_mesh(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
element = ifc.create_entity("IfcShapeRepresentation")
|
||||
obj = bpy.data.meshes.new("Material")
|
||||
subject.link(element, obj)
|
||||
assert obj.BIMMeshProperties.ifc_definition_id == element.id()
|
||||
|
||||
|
||||
class TestUnlink(test.bim.bootstrap.NewFile):
|
||||
def test_unlink_an_object(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
element = ifc.createIfcWall()
|
||||
element = ifc.create_entity("IfcWall")
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.link(element, obj)
|
||||
subject.unlink(element, obj)
|
||||
assert subject.get_entity(obj) is None
|
||||
assert subject.get_object(element) is None
|
||||
|
||||
def test_unlink_a_material(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
element = ifc.createIfcMaterial()
|
||||
obj = bpy.data.materials.new("Material")
|
||||
subject.link(element, obj)
|
||||
subject.unlink(element, obj)
|
||||
subject.unlink(element)
|
||||
assert subject.get_entity(obj) is None
|
||||
assert subject.get_object(element) is None
|
||||
|
||||
def test_unlink_a_style(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
element = ifc.createIfcSurfaceStyle()
|
||||
element = ifc.create_entity("IfcSurfaceStyle")
|
||||
obj = bpy.data.materials.new("Material")
|
||||
subject.link(element, obj)
|
||||
subject.unlink(element, obj)
|
||||
assert subject.get_object(element) is None
|
||||
|
||||
def test_unlink_a_style_and_material(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
style = ifc.createIfcSurfaceStyle()
|
||||
material = ifc.createIfcMaterial()
|
||||
obj = bpy.data.materials.new("Material")
|
||||
subject.link(style, obj)
|
||||
subject.link(material, obj)
|
||||
subject.unlink(element=style, obj=obj)
|
||||
assert subject.get_entity(obj) == material
|
||||
assert subject.get_object(material) == obj
|
||||
assert subject.get_object(style) is None
|
||||
subject.unlink(element=material, obj=obj)
|
||||
subject.unlink(element)
|
||||
assert subject.get_entity(obj) is None
|
||||
assert subject.get_object(material) is None
|
||||
assert subject.get_object(element) is None
|
||||
|
||||
def test_unlinking_using_an_object(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
element = ifc.createIfcWall()
|
||||
element = ifc.create_entity("IfcWall")
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.link(element, obj)
|
||||
subject.unlink(obj=obj)
|
||||
assert subject.get_entity(obj) is None
|
||||
assert subject.get_object(element) is None
|
||||
assert subject.get_object(element) is obj
|
||||
|
||||
def test_unlinking_using_an_element(self):
|
||||
def test_unlinking_using_both_arguments(self):
|
||||
ifc = ifcopenshell.file()
|
||||
subject.set(ifc)
|
||||
element = ifc.createIfcWall()
|
||||
element = ifc.create_entity("IfcWall")
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
subject.link(element, obj)
|
||||
subject.unlink(element=element)
|
||||
assert subject.get_entity(obj) is None
|
||||
assert subject.get_object(element) is None
|
||||
with pytest.raises(TypeError):
|
||||
subject.unlink(element=element, obj=obj)
|
||||
assert subject.get_entity(obj) == element
|
||||
assert subject.get_object(element) == obj
|
||||
|
||||
@@ -24,6 +24,7 @@ import test.bim.bootstrap
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.core.root
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.import_ifc as import_ifc
|
||||
import blenderbim.bim.module.qto.calculator as calculator
|
||||
from blenderbim.tool.qto import Qto as subject
|
||||
|
||||
@@ -53,9 +54,17 @@ class TestGetRoundedValue(test.bim.bootstrap.NewFile):
|
||||
|
||||
class TestGetCalculatedObjectQuantities(test.bim.bootstrap.NewFile):
|
||||
def setup_file(self):
|
||||
import logging
|
||||
|
||||
self.ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(self.ifc)
|
||||
ifcopenshell.api.run("root.create_entity", self.ifc, ifc_class="IfcProject", name="My Project")
|
||||
ifc_import_settings = import_ifc.IfcImportSettings.factory(
|
||||
bpy.context, tool.Ifc.get_path(), logging.getLogger("ImportIFC")
|
||||
)
|
||||
ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
|
||||
ifc_importer.file = self.ifc
|
||||
ifc_importer.create_project()
|
||||
|
||||
def setup_units(self, units):
|
||||
ifcopenshell.api.run("unit.assign_unit", self.ifc, **units)
|
||||
|
||||
@@ -47,9 +47,9 @@ class TestGetGlobalMatrix(test.bim.bootstrap.NewFile):
|
||||
tool.Ifc.set(ifc)
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
props.has_blender_offset = True
|
||||
props.blender_eastings = "1000"
|
||||
props.blender_northings = "2000"
|
||||
props.blender_orthogonal_height = "3000"
|
||||
props.blender_offset_x = "1000"
|
||||
props.blender_offset_y = "2000"
|
||||
props.blender_offset_z = "3000"
|
||||
props.blender_x_axis_abscissa = "0"
|
||||
props.blender_x_axis_ordinate = "1"
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
import numpy as np
|
||||
@@ -229,16 +230,14 @@ class TestImportSystems(NewFile):
|
||||
|
||||
class TestLoadPorts(NewFile):
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.api.run("project.create_file")
|
||||
ifcopenshell.api.run("root.create_entity", ifc, ifc_class="IfcProject")
|
||||
ifcopenshell.api.run("unit.assign_unit", ifc)
|
||||
tool.Ifc().set(ifc)
|
||||
bpy.ops.bim.create_project()
|
||||
ifc = tool.Ifc.get()
|
||||
|
||||
element = ifc.createIfcChiller()
|
||||
element = ifc.create_entity("IfcChiller")
|
||||
obj = bpy.data.objects.new("Object", None)
|
||||
tool.Ifc.link(element, obj)
|
||||
|
||||
port = ifc.createIfcDistributionPort()
|
||||
port = ifc.create_entity("IfcDistributionPort")
|
||||
subject.load_ports(element, [port])
|
||||
obj = tool.Ifc.get_object(port)
|
||||
assert obj
|
||||
|
||||
@@ -888,7 +888,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCurveSegment* inst) {
|
||||
|
||||
auto length = cse.length();
|
||||
|
||||
taxonomy::piecewise_function::spans spans;
|
||||
taxonomy::piecewise_function::spans_t spans;
|
||||
spans.emplace_back(fabs(length), fn);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(0.0, spans,&settings_,inst);
|
||||
return pwf;
|
||||
|
||||
@@ -84,7 +84,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcGradientCurve* inst) {
|
||||
return m;
|
||||
};
|
||||
|
||||
taxonomy::piecewise_function::spans spans;
|
||||
taxonomy::piecewise_function::spans_t spans;
|
||||
spans.emplace_back(length, composition);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(start, spans, &settings_, inst);
|
||||
return pwf;
|
||||
|
||||
@@ -43,7 +43,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
|
||||
double start = pw_curve->start();
|
||||
double basis_curve_length = pw_curve->length();
|
||||
|
||||
taxonomy::piecewise_function::spans offset_spans;
|
||||
taxonomy::piecewise_function::spans_t offset_spans;
|
||||
|
||||
#if defined SCHEMA_HAS_IfcDistanceExpression
|
||||
double first_distance = first_offset_value->DistanceAlong();
|
||||
@@ -155,7 +155,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances* inst
|
||||
|
||||
// current implementation assumes that composition is equal to the full length of basis curve
|
||||
// this may change depending on decisions in the bSI-IF
|
||||
taxonomy::piecewise_function::spans spans;
|
||||
taxonomy::piecewise_function::spans_t spans;
|
||||
spans.emplace_back(basis_curve_length, composition);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(start,spans,&settings_,inst);
|
||||
return pwf;
|
||||
|
||||
@@ -83,7 +83,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins
|
||||
return m;
|
||||
};
|
||||
|
||||
taxonomy::piecewise_function::spans spans;
|
||||
taxonomy::piecewise_function::spans_t spans;
|
||||
spans.emplace_back(length, composition);
|
||||
auto pwf = taxonomy::make<taxonomy::piecewise_function>(start, spans, &settings_, inst);
|
||||
return pwf;
|
||||
|
||||
@@ -612,6 +612,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcStyledItem* inst) {
|
||||
taxonomy::ptr mapping::map(const IfcBaseInterface* inst) {
|
||||
auto iden = inst->as<IfcUtil::IfcBaseClass>()->identity();
|
||||
if (use_caching_) {
|
||||
std::lock_guard<std::mutex> guard(cache_guard_);
|
||||
auto it = cache_.find(iden);
|
||||
if (it != cache_.end()) {
|
||||
return it->second;
|
||||
@@ -629,7 +630,8 @@ taxonomy::ptr mapping::map(const IfcBaseInterface* inst) {
|
||||
|
||||
if (item) {
|
||||
if (use_caching_) {
|
||||
cache_.insert({ iden, item });
|
||||
std::lock_guard<std::mutex> guard(cache_guard_);
|
||||
cache_.insert({iden, item});
|
||||
}
|
||||
} else if (!matched) {
|
||||
Logger::Message(Logger::LOG_ERROR, "No operation defined for:", inst);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "../../ifcparse/IfcFile.h"
|
||||
#include "../../ifcparse/IfcLogger.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h)
|
||||
#include INCLUDE_SCHEMA(IfcSchema)
|
||||
#undef INCLUDE_SCHEMA
|
||||
@@ -24,6 +26,7 @@ namespace geometry {
|
||||
std::string length_unit_name_;
|
||||
|
||||
std::map<uint32_t, ifcopenshell::geometry::taxonomy::ptr> cache_;
|
||||
std::mutex cache_guard_; // provides mutually exclusive access to cache_
|
||||
|
||||
const IfcParse::declaration* placement_rel_to_type_;
|
||||
const IfcUtil::IfcBaseEntity* placement_rel_to_instance_;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user