Compare commits

...

43 Commits

Author SHA1 Message Date
Ryan Schultz c62ed5d3b6 shift+click, to quickly switch the drawing view without turning anything on or off in the scene.
as discussed: https://community.osarch.org/discussion/2196/quick-way-to-switch-between-drawing-views#latest
2024-08-04 10:00:22 -05:00
Ryan Schultz ffb6c82541 snapshot 2024-08-04 09:40:34 -05:00
Ryan Schultz a9e366b238 Assure text 'wraps' in CloseError 2024-08-03 14:30:06 -05:00
Ryan Schultz 1ca0dfb1e0 Make sure drawings are loaded when calling bim.activate_drawing from sheets UI.
related: c11ba23a3d
2024-08-03 14:09:15 -05:00
Ryan Schultz c11ba23a3d Fix #3728 - Be able to bim.activate_drawing a drawing listed in the sheets UI, as well. 2024-08-03 11:01:31 -05:00
Dion Moult 556c769b40 Sun position add-on is now detected in the current session instead of needing to restart Blender 2024-08-03 23:21:31 +10:00
Dion Moult 78173dd546 Add basic tests for new web module 2024-08-03 23:12:21 +10:00
Dion Moult 2196c16097 Fix failing georeference and spatial core/tool/bim tests and clean dead code 2024-08-03 23:08:35 +10:00
Dion Moult 7af5db7cd4 Collector now unassigns from old ifc collections 2024-08-03 22:04:38 +10:00
Dion Moult c58672cc25 Allow selecting a container object when changing spatial container 2024-08-03 19:29:06 +10:00
Dion Moult 85e022d76e IfcTester now groups results by types to make long failure lists more useful 2024-08-02 23:58:01 +10:00
Andrej730 872f40933f remove Python 3.9 from bbim makefile since a31051a93 2024-08-02 18:54:37 +05:00
Andrej730 4491018f5e fix tool surveyor test 2024-08-02 18:54:37 +05:00
Andrej730 a21c440b5b fix tool geometry tests 2024-08-02 18:54:37 +05:00
Andrej730 143e094db8 assign default container on assigning IfcAnnotation class
Currently if you create a IfcAnnotation it might just get lost as it's not assigned anywhere. Also noticed this since previously we allowed using bim.add_reference_image without any specific drawings.
2024-08-02 18:54:37 +05:00
Andrej730 94e9e945d7 fix system/qto tool tests after e6ac012 2024-08-02 18:54:36 +05:00
Andrej730 5e56115050 typing 2024-08-02 18:54:36 +05:00
Andrej730 1ad654aab3 Fix Ifc tool tests after #4843 and unlinking changes 2024-08-02 18:54:36 +05:00
Andrej730 596ffb093b dev environment script - keep it possible to run the script without any changes
by default it assumes it's executed from ifcopenshell repo directory
2024-08-02 18:54:36 +05:00
Andrej730 3576362fd8 blenderbim make test - run all tests but return error code at the end 2024-08-02 18:11:25 +05:00
Andrej730 2c949bb39a blenderbim "make test" - run tool and bim tests even if some core tests failed 2024-08-02 17:20:29 +05:00
Andrej730 34faa0617b fix running core tests on python 3.10 2024-08-02 17:05:28 +05:00
Dion Moult 15f6b3803f Fix #4986. IfcTester now determines whether a spec is relevant to the ifc version 2024-08-02 22:02:56 +10:00
Andrej730 8514a426bb fix potential blenderbim issues for python 3.10
tomllib was added to python 3.11, tomli can be used for the previous versions.

