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
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()
+22 -2
View File
@@ -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
+7
View File
@@ -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
+43 -3
View File
@@ -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