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:
Dion Moult
2021-09-30 18:28:50 +10:00
parent 9753ed07a0
commit b86b8c1b5a
19 changed files with 573 additions and 62 deletions
@@ -20,8 +20,11 @@ import bpy
from . import ui, prop, operator from . import ui, prop, operator
classes = ( classes = (
operator.AddSubcontext, operator.AddContext,
operator.RemoveSubcontext, operator.DisableEditingContext,
operator.EditContext,
operator.EnableEditingContext,
operator.RemoveContext,
prop.BIMContextProperties, prop.BIMContextProperties,
ui.BIM_PT_context, 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 import blenderbim.tool as tool
@@ -15,7 +34,13 @@ class ContextData:
results = [] results = []
for context in tool.Ifc.get().by_type("IfcGeometricRepresentationContext", include_subtypes=False): for context in tool.Ifc.get().by_type("IfcGeometricRepresentationContext", include_subtypes=False):
results.append( 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 return results
@@ -29,6 +54,8 @@ class ContextData:
"context_type": subcontext.ContextType, "context_type": subcontext.ContextType,
"context_identifier": subcontext.ContextIdentifier, "context_identifier": subcontext.ContextIdentifier,
"target_view": subcontext.TargetView, "target_view": subcontext.TargetView,
"is_editing": bpy.context.scene.BIMContextProperties.active_context_id == subcontext.id(),
"props": bpy.context.scene.BIMContextProperties.context_attributes,
} }
) )
return results return results
@@ -31,23 +31,58 @@ class Operator:
return {"FINISHED"} return {"FINISHED"}
class AddSubcontext(bpy.types.Operator, Operator): class AddContext(bpy.types.Operator, Operator):
bl_idname = "bim.add_subcontext" bl_idname = "bim.add_context"
bl_label = "Add Subcontext" bl_label = "Add Subcontext"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
context: bpy.props.StringProperty() context_type: bpy.props.StringProperty()
subcontext: bpy.props.StringProperty() context_identifier: bpy.props.StringProperty()
target_view: bpy.props.StringProperty() target_view: bpy.props.StringProperty()
parent: bpy.props.IntProperty()
def _execute(self, context): 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): class RemoveContext(bpy.types.Operator, Operator):
bl_idname = "bim.remove_subcontext" bl_idname = "bim.remove_context"
bl_label = "Remove Context" bl_label = "Remove Context"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
context: bpy.props.IntProperty() context: bpy.props.IntProperty()
def _execute(self, context): def _execute(self, context):
core.remove_context(tool.Ifc, context=tool.Ifc.get().by_id(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 import bpy
from blenderbim.bim.prop import StrProperty, Attribute from blenderbim.bim.prop import StrProperty, Attribute
from blenderbim.bim.module.context.data import ContextData from blenderbim.bim.module.context.data import ContextData
@@ -46,3 +64,5 @@ class BIMContextProperties(PropertyGroup):
], ],
name="Target Views", 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/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy import bpy
import blenderbim.bim.helper
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.module.context.data import ContextData 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 = self.layout.row(align=True)
row.prop(props, "contexts", text="") row.prop(props, "contexts", text="")
row.prop(props, "subcontexts", text="") op = row.operator("bim.add_context", icon="ADD", text="")
row.prop(props, "target_views", text="") op.context_type = props.contexts
op = row.operator("bim.add_subcontext", icon="ADD", text="") op.context_identifier = ""
op.context = props.contexts op.target_view = ""
op.subcontext = props.subcontexts op.parent = 0
op.target_view = props.target_views
for context in ContextData.data["contexts"]: for ifc_context in ContextData.data["contexts"]:
box = self.layout.box() box = self.layout.box()
row = box.row(align=True)
row.label(text=context["context_type"]) if ifc_context["is_editing"]:
row.operator("bim.remove_subcontext", icon="X", text="").context = context["id"]
for subcontext in context["subcontexts"]:
row = box.row(align=True) row = box.row(align=True)
row.label(text=subcontext["context_type"]) row.operator("bim.edit_context", icon="CHECKMARK")
row.label(text=subcontext["context_identifier"]) row.operator("bim.disable_editing_context", icon="CANCEL", text="")
row.label(text=subcontext["target_view"]) blenderbim.bim.helper.draw_attributes(ifc_context["props"], box)
row.operator("bim.remove_subcontext", icon="X", text="").context = subcontext["id"] 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() organisation: bpy.props.IntProperty()
def _execute(self, context): def _execute(self, context):
core.enable_editing_organisation( core.enable_editing_organisation(tool.OrganisationEditor, organisation=tool.Ifc.get().by_id(self.organisation))
tool.OrganisationEditor, organisation=tool.Ifc.get().by_id(self.organisation)
)
class DisableEditingOrganisation(bpy.types.Operator, Operator): class DisableEditingOrganisation(bpy.types.Operator, Operator):
@@ -26,6 +26,8 @@ import ifcopenshell.api
import ifcopenshell.util.selector import ifcopenshell.util.selector
import ifcopenshell.util.representation import ifcopenshell.util.representation
import blenderbim.bim.handler 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.ifc import IfcStore
from blenderbim.bim import import_ifc 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_class(obj=project.name, ifc_class="IfcProject")
bpy.ops.bim.assign_unit() 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") # TODO: refactor
bpy.ops.bim.add_subcontext(context="Model", subcontext="Box", target_view="MODEL_VIEW") model = context_core.add_context(
bpy.ops.bim.add_subcontext(context="Plan") tool.Ifc, context_type="Model", context_identifier="", target_view="", parent=0
bpy.ops.bim.add_subcontext(context="Plan", subcontext="Annotation", target_view="PLAN_VIEW") )
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( context.scene.BIMProperties.contexts = str(
ifcopenshell.util.representation.get_context(self.file, "Model", "Body", "MODEL_VIEW").id() ifcopenshell.util.representation.get_context(self.file, "Model", "Body", "MODEL_VIEW").id()
+22 -2
View File
@@ -17,9 +17,29 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
def add_context(ifc, context=None, subcontext=None, target_view=None): def add_context(ifc, context_type=None, context_identifier=None, target_view=None, parent=None):
return ifc.run("context.add_context", context=context, subcontext=subcontext, target_view=target_view) 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): def remove_context(ifc, context=None):
ifc.run("context.remove_context", context=context) 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.role_editor import RoleEditor
from blenderbim.core.tool.address_editor import AddressEditor from blenderbim.core.tool.address_editor import AddressEditor
from blenderbim.core.tool.organisation_editor import OrganisationEditor 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.role_editor import RoleEditor
from blenderbim.tool.address_editor import AddressEditor from blenderbim.tool.address_editor import AddressEditor
from blenderbim.tool.organisation_editor import OrganisationEditor 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 Feature: Context
Manages geometric representation contexts and subcontexts Manages geometric representation contexts and subcontexts
Scenario: Add subcontext Scenario: Add context
Given an empty IFC project 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 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 Given an empty IFC project
When the variable "context" is "IfcStore.get_file().by_type('IfcGeometricRepresentationContext')[0].id()" 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 Then nothing happens
+7
View File
@@ -63,6 +63,13 @@ def organisation_editor():
prophet.verify() prophet.verify()
@pytest.fixture
def context_editor():
prophet = Prophecy(blenderbim.core.tool.ContextEditor)
yield prophet
prophet.verify()
class Prophecy: class Prophecy:
def __init__(self, cls): def __init__(self, cls):
self.subject = cls self.subject = cls
+43 -3
View File
@@ -17,18 +17,58 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import blenderbim.core.context as subject import blenderbim.core.context as subject
from test.core.bootstrap import ifc from test.core.bootstrap import ifc, context_editor
class TestAddContext: class TestAddContext:
def test_adding_a_context(self, ifc): def test_adding_a_context(self, ifc):
ifc.run( 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") ).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: class TestRemoveContext:
def test_removing_a_context(self, ifc): def test_removing_a_context(self, ifc):
ifc.run("context.remove_context", context="context").should_be_called() ifc.run("context.remove_context", context="context").should_be_called()
subject.remove_context(ifc, context="context") 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): def __init__(self, file, **settings):
self.file = file self.file = file
self.settings = { self.settings = {
"context": None, "context_type": None,
"subcontext": None, "parent": None,
"context_identifier": None,
"target_view": None, "target_view": None,
} }
for key, value in settings.items(): for key, value in settings.items():
self.settings[key] = value self.settings[key] = value
def execute(self): def execute(self):
parent = [ if not self.settings["parent"]:
c if self.settings["context_type"] == "Plan":
for c in self.file.by_type("IfcGeometricRepresentationContext") self.create_2d_origin()
if c.ContextType == self.settings["context"]
]
if not parent:
self.create_origin()
if self.settings["context"] == "Plan":
context = self.file.createIfcGeometricRepresentationContext(None, "Plan", 2, 1.0e-05, self.origin) context = self.file.createIfcGeometricRepresentationContext(None, "Plan", 2, 1.0e-05, self.origin)
else: 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]
project = self.file.by_type("IfcProject")[0]
else:
project = self.file.by_type("IfcContext")[0]
if project.RepresentationContexts: if project.RepresentationContexts:
contexts = list(project.RepresentationContexts) contexts = list(project.RepresentationContexts)
@@ -34,20 +30,25 @@ class Usecase:
contexts.append(context) contexts.append(context)
project.RepresentationContexts = contexts project.RepresentationContexts = contexts
return context return context
parent = parent[0]
return self.file.create_entity( return self.file.create_entity(
"IfcGeometricRepresentationSubContext", "IfcGeometricRepresentationSubContext",
**{ **{
"ContextIdentifier": self.settings["subcontext"], "ContextIdentifier": self.settings["context_identifier"],
"ContextType": self.settings["context"], "ContextType": self.settings["context_type"],
"ParentContext": parent, "ParentContext": self.settings["parent"],
"TargetView": self.settings["target_view"], "TargetView": self.settings["target_view"],
} }
) )
def create_origin(self): def create_3d_origin(self):
self.origin = self.file.createIfcAxis2Placement3D( self.origin = self.file.createIfcAxis2Placement3D(
self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)), self.file.createIfcCartesianPoint((0.0, 0.0, 0.0)),
self.file.createIfcDirection((0.0, 0.0, 1.0)), self.file.createIfcDirection((0.0, 0.0, 1.0)),
self.file.createIfcDirection((1.0, 0.0, 0.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