Though it is a bit questionable since internally Blender is using just tomllib and because of that I'm not sure anymore if Blender still supports Python 3.10.
2024-08-02 16:00:49 +05:00
Andrej730 2062324294 prevent issues importing blenderbim for core test
initialize_bbim_semver was possible breaking on running core tests if system python was missing tomllib
2024-08-02 16:00:49 +05:00
Dion Moult 90c6218210 Fix #5115. Members (e.g. stringers) can now have a stair modifier applied as they may be used to support stairs 2024-08-02 16:34:30 +10:00
Dion Moult 321bb7178d See #5110. Minor fix when appending linked elements. 2024-08-02 16:29:14 +10:00
Dion Moult 42dda0a07a Run black on light 2024-08-02 16:00:45 +10:00
Dion Moult adb17d91f9 Dedicated doc section for blend open/save issue 2024-08-02 15:57:17 +10:00
Dion Moult 646cc59687 Update live install script on linux/mac and merge system support docs into dev setup docs 2024-08-02 15:57:17 +10:00
Dion Moult 38759348cd Document new install location on 4.2 2024-08-02 15:57:17 +10:00
Dion Moult ff44f4f395 Show warning if a blend file is used alongside an ifc 2024-08-02 15:57:17 +10:00
Dion Moult a31051a937 Drop py39 from build matrix for BBIM as we now only support Blender >=4.2 2024-08-02 15:57:17 +10:00
Chirag Singh 5cfd69f337 Merge branch 'v0.8.0' of https://github.com/IfcOpenShell/IfcOpenShell into v0.8.0 2024-08-02 11:23:09 +05:30
Chirag Singh f4100f7951 Added HDR support 2024-08-02 11:22:40 +05:30
Thomas Krijnen 785d5118d0 installation.rst - minor enhancement 2024-08-02 05:02:20 +02:00
Thomas Krijnen fddd85817a installation.rst - minor doc enhancements 2024-08-02 04:59:09 +02:00
Thomas Krijnen a689fc6377 Consistency TopExp_Explorer::Current() 2024-08-02 04:50:06 +02:00
Augustin Trancart 8e5a7ed24e improve json lib discovery for cmake 2024-08-02 03:31:17 +02:00
Dion Moult 788217c73c Use loader to get name instead of hardcoding when loading IFCs. See #4517. 2024-08-02 09:31:15 +10:00
Blender Defender 1abc3a1422 feat: Update the patch UI of ResetAbsoluteCoordinates
Instead of specifying parameters `a`, `b`, `c` and `d`, more meaningful parameters have been introduced (`threshold`, `automatic_offset_point`, `x`, `y` and `z`), which allow to do the same operations in a more understandable way.
2024-08-02 08:26:14 +10:00
Richard Brice c31c34b7d2 reimplements piecewise_function using PIMPL idiom
PIMPL idiom allows implementaiton of piecewise_function to evolve without envoking systemwide recompile (unless the class definition changes)
2024-08-01 12:34:49 -07:00
Richard Brice b22ecba179 Implements mutually exclusive access to mapping cache with a mutex 2024-08-01 07:15:22 -07:00
110 changed files with 1277 additions and 1091 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
strategy:
fail-fast: false
matrix:
pyver: [py39, py310, py311, py312]
pyver: [py310, py311, py312]
config:
- {
name: "Windows Build",
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
strategy:
fail-fast: false
matrix:
pyver: [py39, py310, py311, py312]
pyver: [py310, py311, py312]
config:
- {
name: "Windows Build",
+4 -3
View File
@@ -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
View File
@@ -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:
+6 -5
View File
@@ -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
+4 -2
View File
@@ -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
+1
View File
@@ -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
+4 -4
View File
@@ -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):
@@ -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
+20 -1
View File
@@ -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)
+2
View File
@@ -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)
+8 -11
View File
@@ -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
+3 -1
View File
@@ -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):
+2
View File
@@ -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
+13 -1
View File
@@ -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"):
+1
View File
@@ -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
+1 -1
View File
@@ -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:
+2 -33
View File
@@ -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
+11 -3
View File
@@ -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
+4
View File
@@ -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
+1 -1
View File
@@ -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:
+10
View File
@@ -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
+2 -1
View File
@@ -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":
+55 -67
View File
@@ -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.
-6
View File
@@ -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/``.
+22 -29
View File
@@ -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.
+1
View File
@@ -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
+1
View File
@@ -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
+1
View File
@@ -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
+2 -1
View File
@@ -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
+63 -52
View File
@@ -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)
+1
View File
@@ -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
+1
View File
@@ -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
+4 -7
View File
@@ -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
+40 -125
View File
@@ -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
+53 -68
View File
@@ -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
+9
View File
@@ -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)
+3 -3
View File
@@ -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)
+5 -6
View File
@@ -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
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+3 -1
View File
@@ -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);
+3
View File
@@ -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