mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
You can now edit attributes of contexts and subcontexts. Fix bug where 2D contexts were not created with the right dimensionality.
This commit is contained in:
@@ -20,8 +20,11 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.AddSubcontext,
|
||||
operator.RemoveSubcontext,
|
||||
operator.AddContext,
|
||||
operator.DisableEditingContext,
|
||||
operator.EditContext,
|
||||
operator.EnableEditingContext,
|
||||
operator.RemoveContext,
|
||||
prop.BIMContextProperties,
|
||||
ui.BIM_PT_context,
|
||||
)
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
@@ -15,7 +34,13 @@ class ContextData:
|
||||
results = []
|
||||
for context in tool.Ifc.get().by_type("IfcGeometricRepresentationContext", include_subtypes=False):
|
||||
results.append(
|
||||
{"id": context.id(), "context_type": context.ContextType, "subcontexts": cls.get_subcontexts(context)}
|
||||
{
|
||||
"id": context.id(),
|
||||
"context_type": context.ContextType,
|
||||
"subcontexts": cls.get_subcontexts(context),
|
||||
"is_editing": bpy.context.scene.BIMContextProperties.active_context_id == context.id(),
|
||||
"props": bpy.context.scene.BIMContextProperties.context_attributes,
|
||||
}
|
||||
)
|
||||
return results
|
||||
|
||||
@@ -29,6 +54,8 @@ class ContextData:
|
||||
"context_type": subcontext.ContextType,
|
||||
"context_identifier": subcontext.ContextIdentifier,
|
||||
"target_view": subcontext.TargetView,
|
||||
"is_editing": bpy.context.scene.BIMContextProperties.active_context_id == subcontext.id(),
|
||||
"props": bpy.context.scene.BIMContextProperties.context_attributes,
|
||||
}
|
||||
)
|
||||
return results
|
||||
|
||||
@@ -31,23 +31,58 @@ class Operator:
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddSubcontext(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.add_subcontext"
|
||||
class AddContext(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.add_context"
|
||||
bl_label = "Add Subcontext"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
context: bpy.props.StringProperty()
|
||||
subcontext: bpy.props.StringProperty()
|
||||
context_type: bpy.props.StringProperty()
|
||||
context_identifier: bpy.props.StringProperty()
|
||||
target_view: bpy.props.StringProperty()
|
||||
parent: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.add_context(tool.Ifc, context=self.context, subcontext=self.subcontext, target_view=self.target_view)
|
||||
core.add_context(
|
||||
tool.Ifc,
|
||||
context_type=self.context_type,
|
||||
context_identifier=self.context_identifier,
|
||||
target_view=self.target_view,
|
||||
parent=tool.Ifc.get().by_id(self.parent) if self.parent else None,
|
||||
)
|
||||
|
||||
|
||||
class RemoveSubcontext(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.remove_subcontext"
|
||||
class RemoveContext(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.remove_context"
|
||||
bl_label = "Remove Context"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
context: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.remove_context(tool.Ifc, context=tool.Ifc.get().by_id(self.context))
|
||||
|
||||
|
||||
class EnableEditingContext(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.enable_editing_context"
|
||||
bl_label = "Enable Editing Context"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
context: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.enable_editing_context(tool.ContextEditor, context=tool.Ifc.get().by_id(self.context))
|
||||
|
||||
|
||||
class DisableEditingContext(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.disable_editing_context"
|
||||
bl_label = "Disable Editing Context"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
core.disable_editing_context(tool.ContextEditor)
|
||||
|
||||
|
||||
class EditContext(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.edit_context"
|
||||
bl_label = "Edit Context"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
core.edit_context(tool.Ifc, tool.ContextEditor)
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from blenderbim.bim.module.context.data import ContextData
|
||||
@@ -46,3 +64,5 @@ class BIMContextProperties(PropertyGroup):
|
||||
],
|
||||
name="Target Views",
|
||||
)
|
||||
active_context_id: IntProperty(name="Active Context Id")
|
||||
context_attributes: CollectionProperty(name="Context Attributes", type=Attribute)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.module.context.data import ContextData
|
||||
|
||||
@@ -41,21 +42,45 @@ class BIM_PT_context(bpy.types.Panel):
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "contexts", text="")
|
||||
row.prop(props, "subcontexts", text="")
|
||||
row.prop(props, "target_views", text="")
|
||||
op = row.operator("bim.add_subcontext", icon="ADD", text="")
|
||||
op.context = props.contexts
|
||||
op.subcontext = props.subcontexts
|
||||
op.target_view = props.target_views
|
||||
op = row.operator("bim.add_context", icon="ADD", text="")
|
||||
op.context_type = props.contexts
|
||||
op.context_identifier = ""
|
||||
op.target_view = ""
|
||||
op.parent = 0
|
||||
|
||||
for context in ContextData.data["contexts"]:
|
||||
for ifc_context in ContextData.data["contexts"]:
|
||||
box = self.layout.box()
|
||||
row = box.row(align=True)
|
||||
row.label(text=context["context_type"])
|
||||
row.operator("bim.remove_subcontext", icon="X", text="").context = context["id"]
|
||||
for subcontext in context["subcontexts"]:
|
||||
|
||||
if ifc_context["is_editing"]:
|
||||
row = box.row(align=True)
|
||||
row.label(text=subcontext["context_type"])
|
||||
row.label(text=subcontext["context_identifier"])
|
||||
row.label(text=subcontext["target_view"])
|
||||
row.operator("bim.remove_subcontext", icon="X", text="").context = subcontext["id"]
|
||||
row.operator("bim.edit_context", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_context", icon="CANCEL", text="")
|
||||
blenderbim.bim.helper.draw_attributes(ifc_context["props"], box)
|
||||
else:
|
||||
row = box.row(align=True)
|
||||
row.label(text=ifc_context["context_type"])
|
||||
row.operator("bim.enable_editing_context", icon="GREASEPENCIL", text="").context = ifc_context["id"]
|
||||
row.operator("bim.remove_context", icon="X", text="").context = ifc_context["id"]
|
||||
|
||||
row = box.row(align=True)
|
||||
row.prop(props, "subcontexts", text="")
|
||||
row.prop(props, "target_views", text="")
|
||||
op = row.operator("bim.add_context", icon="ADD", text="")
|
||||
op.context_type = ifc_context["context_type"]
|
||||
op.context_identifier = props.subcontexts
|
||||
op.target_view = props.target_views
|
||||
op.parent = ifc_context["id"]
|
||||
|
||||
for subcontext in ifc_context["subcontexts"]:
|
||||
if subcontext["is_editing"]:
|
||||
row = box.row(align=True)
|
||||
row.operator("bim.edit_context", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_context", icon="CANCEL", text="")
|
||||
blenderbim.bim.helper.draw_attributes(subcontext["props"], box)
|
||||
else:
|
||||
row = box.row(align=True)
|
||||
row.label(text=subcontext["context_type"])
|
||||
row.label(text=subcontext["context_identifier"])
|
||||
row.label(text=subcontext["target_view"])
|
||||
row.operator("bim.enable_editing_context", icon="GREASEPENCIL", text="").context = subcontext["id"]
|
||||
row.operator("bim.remove_context", icon="X", text="").context = subcontext["id"]
|
||||
|
||||
@@ -226,9 +226,7 @@ class EnableEditingOrganisation(bpy.types.Operator, Operator):
|
||||
organisation: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.enable_editing_organisation(
|
||||
tool.OrganisationEditor, organisation=tool.Ifc.get().by_id(self.organisation)
|
||||
)
|
||||
core.enable_editing_organisation(tool.OrganisationEditor, organisation=tool.Ifc.get().by_id(self.organisation))
|
||||
|
||||
|
||||
class DisableEditingOrganisation(bpy.types.Operator, Operator):
|
||||
|
||||
@@ -26,6 +26,8 @@ import ifcopenshell.api
|
||||
import ifcopenshell.util.selector
|
||||
import ifcopenshell.util.representation
|
||||
import blenderbim.bim.handler
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.context as context_core
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim import import_ifc
|
||||
|
||||
@@ -65,11 +67,21 @@ class CreateProject(bpy.types.Operator):
|
||||
|
||||
bpy.ops.bim.assign_class(obj=project.name, ifc_class="IfcProject")
|
||||
bpy.ops.bim.assign_unit()
|
||||
bpy.ops.bim.add_subcontext(context="Model")
|
||||
bpy.ops.bim.add_subcontext(context="Model", subcontext="Body", target_view="MODEL_VIEW")
|
||||
bpy.ops.bim.add_subcontext(context="Model", subcontext="Box", target_view="MODEL_VIEW")
|
||||
bpy.ops.bim.add_subcontext(context="Plan")
|
||||
bpy.ops.bim.add_subcontext(context="Plan", subcontext="Annotation", target_view="PLAN_VIEW")
|
||||
|
||||
# TODO: refactor
|
||||
model = context_core.add_context(
|
||||
tool.Ifc, context_type="Model", context_identifier="", target_view="", parent=0
|
||||
)
|
||||
context_core.add_context(
|
||||
tool.Ifc, context_type="Model", context_identifier="Body", target_view="MODEL_VIEW", parent=model
|
||||
)
|
||||
context_core.add_context(
|
||||
tool.Ifc, context_type="Model", context_identifier="Box", target_view="MODEL_VIEW", parent=model
|
||||
)
|
||||
plan = context_core.add_context(tool.Ifc, context_type="Plan", context_identifier="", target_view="", parent=0)
|
||||
context_core.add_context(
|
||||
tool.Ifc, context_type="Plan", context_identifier="Annotation", target_view="PLAN_VIEW", parent=plan
|
||||
)
|
||||
|
||||
context.scene.BIMProperties.contexts = str(
|
||||
ifcopenshell.util.representation.get_context(self.file, "Model", "Body", "MODEL_VIEW").id()
|
||||
|
||||
@@ -17,9 +17,29 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
def add_context(ifc, context=None, subcontext=None, target_view=None):
|
||||
return ifc.run("context.add_context", context=context, subcontext=subcontext, target_view=target_view)
|
||||
def add_context(ifc, context_type=None, context_identifier=None, target_view=None, parent=None):
|
||||
return ifc.run(
|
||||
"context.add_context",
|
||||
context_type=context_type,
|
||||
context_identifier=context_identifier,
|
||||
target_view=target_view,
|
||||
parent=parent,
|
||||
)
|
||||
|
||||
|
||||
def remove_context(ifc, context=None):
|
||||
ifc.run("context.remove_context", context=context)
|
||||
|
||||
|
||||
def enable_editing_context(context_editor, context=None):
|
||||
context_editor.set_context(context)
|
||||
context_editor.import_attributes()
|
||||
|
||||
|
||||
def disable_editing_context(context_editor):
|
||||
context_editor.clear_context()
|
||||
|
||||
|
||||
def edit_context(ifc, context_editor):
|
||||
ifc.run("context.edit_context", context=context_editor.get_context(), attributes=context_editor.export_attributes())
|
||||
disable_editing_context(context_editor)
|
||||
|
||||
@@ -22,3 +22,4 @@ from blenderbim.core.tool.person_editor import PersonEditor
|
||||
from blenderbim.core.tool.role_editor import RoleEditor
|
||||
from blenderbim.core.tool.address_editor import AddressEditor
|
||||
from blenderbim.core.tool.organisation_editor import OrganisationEditor
|
||||
from blenderbim.core.tool.context_editor import ContextEditor
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
class ContextEditor(abc.ABC):
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def set_context(cls, context):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def import_attributes(cls):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def clear_context(cls):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def get_context(cls):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def export_attributes(cls):
|
||||
pass
|
||||
@@ -22,3 +22,4 @@ from blenderbim.tool.person_editor import PersonEditor
|
||||
from blenderbim.tool.role_editor import RoleEditor
|
||||
from blenderbim.tool.address_editor import AddressEditor
|
||||
from blenderbim.tool.organisation_editor import OrganisationEditor
|
||||
from blenderbim.tool.context_editor import ContextEditor
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.tool.context_editor
|
||||
|
||||
|
||||
class ContextEditor(blenderbim.core.tool.context_editor.ContextEditor):
|
||||
@classmethod
|
||||
def set_context(cls, context):
|
||||
bpy.context.scene.BIMContextProperties.active_context_id = context.id()
|
||||
|
||||
@classmethod
|
||||
def import_attributes(cls):
|
||||
props = bpy.context.scene.BIMContextProperties
|
||||
props.context_attributes.clear()
|
||||
context = cls.get_context()
|
||||
|
||||
def callback(name, prop, data):
|
||||
if context.is_a("IfcGeometricRepresentationSubContext"):
|
||||
if name == "Precision":
|
||||
props.context_attributes.remove(props.context_attributes.find("Precision"))
|
||||
return True
|
||||
elif name == "CoordinateSpaceDimension":
|
||||
props.context_attributes.remove(props.context_attributes.find("CoordinateSpaceDimension"))
|
||||
return True
|
||||
|
||||
blenderbim.bim.helper.import_attributes(context.is_a(), props.context_attributes, context.get_info(), callback)
|
||||
|
||||
@classmethod
|
||||
def clear_context(cls):
|
||||
bpy.context.scene.BIMContextProperties.active_context_id = 0
|
||||
|
||||
@classmethod
|
||||
def get_context(cls):
|
||||
return tool.Ifc.get().by_id(bpy.context.scene.BIMContextProperties.active_context_id)
|
||||
|
||||
@classmethod
|
||||
def export_attributes(cls):
|
||||
return blenderbim.bim.helper.export_attributes(bpy.context.scene.BIMContextProperties.context_attributes)
|
||||
@@ -2,13 +2,42 @@
|
||||
Feature: Context
|
||||
Manages geometric representation contexts and subcontexts
|
||||
|
||||
Scenario: Add subcontext
|
||||
Scenario: Add context
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_subcontext(context='Model', subcontext='Body', target_view='MODEL_VIEW')"
|
||||
When I press "bim.add_context(context_type='Model', context_identifier='', target_view='', parent=0)"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Remove subcontext
|
||||
Scenario: Add a subcontext
|
||||
Given an empty IFC project
|
||||
When the variable "parent" is "IfcStore.get_file().by_type('IfcGeometricRepresentationContext', include_subtypes=False)[0].id()"
|
||||
When I press "bim.add_context(context_type='Model', context_identifier='Body', target_view='MODEL_VIEW', parent={parent})"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Remove context
|
||||
Given an empty IFC project
|
||||
When the variable "context" is "IfcStore.get_file().by_type('IfcGeometricRepresentationContext')[0].id()"
|
||||
And I press "bim.remove_subcontext(context={context})"
|
||||
And I press "bim.remove_context(context={context})"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Enable editing context
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_context(context_type='Model', context_identifier='', target_view='', parent=0)"
|
||||
And the variable "context" is "IfcStore.get_file().by_type('IfcGeometricRepresentationContext')[0].id()"
|
||||
And I press "bim.enable_editing_context(context={context})"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Disable editing context
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_context(context_type='Model', context_identifier='', target_view='', parent=0)"
|
||||
And the variable "context" is "IfcStore.get_file().by_type('IfcGeometricRepresentationContext')[0].id()"
|
||||
And I press "bim.enable_editing_context(context={context})"
|
||||
And I press "bim.disable_editing_context()"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Edit context
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_context(context_type='Model', context_identifier='', target_view='', parent=0)"
|
||||
And the variable "context" is "IfcStore.get_file().by_type('IfcGeometricRepresentationContext')[0].id()"
|
||||
And I press "bim.enable_editing_context(context={context})"
|
||||
And I press "bim.edit_context"
|
||||
Then nothing happens
|
||||
|
||||
@@ -63,6 +63,13 @@ def organisation_editor():
|
||||
prophet.verify()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def context_editor():
|
||||
prophet = Prophecy(blenderbim.core.tool.ContextEditor)
|
||||
yield prophet
|
||||
prophet.verify()
|
||||
|
||||
|
||||
class Prophecy:
|
||||
def __init__(self, cls):
|
||||
self.subject = cls
|
||||
|
||||
@@ -17,18 +17,58 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import blenderbim.core.context as subject
|
||||
from test.core.bootstrap import ifc
|
||||
from test.core.bootstrap import ifc, context_editor
|
||||
|
||||
|
||||
class TestAddContext:
|
||||
def test_adding_a_context(self, ifc):
|
||||
ifc.run(
|
||||
"context.add_context", context="Model", subcontext="Body", target_view="MODEL_VIEW"
|
||||
"context.add_context", context_type="Model", context_identifier=None, target_view=None, parent=None
|
||||
).should_be_called().will_return("context")
|
||||
assert subject.add_context(ifc, context="Model", subcontext="Body", target_view="MODEL_VIEW") == "context"
|
||||
assert (
|
||||
subject.add_context(ifc, context_type="Model", context_identifier=None, target_view=None, parent=None)
|
||||
== "context"
|
||||
)
|
||||
|
||||
def test_adding_a_subcontext(self, ifc):
|
||||
ifc.run(
|
||||
"context.add_context",
|
||||
context_type="Model",
|
||||
context_identifier="Body",
|
||||
target_view="MODEL_VIEW",
|
||||
parent="parent",
|
||||
).should_be_called().will_return("subcontext")
|
||||
assert (
|
||||
subject.add_context(
|
||||
ifc, context_type="Model", context_identifier="Body", target_view="MODEL_VIEW", parent="parent"
|
||||
)
|
||||
== "subcontext"
|
||||
)
|
||||
|
||||
|
||||
class TestRemoveContext:
|
||||
def test_removing_a_context(self, ifc):
|
||||
ifc.run("context.remove_context", context="context").should_be_called()
|
||||
subject.remove_context(ifc, context="context")
|
||||
|
||||
|
||||
class TestEnableEditingContext:
|
||||
def test_run(self, context_editor):
|
||||
context_editor.set_context("context").should_be_called()
|
||||
context_editor.import_attributes().should_be_called()
|
||||
subject.enable_editing_context(context_editor, context="context")
|
||||
|
||||
|
||||
class TestDisableEditingContext:
|
||||
def test_run(self, context_editor):
|
||||
context_editor.clear_context().should_be_called()
|
||||
subject.disable_editing_context(context_editor)
|
||||
|
||||
|
||||
class TestEditContext:
|
||||
def test_run(self, ifc, context_editor):
|
||||
context_editor.get_context().should_be_called().will_return("context")
|
||||
context_editor.export_attributes().should_be_called().will_return("attributes")
|
||||
ifc.run("context.edit_context", context="context", attributes="attributes").should_be_called()
|
||||
context_editor.clear_context().should_be_called()
|
||||
subject.edit_context(ifc, context_editor)
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import test.bim.bootstrap
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.tool.context_editor import ContextEditor as subject
|
||||
|
||||
|
||||
class TestImplementsTool(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
assert isinstance(subject(), blenderbim.core.tool.context_editor.ContextEditor)
|
||||
|
||||
|
||||
class TestSetContext(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.file()
|
||||
context = ifc.createIfcGeometricRepresentationContext()
|
||||
subject.set_context(context)
|
||||
assert bpy.context.scene.BIMContextProperties.active_context_id == context.id()
|
||||
|
||||
|
||||
class TestImportAttributes(test.bim.bootstrap.NewFile):
|
||||
def test_importing_a_context(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
context = ifc.createIfcGeometricRepresentationContext()
|
||||
context.ContextIdentifier = "ContextIdentifier"
|
||||
context.ContextType = "ContextType"
|
||||
context.CoordinateSpaceDimension = 1
|
||||
context.Precision = 1
|
||||
subject.set_context(context)
|
||||
subject.import_attributes()
|
||||
props = bpy.context.scene.BIMContextProperties
|
||||
assert props.context_attributes.get("ContextIdentifier").string_value == "ContextIdentifier"
|
||||
assert props.context_attributes.get("ContextType").string_value == "ContextType"
|
||||
assert props.context_attributes.get("CoordinateSpaceDimension").int_value == 1
|
||||
assert props.context_attributes.get("Precision").float_value == 1
|
||||
|
||||
def test_importing_a_subcontext(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
subcontext = ifc.createIfcGeometricRepresentationSubcontext()
|
||||
subcontext.TargetScale = 0.5
|
||||
subcontext.TargetView = "NOTDEFINED"
|
||||
subcontext.UserDefinedTargetView = "UserDefinedTargetView"
|
||||
subject.set_context(subcontext)
|
||||
subject.import_attributes()
|
||||
props = bpy.context.scene.BIMContextProperties
|
||||
assert props.context_attributes.get("TargetScale").float_value == 0.5
|
||||
assert props.context_attributes.get("TargetView").enum_value == "NOTDEFINED"
|
||||
assert props.context_attributes.get("UserDefinedTargetView").string_value == "UserDefinedTargetView"
|
||||
assert not props.context_attributes.get("Precision")
|
||||
|
||||
def test_importing_twice(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
context = ifc.createIfcGeometricRepresentationContext()
|
||||
context.ContextIdentifier = "ContextIdentifier"
|
||||
subject.set_context(context)
|
||||
subject.import_attributes()
|
||||
context.ContextIdentifier = "ContextIdentifier2"
|
||||
subject.import_attributes()
|
||||
props = bpy.context.scene.BIMContextProperties
|
||||
assert props.context_attributes.get("ContextIdentifier").string_value == "ContextIdentifier2"
|
||||
|
||||
|
||||
class TestClearContext(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
TestSetContext().test_run()
|
||||
subject.clear_context()
|
||||
assert bpy.context.scene.BIMContextProperties.active_context_id == 0
|
||||
|
||||
|
||||
class TestGetContext(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
ifc = ifcopenshell.file()
|
||||
tool.Ifc.set(ifc)
|
||||
context = ifc.createIfcGeometricRepresentationContext()
|
||||
subject.set_context(context)
|
||||
assert subject.get_context() == context
|
||||
|
||||
|
||||
class TestExportAttributes(test.bim.bootstrap.NewFile):
|
||||
def test_exporting_a_context(self):
|
||||
TestImportAttributes().test_importing_a_context()
|
||||
assert subject.export_attributes() == {
|
||||
"ContextIdentifier": "ContextIdentifier",
|
||||
"ContextType": "ContextType",
|
||||
"CoordinateSpaceDimension": 1,
|
||||
"Precision": 1,
|
||||
}
|
||||
|
||||
def test_exporting_a_subcontext(self):
|
||||
TestImportAttributes().test_importing_a_subcontext()
|
||||
assert subject.export_attributes() == {
|
||||
"TargetScale": 0.5,
|
||||
"TargetView": "NOTDEFINED",
|
||||
"UserDefinedTargetView": "UserDefinedTargetView",
|
||||
"ContextIdentifier": None,
|
||||
"ContextType": None,
|
||||
"CoordinateSpaceDimension": None,
|
||||
}
|
||||
@@ -2,30 +2,26 @@ class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {
|
||||
"context": None,
|
||||
"subcontext": None,
|
||||
"context_type": None,
|
||||
"parent": None,
|
||||
"context_identifier": None,
|
||||
"target_view": None,
|
||||
}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
parent = [
|
||||
c
|
||||
for c in self.file.by_type("IfcGeometricRepresentationContext")
|
||||
if c.ContextType == self.settings["context"]
|
||||
]
|
||||
if not parent:
|
||||
self.create_origin()
|
||||
if self.settings["context"] == "Plan":
|
||||
if not self.settings["parent"]:
|
||||
if self.settings["context_type"] == "Plan":
|
||||
self.create_2d_origin()
|
||||
context = self.file.createIfcGeometricRepresentationContext(None, "Plan", 2, 1.0e-05, self.origin)
|
||||
else:
|
||||
context = self.file.createIfcGeometricRepresentationContext(None, "Model", 3, 1.0e-05, self.origin)
|
||||
self.create_3d_origin()
|
||||
context = self.file.createIfcGeometricRepresentationContext(
|
||||
None, self.settings["context_type"], 3, 1.0e-05, self.origin
|
||||
)
|
||||
|
||||
if self.file.schema == "IFC2X3":
|
||||
project = self.file.by_type("IfcProject")[0]
|
||||
else:
|
||||
project = self.file.by_type("IfcContext")[0]
|
||||
project = self.file.by_type("IfcProject")[0]
|
||||
|
||||
if project.RepresentationContexts:
|
||||
contexts = list(project.RepresentationContexts)
|
||||
@@ -34,20 +30,25 @@ class Usecase:
|
||||
contexts.append(context)
|
||||
project.RepresentationContexts = contexts
|
||||
return context
|
||||
parent = parent[0]
|
||||
return self.file.create_entity(
|
||||
"IfcGeometricRepresentationSubContext",
|
||||
**{
|
||||
"ContextIdentifier": self.settings["subcontext"],
|
||||
"ContextType": self.settings["context"],
|
||||
"ParentContext": parent,
|
||||
"ContextIdentifier": self.settings["context_identifier"],
|
||||
"ContextType": self.settings["context_type"],
|
||||
"ParentContext": self.settings["parent"],
|
||||
"TargetView": self.settings["target_view"],
|
||||
}
|
||||
)
|
||||
|
||||
def create_origin(self):
|
||||
def create_3d_origin(self):
|
||||
self.origin = self.file.createIfcAxis2Placement3D(
|
||||
self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)),
|
||||
self.file.createIfcDirection((0.0, 0.0, 1.0)),
|
||||
self.file.createIfcDirection((1.0, 0.0, 0.0)),
|
||||
)
|
||||
|
||||
def create_2d_origin(self):
|
||||
self.origin = self.file.createIfcAxis2Placement2D(
|
||||
self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)),
|
||||
self.file.createIfcDirection((1.0, 0.0, 0.0)),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
class Usecase:
|
||||
def __init__(self, file, **settings):
|
||||
self.file = file
|
||||
self.settings = {"context": None, "attributes": {}}
|
||||
for key, value in settings.items():
|
||||
self.settings[key] = value
|
||||
|
||||
def execute(self):
|
||||
for name, value in self.settings["attributes"].items():
|
||||
setattr(self.settings["context"], name, value)
|
||||
@@ -0,0 +1,59 @@
|
||||
import test.bootstrap
|
||||
import ifcopenshell.api
|
||||
|
||||
|
||||
class TestAddContext(test.bootstrap.IFC4):
|
||||
def test_adding_a_3d_context(self):
|
||||
self.file.createIfcProject()
|
||||
context = ifcopenshell.api.run("context.add_context", self.file, context_type="Model")
|
||||
assert context.ContextType == "Model"
|
||||
assert context.is_a() == "IfcGeometricRepresentationContext"
|
||||
assert context.WorldCoordinateSystem.is_a() == "IfcAxis2Placement3D"
|
||||
assert context.WorldCoordinateSystem.Location.Coordinates == (0, 0, 0)
|
||||
assert context.WorldCoordinateSystem.Axis.DirectionRatios == (0, 0, 1)
|
||||
assert context.WorldCoordinateSystem.RefDirection.DirectionRatios == (1, 0, 0)
|
||||
assert context.CoordinateSpaceDimension == 3
|
||||
|
||||
def test_adding_a_2d_context(self):
|
||||
self.file.createIfcProject()
|
||||
context = ifcopenshell.api.run("context.add_context", self.file, context_type="Plan")
|
||||
assert context.ContextType == "Plan"
|
||||
assert context.is_a() == "IfcGeometricRepresentationContext"
|
||||
assert context.WorldCoordinateSystem.is_a() == "IfcAxis2Placement2D"
|
||||
assert context.WorldCoordinateSystem.Location.Coordinates == (0, 0, 0)
|
||||
assert context.WorldCoordinateSystem.RefDirection.DirectionRatios == (1, 0, 0)
|
||||
assert context.CoordinateSpaceDimension == 2
|
||||
|
||||
def test_defaulting_to_3d_with_an_unknown_context_type(self):
|
||||
self.file.createIfcProject()
|
||||
context = ifcopenshell.api.run("context.add_context", self.file)
|
||||
assert context.ContextType is None
|
||||
assert context.is_a() == "IfcGeometricRepresentationContext"
|
||||
assert context.WorldCoordinateSystem.is_a() == "IfcAxis2Placement3D"
|
||||
assert context.WorldCoordinateSystem.Location.Coordinates == (0, 0, 0)
|
||||
assert context.WorldCoordinateSystem.Axis.DirectionRatios == (0, 0, 1)
|
||||
assert context.WorldCoordinateSystem.RefDirection.DirectionRatios == (1, 0, 0)
|
||||
assert context.CoordinateSpaceDimension == 3
|
||||
|
||||
def test_adding_a_subcontext(self):
|
||||
self.test_adding_a_3d_context()
|
||||
context = self.file.by_type("IfcGeometricRepresentationContext")[0]
|
||||
subcontext = ifcopenshell.api.run("context.add_context", self.file, parent=context, target_view="NOTDEFINED")
|
||||
assert subcontext.is_a("IfcGeometricRepresentationSubContext")
|
||||
assert subcontext.TargetView == "NOTDEFINED"
|
||||
|
||||
def test_adding_a_subcontext_with_an_optional_identifier_specified(self):
|
||||
self.test_adding_a_3d_context()
|
||||
context = self.file.by_type("IfcGeometricRepresentationContext")[0]
|
||||
subcontext = ifcopenshell.api.run(
|
||||
"context.add_context", self.file, parent=context, target_view="NOTDEFINED", context_identifier="Body"
|
||||
)
|
||||
assert subcontext.is_a("IfcGeometricRepresentationSubContext")
|
||||
assert subcontext.TargetView == "NOTDEFINED"
|
||||
assert subcontext.ContextIdentifier == "Body"
|
||||
|
||||
def test_adding_two_contexts(self):
|
||||
self.test_adding_a_3d_context()
|
||||
self.test_adding_a_2d_context()
|
||||
project = self.file.by_type("IfcProject")[0]
|
||||
assert len(project.RepresentationContexts) == 2
|
||||
Reference in New Issue
Block a user