mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Rebuild text annotations to have leaders in the same object and use text literals. See #1153.
This commit is contained in:
@@ -35,7 +35,6 @@ classes = (
|
|||||||
operator.ResizeText,
|
operator.ResizeText,
|
||||||
operator.AddVariable,
|
operator.AddVariable,
|
||||||
operator.RemoveVariable,
|
operator.RemoveVariable,
|
||||||
operator.PropagateTextData,
|
|
||||||
operator.RemoveDrawing,
|
operator.RemoveDrawing,
|
||||||
operator.AddDrawingStyle,
|
operator.AddDrawingStyle,
|
||||||
operator.RemoveDrawingStyle,
|
operator.RemoveDrawingStyle,
|
||||||
@@ -54,6 +53,9 @@ classes = (
|
|||||||
operator.CleanWireframes,
|
operator.CleanWireframes,
|
||||||
operator.CopyGrid,
|
operator.CopyGrid,
|
||||||
operator.AddSectionsAnnotations,
|
operator.AddSectionsAnnotations,
|
||||||
|
operator.EditText,
|
||||||
|
operator.DisableEditingText,
|
||||||
|
operator.EnableEditingText,
|
||||||
prop.Variable,
|
prop.Variable,
|
||||||
prop.Drawing,
|
prop.Drawing,
|
||||||
prop.Schedule,
|
prop.Schedule,
|
||||||
@@ -81,6 +83,7 @@ classes = (
|
|||||||
def register():
|
def register():
|
||||||
bpy.types.Scene.DocProperties = bpy.props.PointerProperty(type=prop.DocProperties)
|
bpy.types.Scene.DocProperties = bpy.props.PointerProperty(type=prop.DocProperties)
|
||||||
bpy.types.Camera.BIMCameraProperties = bpy.props.PointerProperty(type=prop.BIMCameraProperties)
|
bpy.types.Camera.BIMCameraProperties = bpy.props.PointerProperty(type=prop.BIMCameraProperties)
|
||||||
|
bpy.types.Object.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties)
|
||||||
bpy.types.TextCurve.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties)
|
bpy.types.TextCurve.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties)
|
||||||
bpy.app.handlers.load_post.append(handler.toggleDecorationsOnLoad)
|
bpy.app.handlers.load_post.append(handler.toggleDecorationsOnLoad)
|
||||||
bpy.app.handlers.depsgraph_update_pre.append(handler.depsgraph_update_pre_handler)
|
bpy.app.handlers.depsgraph_update_pre.append(handler.depsgraph_update_pre_handler)
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# 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.util.representation
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
|
||||||
|
|
||||||
|
def refresh():
|
||||||
|
TextData.is_loaded = False
|
||||||
|
|
||||||
|
|
||||||
|
class TextData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.data = {"attributes": cls.attributes()}
|
||||||
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def attributes(cls):
|
||||||
|
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||||
|
if not element or not element.is_a("IfcAnnotation") or element.ObjectType not in ["TEXT", "TEXT_LEADER"]:
|
||||||
|
return []
|
||||||
|
rep = ifcopenshell.util.representation.get_representation(element, "Plan", "Annotation")
|
||||||
|
text_literal = [i for i in rep.Items if i.is_a("IfcTextLiteral")][0]
|
||||||
|
return [
|
||||||
|
{"name": "Literal", "value": text_literal.Literal},
|
||||||
|
{"name": "BoxAlignment", "value": text_literal.BoxAlignment},
|
||||||
|
]
|
||||||
@@ -1228,6 +1228,90 @@ class SectionViewDecorator(LevelDecorator):
|
|||||||
self.draw_lines(context, obj, verts, [(0, 1)])
|
self.draw_lines(context, obj, verts, [(0, 1)])
|
||||||
|
|
||||||
|
|
||||||
|
class TextDecorator(BaseDecorator):
|
||||||
|
"""Decorator for text objects
|
||||||
|
- draws the text next to the origin
|
||||||
|
"""
|
||||||
|
|
||||||
|
objecttype = "TEXT"
|
||||||
|
|
||||||
|
DEF_GLSL = (
|
||||||
|
BaseDecorator.DEF_GLSL
|
||||||
|
+ """
|
||||||
|
#define ARROW_ANGLE PI / 12.0
|
||||||
|
#define ARROW_SIZE 16.0
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
GEOM_GLSL = """
|
||||||
|
uniform vec2 winsize;
|
||||||
|
uniform float viewportDrawingScale;
|
||||||
|
|
||||||
|
layout(lines) in;
|
||||||
|
layout(line_strip, max_vertices=MAX_POINTS) out;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 clip2win = matCLIP2WIN();
|
||||||
|
vec4 win2clip = matWIN2CLIP();
|
||||||
|
|
||||||
|
vec4 p0 = gl_in[0].gl_Position, p1 = gl_in[1].gl_Position;
|
||||||
|
|
||||||
|
vec4 p0w = CLIP2WIN(p0), p1w = CLIP2WIN(p1);
|
||||||
|
vec4 edge = p1w - p0w, dir = normalize(edge);
|
||||||
|
|
||||||
|
vec4 p;
|
||||||
|
|
||||||
|
vec4 head[3];
|
||||||
|
arrow_head(dir, viewportDrawingScale * ARROW_SIZE, ARROW_ANGLE, head);
|
||||||
|
|
||||||
|
// start edge arrow
|
||||||
|
gl_Position = p0;
|
||||||
|
EmitVertex();
|
||||||
|
p = p0w + head[1];
|
||||||
|
gl_Position = WIN2CLIP(p);
|
||||||
|
EmitVertex();
|
||||||
|
p = p0w + head[2];
|
||||||
|
gl_Position = WIN2CLIP(p);
|
||||||
|
EmitVertex();
|
||||||
|
gl_Position = p0;
|
||||||
|
EmitVertex();
|
||||||
|
EndPrimitive();
|
||||||
|
|
||||||
|
// end edge arrow
|
||||||
|
gl_Position = p1;
|
||||||
|
EmitVertex();
|
||||||
|
p = p1w - head[1];
|
||||||
|
gl_Position = WIN2CLIP(p);
|
||||||
|
EmitVertex();
|
||||||
|
p = p1w - head[2];
|
||||||
|
gl_Position = WIN2CLIP(p);
|
||||||
|
EmitVertex();
|
||||||
|
gl_Position = p1;
|
||||||
|
EmitVertex();
|
||||||
|
EndPrimitive();
|
||||||
|
|
||||||
|
// stem, with gaps for arrows
|
||||||
|
p = p0w + head[0];
|
||||||
|
gl_Position = WIN2CLIP(p);
|
||||||
|
EmitVertex();
|
||||||
|
p = p1w - head[0];
|
||||||
|
gl_Position = WIN2CLIP(p);
|
||||||
|
EmitVertex();
|
||||||
|
EndPrimitive();
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def decorate(self, context, obj):
|
||||||
|
self.draw_labels(context, obj)
|
||||||
|
|
||||||
|
def draw_labels(self, context, obj):
|
||||||
|
region = context.region
|
||||||
|
region3d = context.region_data
|
||||||
|
dir = Vector((1, 0))
|
||||||
|
pos = location_3d_to_region_2d(region, region3d, obj.matrix_world.translation)
|
||||||
|
self.draw_label(context, obj.BIMTextProperties.value, pos, dir, gap=0, center=False, vcenter=False)
|
||||||
|
|
||||||
|
|
||||||
class DecorationsHandler:
|
class DecorationsHandler:
|
||||||
decorators_classes = [
|
decorators_classes = [
|
||||||
DimensionDecorator,
|
DimensionDecorator,
|
||||||
@@ -1241,6 +1325,7 @@ class DecorationsHandler:
|
|||||||
StairDecorator,
|
StairDecorator,
|
||||||
BreakDecorator,
|
BreakDecorator,
|
||||||
SectionViewDecorator,
|
SectionViewDecorator,
|
||||||
|
TextDecorator,
|
||||||
]
|
]
|
||||||
|
|
||||||
installed = None
|
installed = None
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import ifcopenshell.util.selector
|
|||||||
import ifcopenshell.util.representation
|
import ifcopenshell.util.representation
|
||||||
import blenderbim.bim.schema
|
import blenderbim.bim.schema
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
|
import blenderbim.core.drawing as core
|
||||||
import blenderbim.bim.module.drawing.svgwriter as svgwriter
|
import blenderbim.bim.module.drawing.svgwriter as svgwriter
|
||||||
import blenderbim.bim.module.drawing.annotation as annotation
|
import blenderbim.bim.module.drawing.annotation as annotation
|
||||||
import blenderbim.bim.module.drawing.sheeter as sheeter
|
import blenderbim.bim.module.drawing.sheeter as sheeter
|
||||||
@@ -57,6 +58,13 @@ def open_with_user_command(user_command, path):
|
|||||||
webbrowser.open("file://" + path)
|
webbrowser.open("file://" + path)
|
||||||
|
|
||||||
|
|
||||||
|
class Operator:
|
||||||
|
def execute(self, context):
|
||||||
|
IfcStore.execute_ifc_operator(self, context)
|
||||||
|
blenderbim.bim.handler.refresh_ui_data()
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class AddDrawing(bpy.types.Operator):
|
class AddDrawing(bpy.types.Operator):
|
||||||
bl_idname = "bim.add_drawing"
|
bl_idname = "bim.add_drawing"
|
||||||
bl_label = "Add Drawing"
|
bl_label = "Add Drawing"
|
||||||
@@ -79,7 +87,7 @@ class AddDrawing(bpy.types.Operator):
|
|||||||
view_collection = bpy.data.collections.new("IfcGroup/" + new.name)
|
view_collection = bpy.data.collections.new("IfcGroup/" + new.name)
|
||||||
views_collection.children.link(view_collection)
|
views_collection.children.link(view_collection)
|
||||||
camera = bpy.data.objects.new(new.name, bpy.data.cameras.new(new.name))
|
camera = bpy.data.objects.new(new.name, bpy.data.cameras.new(new.name))
|
||||||
camera.location = (0, 0, 1.7) # The view shall be 1.7m above the origin
|
camera.location = (0, 0, 1.5) # The view shall be 1.5m above the origin
|
||||||
camera.data.type = "ORTHO"
|
camera.data.type = "ORTHO"
|
||||||
camera.data.ortho_scale = 50 # The default of 6m is too small
|
camera.data.ortho_scale = 50 # The default of 6m is too small
|
||||||
camera.data.clip_end = 10 # A slightly more reasonable default
|
camera.data.clip_end = 10 # A slightly more reasonable default
|
||||||
@@ -573,28 +581,45 @@ class AddAnnotation(bpy.types.Operator):
|
|||||||
)
|
)
|
||||||
if not subcontext:
|
if not subcontext:
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
if self.data_type == "text":
|
# TODO: reimplement bulk smart tagging
|
||||||
if context.selected_objects:
|
# if self.data_type == "text":
|
||||||
for selected_object in context.selected_objects:
|
# if context.selected_objects:
|
||||||
obj = annotation.Annotator.add_text(context, related_element=selected_object)
|
# for selected_object in context.selected_objects:
|
||||||
else:
|
# obj = annotation.Annotator.add_text(context, related_element=selected_object)
|
||||||
obj = annotation.Annotator.add_text(context)
|
# else:
|
||||||
else:
|
# obj = annotation.Annotator.add_text(context)
|
||||||
obj = annotation.Annotator.get_annotation_obj(self.obj_name, self.data_type, context)
|
# else:
|
||||||
if self.obj_name == "Break":
|
obj = annotation.Annotator.get_annotation_obj(self.object_type, self.data_type, context)
|
||||||
obj = annotation.Annotator.add_plane_to_annotation(obj, context)
|
if self.object_type == "BREAKLINE":
|
||||||
else:
|
obj = annotation.Annotator.add_plane_to_annotation(obj, context)
|
||||||
obj = annotation.Annotator.add_line_to_annotation(obj, context)
|
elif self.object_type != "TEXT":
|
||||||
|
obj = annotation.Annotator.add_line_to_annotation(obj, context)
|
||||||
|
|
||||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||||
bpy.ops.bim.assign_class(obj=obj.name, ifc_class="IfcAnnotation", context_id=subcontext.id())
|
ifc_representation_class = ""
|
||||||
|
if self.object_type == "TEXT":
|
||||||
|
ifc_representation_class = "IfcTextLiteral"
|
||||||
|
elif self.object_type == "TEXT_LEADER":
|
||||||
|
ifc_representation_class = "IfcGeometricCurveSet/IfcTextLiteral"
|
||||||
|
bpy.ops.bim.assign_class(
|
||||||
|
obj=obj.name,
|
||||||
|
ifc_class="IfcAnnotation",
|
||||||
|
context_id=subcontext.id(),
|
||||||
|
ifc_representation_class=ifc_representation_class,
|
||||||
|
)
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
element.ObjectType = self.object_type
|
||||||
|
camera = tool.Ifc.get_entity(context.scene.camera)
|
||||||
|
group = [r for r in camera.HasAssignments if r.is_a("IfcRelAssignsToGroup")][0].RelatingGroup
|
||||||
|
bpy.ops.bim.assign_group(product=obj.name, group=group.id())
|
||||||
else:
|
else:
|
||||||
bpy.ops.bim.update_representation(obj=obj.name)
|
bpy.ops.bim.update_representation(obj=obj.name)
|
||||||
|
|
||||||
bpy.ops.object.select_all(action="DESELECT")
|
bpy.ops.object.select_all(action="DESELECT")
|
||||||
context.view_layer.objects.active = obj
|
context.view_layer.objects.active = obj
|
||||||
obj.select_set(True)
|
obj.select_set(True)
|
||||||
bpy.ops.object.mode_set(mode="EDIT")
|
if obj.data:
|
||||||
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -888,29 +913,6 @@ class RemoveVariable(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class PropagateTextData(bpy.types.Operator):
|
|
||||||
bl_idname = "bim.propagate_text_data"
|
|
||||||
bl_label = "Propagate Text Data"
|
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
source = context.active_object
|
|
||||||
for obj in context.selected_objects:
|
|
||||||
if obj == source:
|
|
||||||
continue
|
|
||||||
obj.data.body = source.data.body
|
|
||||||
obj.data.align_x = source.data.align_x
|
|
||||||
obj.data.align_y = source.data.align_y
|
|
||||||
obj.data.BIMTextProperties.font_size = source.data.BIMTextProperties.font_size
|
|
||||||
obj.data.BIMTextProperties.symbol = source.data.BIMTextProperties.symbol
|
|
||||||
obj.data.BIMTextProperties.variables.clear()
|
|
||||||
for variable in source.data.BIMTextProperties.variables:
|
|
||||||
new_variable = obj.data.BIMTextProperties.variables.add()
|
|
||||||
new_variable.name = variable.name
|
|
||||||
new_variable.prop_key = variable.prop_key
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveDrawing(bpy.types.Operator):
|
class RemoveDrawing(bpy.types.Operator):
|
||||||
bl_idname = "bim.remove_drawing"
|
bl_idname = "bim.remove_drawing"
|
||||||
bl_label = "Remove Drawing"
|
bl_label = "Remove Drawing"
|
||||||
@@ -1380,3 +1382,30 @@ class AddSectionsAnnotations(bpy.types.Operator):
|
|||||||
view_coll.objects.link(obj)
|
view_coll.objects.link(obj)
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class EditText(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.edit_text"
|
||||||
|
bl_label = "Edit Text"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.edit_text(tool.Ifc, tool.Drawing, obj=context.active_object)
|
||||||
|
|
||||||
|
|
||||||
|
class EnableEditingText(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.enable_editing_text"
|
||||||
|
bl_label = "Enable Editing Text"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.enable_editing_text(tool.Drawing, obj=context.active_object)
|
||||||
|
|
||||||
|
|
||||||
|
class DisableEditingText(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.disable_editing_text"
|
||||||
|
bl_label = "Disable Editing Text"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.disable_editing_text(tool.Drawing, obj=context.active_object)
|
||||||
|
|||||||
@@ -169,6 +169,10 @@ def refreshTitleblocks(self, context):
|
|||||||
def toggleDecorations(self, context):
|
def toggleDecorations(self, context):
|
||||||
toggle = self.should_draw_decorations
|
toggle = self.should_draw_decorations
|
||||||
if toggle:
|
if toggle:
|
||||||
|
# TODO: design a proper text variable templating renderer
|
||||||
|
collection = context.scene.camera.users_collection[0]
|
||||||
|
for obj in collection.objects:
|
||||||
|
tool.Drawing.update_text_value(obj)
|
||||||
decoration.DecorationsHandler.install(context)
|
decoration.DecorationsHandler.install(context)
|
||||||
else:
|
else:
|
||||||
decoration.DecorationsHandler.uninstall()
|
decoration.DecorationsHandler.uninstall()
|
||||||
@@ -353,6 +357,9 @@ class BIMCameraProperties(PropertyGroup):
|
|||||||
|
|
||||||
|
|
||||||
class BIMTextProperties(PropertyGroup):
|
class BIMTextProperties(PropertyGroup):
|
||||||
|
is_editing: BoolProperty(name="Is Editing", default=False)
|
||||||
|
attributes: CollectionProperty(name="Attributes", type=Attribute)
|
||||||
|
value: StringProperty(name="Value", default="TEXT")
|
||||||
font_size: EnumProperty(
|
font_size: EnumProperty(
|
||||||
items=[
|
items=[
|
||||||
("1.8", "1.8 - Small", ""),
|
("1.8", "1.8 - Small", ""),
|
||||||
@@ -361,6 +368,7 @@ class BIMTextProperties(PropertyGroup):
|
|||||||
("5.0", "5.0 - Header", ""),
|
("5.0", "5.0 - Header", ""),
|
||||||
("7.0", "7.0 - Title", ""),
|
("7.0", "7.0 - Title", ""),
|
||||||
],
|
],
|
||||||
|
default="2.5",
|
||||||
update=refreshFontSize,
|
update=refreshFontSize,
|
||||||
name="Font Size",
|
name="Font Size",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import pystache
|
|||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
import svgwrite
|
import svgwrite
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.representation
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
import blenderbim.bim.module.drawing.helper as helper
|
import blenderbim.bim.module.drawing.helper as helper
|
||||||
import blenderbim.bim.module.drawing.annotation as annotation
|
import blenderbim.bim.module.drawing.annotation as annotation
|
||||||
@@ -208,8 +209,7 @@ class SvgWriter:
|
|||||||
for obj_data in self.annotations.get("solid_objs", []):
|
for obj_data in self.annotations.get("solid_objs", []):
|
||||||
self.draw_line_annotation(obj_data, ["solid"])
|
self.draw_line_annotation(obj_data, ["solid"])
|
||||||
|
|
||||||
if self.annotations.get("leader_obj"):
|
self.draw_leader_annotations()
|
||||||
self.draw_line_annotation(self.annotations["leader_obj"], ["leader"])
|
|
||||||
|
|
||||||
if self.annotations.get("plan_level_obj"):
|
if self.annotations.get("plan_level_obj"):
|
||||||
matrix_world = self.annotations["plan_level_obj"].matrix_world
|
matrix_world = self.annotations["plan_level_obj"].matrix_world
|
||||||
@@ -456,72 +456,99 @@ class SvgWriter:
|
|||||||
self.svg.line(start=tuple(start * self.scale), end=tuple(end * self.scale), class_=" ".join(classes))
|
self.svg.line(start=tuple(start * self.scale), end=tuple(end * self.scale), class_=" ".join(classes))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def draw_leader_annotations(self):
|
||||||
|
for obj in self.annotations.get("leader_objs", []):
|
||||||
|
self.draw_line_annotation((obj, obj.data), ["leader"])
|
||||||
|
spline = obj.data.splines[0]
|
||||||
|
spline_points = spline.bezier_points if spline.bezier_points else spline.points
|
||||||
|
if spline_points:
|
||||||
|
position = obj.matrix_world @ spline_points[0].co.xyz
|
||||||
|
else:
|
||||||
|
position = Vector((0, 0, 0))
|
||||||
|
self.draw_text_annotation(obj, position)
|
||||||
|
|
||||||
def draw_text_annotations(self):
|
def draw_text_annotations(self):
|
||||||
|
for text_obj in self.annotations.get("text_objs", []):
|
||||||
|
self.draw_text_annotation(text_obj, text_obj.location)
|
||||||
|
|
||||||
|
def draw_text_annotation(self, text_obj, position):
|
||||||
x_offset = self.raw_width / 2
|
x_offset = self.raw_width / 2
|
||||||
y_offset = self.raw_height / 2
|
y_offset = self.raw_height / 2
|
||||||
|
element = tool.Ifc.get_entity(text_obj)
|
||||||
|
rep = ifcopenshell.util.representation.get_representation(element, "Plan", "Annotation")
|
||||||
|
text_literal = [i for i in rep.Items if i.is_a("IfcTextLiteral")][0]
|
||||||
|
|
||||||
for text_obj in self.annotations.get("text_objs", []):
|
text_position = self.project_point_onto_camera(position)
|
||||||
text_position = self.project_point_onto_camera(text_obj.location)
|
text_position = Vector(((x_offset + text_position.x), (y_offset - text_position.y)))
|
||||||
text_position = Vector(((x_offset + text_position.x), (y_offset - text_position.y)))
|
|
||||||
|
|
||||||
local_x_axis = text_obj.matrix_world.to_quaternion() @ Vector((1, 0, 0))
|
local_x_axis = text_obj.matrix_world.to_quaternion() @ Vector((1, 0, 0))
|
||||||
projected_x_axis = self.project_point_onto_camera(text_obj.location + local_x_axis)
|
projected_x_axis = self.project_point_onto_camera(position + local_x_axis)
|
||||||
angle = math.degrees(
|
angle = math.degrees(
|
||||||
(Vector((x_offset + projected_x_axis.x, y_offset - projected_x_axis.y)) - text_position).angle_signed(
|
(Vector((x_offset + projected_x_axis.x, y_offset - projected_x_axis.y)) - text_position).angle_signed(
|
||||||
Vector((1, 0))
|
Vector((1, 0))
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
transform = "rotate({}, {}, {})".format(
|
||||||
|
angle,
|
||||||
|
(text_position * self.scale)[0],
|
||||||
|
(text_position * self.scale)[1],
|
||||||
|
)
|
||||||
|
|
||||||
|
if text_obj.BIMTextProperties.symbol != "None":
|
||||||
|
self.svg.add(
|
||||||
|
self.svg.use("#{}".format(text_obj.BIMTextProperties.symbol), insert=tuple(text_position * self.scale))
|
||||||
)
|
)
|
||||||
|
|
||||||
transform = "rotate({}, {}, {})".format(
|
if text_literal.BoxAlignment == "top-left":
|
||||||
angle,
|
alignment_baseline = "hanging"
|
||||||
(text_position * self.scale)[0],
|
text_anchor = "start"
|
||||||
(text_position * self.scale)[1],
|
elif text_literal.BoxAlignment == "top-middle":
|
||||||
|
alignment_baseline = "hanging"
|
||||||
|
text_anchor = "middle"
|
||||||
|
elif text_literal.BoxAlignment == "top-right":
|
||||||
|
alignment_baseline = "hanging"
|
||||||
|
text_anchor = "end"
|
||||||
|
elif text_literal.BoxAlignment == "middle-left":
|
||||||
|
alignment_baseline = "middle"
|
||||||
|
text_anchor = "start"
|
||||||
|
elif text_literal.BoxAlignment == "center":
|
||||||
|
alignment_baseline = "middle"
|
||||||
|
text_anchor = "middle"
|
||||||
|
elif text_literal.BoxAlignment == "middle-right":
|
||||||
|
alignment_baseline = "middle"
|
||||||
|
text_anchor = "end"
|
||||||
|
elif text_literal.BoxAlignment == "bottom-left":
|
||||||
|
alignment_baseline = "baseline"
|
||||||
|
text_anchor = "start"
|
||||||
|
elif text_literal.BoxAlignment == "bottom-middle":
|
||||||
|
alignment_baseline = "baseline"
|
||||||
|
text_anchor = "middle"
|
||||||
|
elif text_literal.BoxAlignment == "bottom-right":
|
||||||
|
alignment_baseline = "baseline"
|
||||||
|
text_anchor = "end"
|
||||||
|
|
||||||
|
text_body = text_literal.Literal
|
||||||
|
if text_obj.name in self.annotations.get("template_variables", {}):
|
||||||
|
text_body = pystache.render(text_body, self.annotations["template_variables"][text_obj.name])
|
||||||
|
|
||||||
|
for line_number, text_line in enumerate(text_body.split("\n")):
|
||||||
|
self.svg.add(
|
||||||
|
self.svg.text(
|
||||||
|
text_line,
|
||||||
|
insert=tuple((text_position * self.scale) + Vector((0, 3.5 * line_number))),
|
||||||
|
class_=" ".join(self.get_attribute_classes(text_obj)),
|
||||||
|
**{
|
||||||
|
"font-size": annotation.Annotator.get_svg_text_size(text_obj.BIMTextProperties.font_size),
|
||||||
|
"font-family": "OpenGost Type B TT",
|
||||||
|
"text-anchor": text_anchor,
|
||||||
|
"alignment-baseline": alignment_baseline,
|
||||||
|
"dominant-baseline": alignment_baseline,
|
||||||
|
"transform": transform,
|
||||||
|
},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if text_obj.data.BIMTextProperties.symbol != "None":
|
|
||||||
self.svg.add(
|
|
||||||
self.svg.use(
|
|
||||||
"#{}".format(text_obj.data.BIMTextProperties.symbol), insert=tuple(text_position * self.scale)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if text_obj.data.align_x == "CENTER":
|
|
||||||
text_anchor = "middle"
|
|
||||||
elif text_obj.data.align_x == "RIGHT":
|
|
||||||
text_anchor = "end"
|
|
||||||
else:
|
|
||||||
text_anchor = "start"
|
|
||||||
|
|
||||||
if text_obj.data.align_y == "CENTER":
|
|
||||||
alignment_baseline = "middle"
|
|
||||||
elif text_obj.data.align_y == "TOP":
|
|
||||||
alignment_baseline = "hanging"
|
|
||||||
else:
|
|
||||||
alignment_baseline = "baseline"
|
|
||||||
|
|
||||||
text_body = text_obj.data.body
|
|
||||||
if text_obj.name in self.annotations.get("template_variables", {}):
|
|
||||||
text_body = pystache.render(text_body, self.annotations["template_variables"][text_obj.name])
|
|
||||||
|
|
||||||
for line_number, text_line in enumerate(text_body.split("\n")):
|
|
||||||
self.svg.add(
|
|
||||||
self.svg.text(
|
|
||||||
text_line,
|
|
||||||
insert=tuple((text_position * self.scale) + Vector((0, 3.5 * line_number))),
|
|
||||||
class_=" ".join(self.get_attribute_classes(text_obj)),
|
|
||||||
**{
|
|
||||||
"font-size": annotation.Annotator.get_svg_text_size(
|
|
||||||
text_obj.data.BIMTextProperties.font_size
|
|
||||||
),
|
|
||||||
"font-family": "OpenGost Type B TT",
|
|
||||||
"text-anchor": text_anchor,
|
|
||||||
"alignment-baseline": alignment_baseline,
|
|
||||||
"dominant-baseline": alignment_baseline,
|
|
||||||
"transform": transform,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def draw_break_annotations(self, break_obj):
|
def draw_break_annotations(self, break_obj):
|
||||||
x_offset = self.raw_width / 2
|
x_offset = self.raw_width / 2
|
||||||
y_offset = self.raw_height / 2
|
y_offset = self.raw_height / 2
|
||||||
|
|||||||
@@ -17,7 +17,10 @@
|
|||||||
# 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
|
||||||
from bpy.types import Panel
|
from bpy.types import Panel
|
||||||
|
from blenderbim.bim.module.drawing.data import TextData
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_camera(Panel):
|
class BIM_PT_camera(Panel):
|
||||||
@@ -233,39 +236,57 @@ class BIM_PT_sheets(Panel):
|
|||||||
|
|
||||||
|
|
||||||
class BIM_PT_text(Panel):
|
class BIM_PT_text(Panel):
|
||||||
bl_label = "Text Paper Space"
|
bl_label = "IFC Text"
|
||||||
bl_idname = "BIM_PT_text"
|
bl_idname = "BIM_PT_text"
|
||||||
bl_space_type = "PROPERTIES"
|
bl_space_type = "PROPERTIES"
|
||||||
bl_region_type = "WINDOW"
|
bl_region_type = "WINDOW"
|
||||||
bl_context = "data"
|
bl_context = "object"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
return type(context.curve) is bpy.types.TextCurve
|
if not tool.Ifc.get() or not context.active_object:
|
||||||
|
return
|
||||||
|
element = tool.Ifc.get_entity(context.active_object)
|
||||||
|
if not element:
|
||||||
|
return
|
||||||
|
return element.is_a("IfcAnnotation") and element.ObjectType in ["TEXT", "TEXT_LEADER"]
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
if not TextData.is_loaded:
|
||||||
layout.use_property_split = True
|
TextData.load()
|
||||||
props = context.active_object.data.BIMTextProperties
|
|
||||||
|
|
||||||
row = layout.row()
|
self.layout.use_property_split = True
|
||||||
row.operator("bim.propagate_text_data")
|
props = context.active_object.BIMTextProperties
|
||||||
|
|
||||||
row = layout.row()
|
if props.is_editing:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.operator("bim.edit_text", icon="CHECKMARK")
|
||||||
|
row.operator("bim.disable_editing_text", icon="CANCEL", text="")
|
||||||
|
blenderbim.bim.helper.draw_attributes(props.attributes, self.layout)
|
||||||
|
else:
|
||||||
|
row = self.layout.row()
|
||||||
|
row.operator("bim.enable_editing_text", icon="GREASEPENCIL")
|
||||||
|
|
||||||
|
for attribute in TextData.data["attributes"]:
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.label(text=attribute["name"])
|
||||||
|
row.label(text=attribute["value"])
|
||||||
|
|
||||||
|
row = self.layout.row()
|
||||||
row.prop(props, "font_size")
|
row.prop(props, "font_size")
|
||||||
row = layout.row()
|
row = self.layout.row()
|
||||||
row.prop(props, "symbol")
|
row.prop(props, "symbol")
|
||||||
row = layout.row()
|
row = self.layout.row()
|
||||||
row.prop(props, "related_element")
|
row.prop(props, "related_element")
|
||||||
|
|
||||||
row = layout.row()
|
row = self.layout.row()
|
||||||
row.operator("bim.add_variable")
|
row.operator("bim.add_variable")
|
||||||
|
|
||||||
for index, variable in enumerate(props.variables):
|
for index, variable in enumerate(props.variables):
|
||||||
row = layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.prop(variable, "name")
|
row.prop(variable, "name")
|
||||||
row.operator("bim.remove_variable", icon="X", text="").index = index
|
row.operator("bim.remove_variable", icon="X", text="").index = index
|
||||||
row = layout.row()
|
row = self.layout.row()
|
||||||
row.prop(variable, "prop_key")
|
row.prop(variable, "prop_key")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ class UpdateRepresentation(bpy.types.Operator):
|
|||||||
product, old_representation
|
product, old_representation
|
||||||
)
|
)
|
||||||
representation_data["profile_set_usage"] = tool.Geometry.get_profile_set_usage(product)
|
representation_data["profile_set_usage"] = tool.Geometry.get_profile_set_usage(product)
|
||||||
|
representation_data["text_literal"] = tool.Geometry.get_text_literal(old_representation)
|
||||||
|
|
||||||
new_representation = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
|
new_representation = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# 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/>.
|
||||||
|
|
||||||
|
|
||||||
|
def enable_editing_text(drawing, obj=None):
|
||||||
|
drawing.enable_editing_text(obj)
|
||||||
|
drawing.import_text_attributes(obj)
|
||||||
|
|
||||||
|
|
||||||
|
def disable_editing_text(drawing, obj=None):
|
||||||
|
drawing.disable_editing_text(obj)
|
||||||
|
|
||||||
|
|
||||||
|
def edit_text(ifc, drawing, obj=None):
|
||||||
|
ifc.run(
|
||||||
|
"drawing.edit_text_literal",
|
||||||
|
text_literal=drawing.get_text_literal(obj),
|
||||||
|
attributes=drawing.export_text_literal_attributes(obj),
|
||||||
|
)
|
||||||
|
drawing.update_text_value(obj)
|
||||||
|
drawing.disable_editing_text(obj)
|
||||||
@@ -70,6 +70,16 @@ class Context:
|
|||||||
def set_context(cls, context): pass
|
def set_context(cls, context): pass
|
||||||
|
|
||||||
|
|
||||||
|
@interface
|
||||||
|
class Drawing:
|
||||||
|
def disable_editing_text(cls, obj): pass
|
||||||
|
def enable_editing_text(cls, obj): pass
|
||||||
|
def export_text_literal_attributes(cls, obj): pass
|
||||||
|
def get_text_literal(cls, obj): pass
|
||||||
|
def import_text_attributes(cls, obj): pass
|
||||||
|
def update_text_value(cls, obj): pass
|
||||||
|
|
||||||
|
|
||||||
@interface
|
@interface
|
||||||
class Geometry:
|
class Geometry:
|
||||||
def change_object_data(cls, obj, data, is_global=False): pass
|
def change_object_data(cls, obj, data, is_global=False): pass
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ from blenderbim.tool.blender import Blender
|
|||||||
from blenderbim.tool.brick import Brick
|
from blenderbim.tool.brick import Brick
|
||||||
from blenderbim.tool.collector import Collector
|
from blenderbim.tool.collector import Collector
|
||||||
from blenderbim.tool.context import Context
|
from blenderbim.tool.context import Context
|
||||||
|
from blenderbim.tool.drawing import Drawing
|
||||||
from blenderbim.tool.geometry import Geometry
|
from blenderbim.tool.geometry import Geometry
|
||||||
from blenderbim.tool.ifc import Ifc
|
from blenderbim.tool.ifc import Ifc
|
||||||
from blenderbim.tool.material import Material
|
from blenderbim.tool.material import Material
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
# 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.core.tool
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
import ifcopenshell.util.representation
|
||||||
|
|
||||||
|
|
||||||
|
class Drawing(blenderbim.core.tool.Drawing):
|
||||||
|
@classmethod
|
||||||
|
def disable_editing_text(cls, obj):
|
||||||
|
obj.BIMTextProperties.is_editing = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def enable_editing_text(cls, obj):
|
||||||
|
obj.BIMTextProperties.is_editing = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def export_text_literal_attributes(cls, obj):
|
||||||
|
return blenderbim.bim.helper.export_attributes(obj.BIMTextProperties.attributes)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_text_literal(cls, obj):
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
if not element:
|
||||||
|
return
|
||||||
|
rep = ifcopenshell.util.representation.get_representation(element, "Plan", "Annotation")
|
||||||
|
if not rep:
|
||||||
|
return
|
||||||
|
items = [i for i in rep.Items if i.is_a("IfcTextLiteral")]
|
||||||
|
if items:
|
||||||
|
return items[0]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def import_text_attributes(cls, obj):
|
||||||
|
props = obj.BIMTextProperties
|
||||||
|
props.attributes.clear()
|
||||||
|
text = cls.get_text_literal(obj)
|
||||||
|
blenderbim.bim.helper.import_attributes2(text, props.attributes)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def update_text_value(cls, obj):
|
||||||
|
element = cls.get_text_literal(obj)
|
||||||
|
if element:
|
||||||
|
obj.BIMTextProperties.value = element.Literal
|
||||||
@@ -105,6 +105,12 @@ class Geometry(blenderbim.core.tool.Geometry):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_ifc_representation_class(cls, element, representation):
|
def get_ifc_representation_class(cls, element, representation):
|
||||||
|
if element.is_a("IfcAnnotation"):
|
||||||
|
if element.ObjectType == "TEXT":
|
||||||
|
return "IfcTextLiteral"
|
||||||
|
elif element.ObjectType == "TEXT_LEADER":
|
||||||
|
return "IfcGeometricCurveSet/IfcTextLiteral"
|
||||||
|
|
||||||
material = ifcopenshell.util.element.get_material(element)
|
material = ifcopenshell.util.element.get_material(element)
|
||||||
if material and material.is_a("IfcMaterialProfileSetUsage"):
|
if material and material.is_a("IfcMaterialProfileSetUsage"):
|
||||||
return "IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage"
|
return "IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage"
|
||||||
@@ -151,6 +157,12 @@ class Geometry(blenderbim.core.tool.Geometry):
|
|||||||
def get_styles(cls, obj):
|
def get_styles(cls, obj):
|
||||||
return [tool.Style.get_style(s.material) for s in obj.material_slots if s.material]
|
return [tool.Style.get_style(s.material) for s in obj.material_slots if s.material]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_text_literal(cls, representation):
|
||||||
|
texts = [i for i in representation.Items if i.is_a("IfcTextLiteral")]
|
||||||
|
if texts:
|
||||||
|
return texts[0]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_total_representation_items(cls, obj):
|
def get_total_representation_items(cls, obj):
|
||||||
return max(1, len(obj.material_slots))
|
return max(1, len(obj.material_slots))
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ markers =
|
|||||||
bimtester
|
bimtester
|
||||||
brick
|
brick
|
||||||
context
|
context
|
||||||
|
drawing
|
||||||
geometry
|
geometry
|
||||||
material
|
material
|
||||||
misc
|
misc
|
||||||
|
|||||||
@@ -63,6 +63,13 @@ def context():
|
|||||||
prophet.verify()
|
prophet.verify()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def drawing():
|
||||||
|
prophet = Prophecy(blenderbim.core.tool.Drawing)
|
||||||
|
yield prophet
|
||||||
|
prophet.verify()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def geometry():
|
def geometry():
|
||||||
prophet = Prophecy(blenderbim.core.tool.Geometry)
|
prophet = Prophecy(blenderbim.core.tool.Geometry)
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# 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 blenderbim.core.drawing as subject
|
||||||
|
from test.core.bootstrap import ifc, drawing
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnableEditingText:
|
||||||
|
def test_run(self, drawing):
|
||||||
|
drawing.enable_editing_text("obj").should_be_called()
|
||||||
|
drawing.import_text_attributes("obj").should_be_called()
|
||||||
|
subject.enable_editing_text(drawing, obj="obj")
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisableEditingText:
|
||||||
|
def test_run(self, drawing):
|
||||||
|
drawing.disable_editing_text("obj").should_be_called()
|
||||||
|
subject.disable_editing_text(drawing, obj="obj")
|
||||||
|
|
||||||
|
|
||||||
|
class TestEditText:
|
||||||
|
def test_run(self, ifc, drawing):
|
||||||
|
drawing.get_text_literal("obj").should_be_called().will_return("text")
|
||||||
|
drawing.export_text_literal_attributes("obj").should_be_called().will_return("attributes")
|
||||||
|
ifc.run("drawing.edit_text_literal", text_literal="text", attributes="attributes").should_be_called()
|
||||||
|
drawing.update_text_value("obj").should_be_called()
|
||||||
|
drawing.disable_editing_text("obj").should_be_called()
|
||||||
|
subject.edit_text(ifc, drawing, obj="obj")
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# 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 blenderbim.core.tool
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
from test.bim.bootstrap import NewFile
|
||||||
|
from blenderbim.tool.drawing import Drawing as subject
|
||||||
|
|
||||||
|
|
||||||
|
class TestImplementsTool(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
assert isinstance(subject(), blenderbim.core.tool.Drawing)
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisableEditingText(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
obj = bpy.data.objects.new("Object", None)
|
||||||
|
obj.BIMTextProperties.is_editing = True
|
||||||
|
subject.disable_editing_text(obj)
|
||||||
|
assert obj.BIMTextProperties.is_editing == False
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnableEditingText(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
obj = bpy.data.objects.new("Object", None)
|
||||||
|
subject.enable_editing_text(obj)
|
||||||
|
assert obj.BIMTextProperties.is_editing == True
|
||||||
|
|
||||||
|
|
||||||
|
class TestExportTextLiteralAttributes(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
TestImportTextAttributes().test_run()
|
||||||
|
assert subject.export_text_literal_attributes(bpy.data.objects.get("Object")) == {
|
||||||
|
"Literal": "Literal",
|
||||||
|
"Path": "RIGHT",
|
||||||
|
"BoxAlignment": "BoxAlignment",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetTextLiteral(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
obj = bpy.data.objects.new("Object", None)
|
||||||
|
element = ifc.createIfcAnnotation()
|
||||||
|
element.Representation = ifc.createIfcProductDefinitionShape()
|
||||||
|
context = ifc.createIfcGeometricRepresentationSubContext(ContextType="Plan", ContextIdentifier="Annotation")
|
||||||
|
item = ifc.createIfcTextLiteralWithExtent(Literal="Literal", Path="RIGHT", BoxAlignment="BoxAlignment")
|
||||||
|
representation = ifc.createIfcShapeRepresentation(ContextOfItems=context, Items=[item])
|
||||||
|
element.Representation.Representations = [representation]
|
||||||
|
tool.Ifc.link(element, obj)
|
||||||
|
assert subject.get_text_literal(obj) == item
|
||||||
|
|
||||||
|
|
||||||
|
class TestImportTextAttributes(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
obj = bpy.data.objects.new("Object", None)
|
||||||
|
element = ifc.createIfcAnnotation()
|
||||||
|
element.Representation = ifc.createIfcProductDefinitionShape()
|
||||||
|
context = ifc.createIfcGeometricRepresentationSubContext(ContextType="Plan", ContextIdentifier="Annotation")
|
||||||
|
item = ifc.createIfcTextLiteralWithExtent(Literal="Literal", Path="RIGHT", BoxAlignment="BoxAlignment")
|
||||||
|
representation = ifc.createIfcShapeRepresentation(ContextOfItems=context, Items=[item])
|
||||||
|
element.Representation.Representations = [representation]
|
||||||
|
tool.Ifc.link(element, obj)
|
||||||
|
subject.import_text_attributes(obj)
|
||||||
|
props = obj.BIMTextProperties
|
||||||
|
assert props.attributes.get("Literal").string_value == "Literal"
|
||||||
|
assert props.attributes.get("Path").enum_value == "RIGHT"
|
||||||
|
assert props.attributes.get("BoxAlignment").string_value == "BoxAlignment"
|
||||||
|
|
||||||
|
|
||||||
|
class TestUpdateTextValue(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
TestGetTextLiteral().test_run()
|
||||||
|
obj = bpy.data.objects.get("Object")
|
||||||
|
subject.update_text_value(obj)
|
||||||
|
assert obj.BIMTextProperties.value == "Literal"
|
||||||
@@ -178,7 +178,16 @@ class TestGetStyles(NewFile):
|
|||||||
tool.Ifc.link(style, material)
|
tool.Ifc.link(style, material)
|
||||||
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
|
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
|
||||||
obj.data.materials.append(material)
|
obj.data.materials.append(material)
|
||||||
subject.get_styles(obj) == [style]
|
assert subject.get_styles(obj) == [style]
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetTextLiteral(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
item = ifc.createIfcTextLiteralWithExtent()
|
||||||
|
representation = ifc.createIfcShapeRepresentation(Items=[item])
|
||||||
|
assert subject.get_text_literal(representation) == item
|
||||||
|
|
||||||
|
|
||||||
class TestGetCartesianPointCoordinateOffset(NewFile):
|
class TestGetCartesianPointCoordinateOffset(NewFile):
|
||||||
@@ -490,6 +499,20 @@ class TestGetIfcRepresentationClass(NewFile):
|
|||||||
subject.get_ifc_representation_class(element, representation) == "IfcExtrudedAreaSolid/IfcCircleProfileDef"
|
subject.get_ifc_representation_class(element, representation) == "IfcExtrudedAreaSolid/IfcCircleProfileDef"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_detecting_text_representations(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
element = ifc.createIfcAnnotation()
|
||||||
|
element.ObjectType = "TEXT"
|
||||||
|
assert subject.get_ifc_representation_class(element, None) == "IfcTextLiteral"
|
||||||
|
|
||||||
|
def test_detecting_text_and_geometric_representations(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
element = ifc.createIfcAnnotation()
|
||||||
|
element.ObjectType = "TEXT_LEADER"
|
||||||
|
assert subject.get_ifc_representation_class(element, None) == "IfcGeometricCurveSet/IfcTextLiteral"
|
||||||
|
|
||||||
def test_returning_null_for_non_parametric_representations(self):
|
def test_returning_null_for_non_parametric_representations(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc.set(ifc)
|
tool.Ifc.set(ifc)
|
||||||
|
|||||||
@@ -18,18 +18,18 @@
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import test.bim.bootstrap
|
|
||||||
import blenderbim.core.tool
|
import blenderbim.core.tool
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
|
from test.bim.bootstrap import NewFile
|
||||||
from blenderbim.tool.owner import Owner as subject
|
from blenderbim.tool.owner import Owner as subject
|
||||||
|
|
||||||
|
|
||||||
class TestImplementsTool(test.bim.bootstrap.NewFile):
|
class TestImplementsTool(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
assert isinstance(subject(), blenderbim.core.tool.Owner)
|
assert isinstance(subject(), blenderbim.core.tool.Owner)
|
||||||
|
|
||||||
|
|
||||||
class TestSetUser(test.bim.bootstrap.NewFile):
|
class TestSetUser(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc.set(ifc)
|
tool.Ifc.set(ifc)
|
||||||
@@ -38,7 +38,7 @@ class TestSetUser(test.bim.bootstrap.NewFile):
|
|||||||
assert bpy.context.scene.BIMOwnerProperties.active_user_id == user.id()
|
assert bpy.context.scene.BIMOwnerProperties.active_user_id == user.id()
|
||||||
|
|
||||||
|
|
||||||
class TestGetUser(test.bim.bootstrap.NewFile):
|
class TestGetUser(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
assert subject.get_user() is None
|
assert subject.get_user() is None
|
||||||
TestSetUser().test_run()
|
TestSetUser().test_run()
|
||||||
@@ -56,14 +56,14 @@ class TestGetUser(test.bim.bootstrap.NewFile):
|
|||||||
assert subject.get_user() == user2
|
assert subject.get_user() == user2
|
||||||
|
|
||||||
|
|
||||||
class TestClearUser(test.bim.bootstrap.NewFile):
|
class TestClearUser(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
TestSetUser().test_run()
|
TestSetUser().test_run()
|
||||||
subject.clear_user()
|
subject.clear_user()
|
||||||
assert bpy.context.scene.BIMOwnerProperties.active_user_id == 0
|
assert bpy.context.scene.BIMOwnerProperties.active_user_id == 0
|
||||||
|
|
||||||
|
|
||||||
class TestSetAddress(test.bim.bootstrap.NewFile):
|
class TestSetAddress(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
address = ifc.createIfcPostalAddress()
|
address = ifc.createIfcPostalAddress()
|
||||||
@@ -71,7 +71,7 @@ class TestSetAddress(test.bim.bootstrap.NewFile):
|
|||||||
assert bpy.context.scene.BIMOwnerProperties.active_address_id == address.id()
|
assert bpy.context.scene.BIMOwnerProperties.active_address_id == address.id()
|
||||||
|
|
||||||
|
|
||||||
class TestImportAddressAttributes(test.bim.bootstrap.NewFile):
|
class TestImportAddressAttributes(NewFile):
|
||||||
def test_importing_a_postal_address(self):
|
def test_importing_a_postal_address(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc().set(ifc)
|
tool.Ifc().set(ifc)
|
||||||
@@ -152,7 +152,7 @@ class TestImportAddressAttributes(test.bim.bootstrap.NewFile):
|
|||||||
assert len(props.messaging_ids) == 0
|
assert len(props.messaging_ids) == 0
|
||||||
|
|
||||||
|
|
||||||
class TestClearAddress(test.bim.bootstrap.NewFile):
|
class TestClearAddress(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
address = ifc.createIfcPostalAddress()
|
address = ifc.createIfcPostalAddress()
|
||||||
@@ -161,7 +161,7 @@ class TestClearAddress(test.bim.bootstrap.NewFile):
|
|||||||
assert bpy.context.scene.BIMOwnerProperties.active_address_id == 0
|
assert bpy.context.scene.BIMOwnerProperties.active_address_id == 0
|
||||||
|
|
||||||
|
|
||||||
class TestGetAddress(test.bim.bootstrap.NewFile):
|
class TestGetAddress(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc().set(ifc)
|
tool.Ifc().set(ifc)
|
||||||
@@ -170,7 +170,7 @@ class TestGetAddress(test.bim.bootstrap.NewFile):
|
|||||||
assert subject().get_address() == address
|
assert subject().get_address() == address
|
||||||
|
|
||||||
|
|
||||||
class TestExportAttributes(test.bim.bootstrap.NewFile):
|
class TestExportAttributes(NewFile):
|
||||||
def test_exporting_a_postal_address(self):
|
def test_exporting_a_postal_address(self):
|
||||||
TestImportAddressAttributes().test_importing_a_postal_address()
|
TestImportAddressAttributes().test_importing_a_postal_address()
|
||||||
assert subject().export_address_attributes() == {
|
assert subject().export_address_attributes() == {
|
||||||
@@ -201,7 +201,7 @@ class TestExportAttributes(test.bim.bootstrap.NewFile):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestAddAddressAttribute(test.bim.bootstrap.NewFile):
|
class TestAddAddressAttribute(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
subject().add_address_attribute("AddressLines")
|
subject().add_address_attribute("AddressLines")
|
||||||
subject().add_address_attribute("TelephoneNumbers")
|
subject().add_address_attribute("TelephoneNumbers")
|
||||||
@@ -216,7 +216,7 @@ class TestAddAddressAttribute(test.bim.bootstrap.NewFile):
|
|||||||
assert len(props.messaging_ids) == 1
|
assert len(props.messaging_ids) == 1
|
||||||
|
|
||||||
|
|
||||||
class TestRemoveAddressAttribute(test.bim.bootstrap.NewFile):
|
class TestRemoveAddressAttribute(NewFile):
|
||||||
TestAddAddressAttribute().test_run()
|
TestAddAddressAttribute().test_run()
|
||||||
subject().remove_address_attribute("AddressLines", 0)
|
subject().remove_address_attribute("AddressLines", 0)
|
||||||
subject().remove_address_attribute("TelephoneNumbers", 0)
|
subject().remove_address_attribute("TelephoneNumbers", 0)
|
||||||
@@ -231,14 +231,14 @@ class TestRemoveAddressAttribute(test.bim.bootstrap.NewFile):
|
|||||||
assert len(props.messaging_ids) == 0
|
assert len(props.messaging_ids) == 0
|
||||||
|
|
||||||
|
|
||||||
class TestSetOrganisation(test.bim.bootstrap.NewFile):
|
class TestSetOrganisation(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
organisation = ifcopenshell.file().createIfcOrganization()
|
organisation = ifcopenshell.file().createIfcOrganization()
|
||||||
subject().set_organisation(organisation)
|
subject().set_organisation(organisation)
|
||||||
assert bpy.context.scene.BIMOwnerProperties.active_organisation_id == organisation.id()
|
assert bpy.context.scene.BIMOwnerProperties.active_organisation_id == organisation.id()
|
||||||
|
|
||||||
|
|
||||||
class TestImportOrganisationAttributes(test.bim.bootstrap.NewFile):
|
class TestImportOrganisationAttributes(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc().set(ifc)
|
tool.Ifc().set(ifc)
|
||||||
@@ -269,7 +269,7 @@ class TestImportOrganisationAttributes(test.bim.bootstrap.NewFile):
|
|||||||
assert props.organisation_attributes.get("Description").string_value == ""
|
assert props.organisation_attributes.get("Description").string_value == ""
|
||||||
|
|
||||||
|
|
||||||
class TestClearOrganisation(test.bim.bootstrap.NewFile):
|
class TestClearOrganisation(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
props = bpy.context.scene.BIMOwnerProperties
|
props = bpy.context.scene.BIMOwnerProperties
|
||||||
props.active_organisation_id = 1
|
props.active_organisation_id = 1
|
||||||
@@ -277,7 +277,7 @@ class TestClearOrganisation(test.bim.bootstrap.NewFile):
|
|||||||
assert props.active_organisation_id == 0
|
assert props.active_organisation_id == 0
|
||||||
|
|
||||||
|
|
||||||
class TestExportOrganisationAttributes(test.bim.bootstrap.NewFile):
|
class TestExportOrganisationAttributes(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
TestImportOrganisationAttributes().test_run()
|
TestImportOrganisationAttributes().test_run()
|
||||||
assert subject().export_organisation_attributes() == {
|
assert subject().export_organisation_attributes() == {
|
||||||
@@ -287,7 +287,7 @@ class TestExportOrganisationAttributes(test.bim.bootstrap.NewFile):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestGetOrganisation(test.bim.bootstrap.NewFile):
|
class TestGetOrganisation(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc().set(ifc)
|
tool.Ifc().set(ifc)
|
||||||
@@ -296,14 +296,14 @@ class TestGetOrganisation(test.bim.bootstrap.NewFile):
|
|||||||
assert subject().get_organisation() == organisation
|
assert subject().get_organisation() == organisation
|
||||||
|
|
||||||
|
|
||||||
class TestSetPerson(test.bim.bootstrap.NewFile):
|
class TestSetPerson(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
person = ifcopenshell.file().createIfcPerson()
|
person = ifcopenshell.file().createIfcPerson()
|
||||||
subject().set_person(person)
|
subject().set_person(person)
|
||||||
assert bpy.context.scene.BIMOwnerProperties.active_person_id == person.id()
|
assert bpy.context.scene.BIMOwnerProperties.active_person_id == person.id()
|
||||||
|
|
||||||
|
|
||||||
class TestImportPersonAttributes(test.bim.bootstrap.NewFile):
|
class TestImportPersonAttributes(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc().set(ifc)
|
tool.Ifc().set(ifc)
|
||||||
@@ -346,7 +346,7 @@ class TestImportPersonAttributes(test.bim.bootstrap.NewFile):
|
|||||||
assert props.person_attributes.get("GivenName").string_value == ""
|
assert props.person_attributes.get("GivenName").string_value == ""
|
||||||
|
|
||||||
|
|
||||||
class TestClearPerson(test.bim.bootstrap.NewFile):
|
class TestClearPerson(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
props = bpy.context.scene.BIMOwnerProperties
|
props = bpy.context.scene.BIMOwnerProperties
|
||||||
props.active_person_id = 1
|
props.active_person_id = 1
|
||||||
@@ -354,7 +354,7 @@ class TestClearPerson(test.bim.bootstrap.NewFile):
|
|||||||
assert props.active_person_id == 0
|
assert props.active_person_id == 0
|
||||||
|
|
||||||
|
|
||||||
class TestExportPersonAttributes(test.bim.bootstrap.NewFile):
|
class TestExportPersonAttributes(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc().set(ifc)
|
tool.Ifc().set(ifc)
|
||||||
@@ -385,7 +385,7 @@ class TestExportPersonAttributes(test.bim.bootstrap.NewFile):
|
|||||||
assert result["SuffixTitles"] is None
|
assert result["SuffixTitles"] is None
|
||||||
|
|
||||||
|
|
||||||
class TestGetPerson(test.bim.bootstrap.NewFile):
|
class TestGetPerson(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc().set(ifc)
|
tool.Ifc().set(ifc)
|
||||||
@@ -394,7 +394,7 @@ class TestGetPerson(test.bim.bootstrap.NewFile):
|
|||||||
assert subject().get_person() == person
|
assert subject().get_person() == person
|
||||||
|
|
||||||
|
|
||||||
class TestAddPersonAttribute(test.bim.bootstrap.NewFile):
|
class TestAddPersonAttribute(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
subject().add_person_attribute("MiddleNames")
|
subject().add_person_attribute("MiddleNames")
|
||||||
subject().add_person_attribute("PrefixTitles")
|
subject().add_person_attribute("PrefixTitles")
|
||||||
@@ -405,7 +405,7 @@ class TestAddPersonAttribute(test.bim.bootstrap.NewFile):
|
|||||||
assert len(props.suffix_titles) == 1
|
assert len(props.suffix_titles) == 1
|
||||||
|
|
||||||
|
|
||||||
class TestRemovePersonAttribute(test.bim.bootstrap.NewFile):
|
class TestRemovePersonAttribute(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
subject().add_person_attribute("MiddleNames")
|
subject().add_person_attribute("MiddleNames")
|
||||||
subject().remove_person_attribute("MiddleNames", 0)
|
subject().remove_person_attribute("MiddleNames", 0)
|
||||||
@@ -419,14 +419,14 @@ class TestRemovePersonAttribute(test.bim.bootstrap.NewFile):
|
|||||||
assert len(props.suffix_titles) == 0
|
assert len(props.suffix_titles) == 0
|
||||||
|
|
||||||
|
|
||||||
class TestSetRole(test.bim.bootstrap.NewFile):
|
class TestSetRole(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
role = ifcopenshell.file().createIfcActorRole()
|
role = ifcopenshell.file().createIfcActorRole()
|
||||||
subject().set_role(role)
|
subject().set_role(role)
|
||||||
assert bpy.context.scene.BIMOwnerProperties.active_role_id == role.id()
|
assert bpy.context.scene.BIMOwnerProperties.active_role_id == role.id()
|
||||||
|
|
||||||
|
|
||||||
class TestImportRoleAttributes(test.bim.bootstrap.NewFile):
|
class TestImportRoleAttributes(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc().set(ifc)
|
tool.Ifc().set(ifc)
|
||||||
@@ -454,7 +454,7 @@ class TestImportRoleAttributes(test.bim.bootstrap.NewFile):
|
|||||||
assert props.role_attributes.get("Role").enum_value == "ARCHITECT"
|
assert props.role_attributes.get("Role").enum_value == "ARCHITECT"
|
||||||
|
|
||||||
|
|
||||||
class TestClearRole(test.bim.bootstrap.NewFile):
|
class TestClearRole(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
role = ifcopenshell.file().createIfcActorRole()
|
role = ifcopenshell.file().createIfcActorRole()
|
||||||
subject().set_role(role)
|
subject().set_role(role)
|
||||||
@@ -462,7 +462,7 @@ class TestClearRole(test.bim.bootstrap.NewFile):
|
|||||||
assert bpy.context.scene.BIMOwnerProperties.active_role_id == 0
|
assert bpy.context.scene.BIMOwnerProperties.active_role_id == 0
|
||||||
|
|
||||||
|
|
||||||
class TestGetRole(test.bim.bootstrap.NewFile):
|
class TestGetRole(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc().set(ifc)
|
tool.Ifc().set(ifc)
|
||||||
@@ -471,7 +471,7 @@ class TestGetRole(test.bim.bootstrap.NewFile):
|
|||||||
assert subject().get_role() == role
|
assert subject().get_role() == role
|
||||||
|
|
||||||
|
|
||||||
class TestExportRoleAttributes(test.bim.bootstrap.NewFile):
|
class TestExportRoleAttributes(NewFile):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ifc = ifcopenshell.file()
|
ifc = ifcopenshell.file()
|
||||||
tool.Ifc().set(ifc)
|
tool.Ifc().set(ifc)
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
class Usecase:
|
||||||
|
def __init__(self, file, **settings):
|
||||||
|
self.file = file
|
||||||
|
self.settings = {"text_literal": 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["text_literal"], name, value)
|
||||||
@@ -28,8 +28,11 @@ class Usecase:
|
|||||||
# IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef
|
# IfcExtrudedAreaSolid/IfcArbitraryClosedProfileDef
|
||||||
# IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids
|
# IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids
|
||||||
# IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage
|
# IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage
|
||||||
|
# IfcGeometricCurveSet/IfcTextLiteral
|
||||||
|
# IfcTextLiteral
|
||||||
"ifc_representation_class": None, # Whether to cast a mesh into a particular class
|
"ifc_representation_class": None, # Whether to cast a mesh into a particular class
|
||||||
"profile_set_usage": None, # The material profile set if the extrusion requires it
|
"profile_set_usage": None, # The material profile set if the extrusion requires it
|
||||||
|
"text_literal": None, # The text literal if the representation requires it
|
||||||
}
|
}
|
||||||
self.ifc_vertices = []
|
self.ifc_vertices = []
|
||||||
for key, value in settings.items():
|
for key, value in settings.items():
|
||||||
@@ -117,9 +120,16 @@ class Usecase:
|
|||||||
return self.create_lighting_representation()
|
return self.create_lighting_representation()
|
||||||
|
|
||||||
def create_plan_representation(self):
|
def create_plan_representation(self):
|
||||||
if self.settings["context"].ContextIdentifier == "Annotation":
|
if self.settings["ifc_representation_class"] == "IfcTextLiteral":
|
||||||
if isinstance(self.settings["geometry"], bpy.types.TextCurve):
|
return self.create_text_representation()
|
||||||
return self.create_text_representation()
|
elif self.settings["ifc_representation_class"] == "IfcGeometricCurveSet/IfcTextLiteral":
|
||||||
|
shape_representation = self.create_geometric_curve_set_representation(is_2d=True)
|
||||||
|
shape_representation.RepresentationType = "Annotation2D"
|
||||||
|
items = list(shape_representation.Items)
|
||||||
|
items.append(self.create_text())
|
||||||
|
shape_representation.Items = items
|
||||||
|
return shape_representation
|
||||||
|
elif self.settings["context"].ContextIdentifier == "Annotation":
|
||||||
shape_representation = self.create_geometric_curve_set_representation(is_2d=True)
|
shape_representation = self.create_geometric_curve_set_representation(is_2d=True)
|
||||||
shape_representation.RepresentationType = "Annotation2D"
|
shape_representation.RepresentationType = "Annotation2D"
|
||||||
return shape_representation
|
return shape_representation
|
||||||
@@ -143,8 +153,6 @@ class Usecase:
|
|||||||
elif self.settings["context"].ContextIdentifier == "SurveyPoints":
|
elif self.settings["context"].ContextIdentifier == "SurveyPoints":
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if isinstance(self.settings["geometry"], bpy.types.TextCurve):
|
|
||||||
return self.create_text_representation()
|
|
||||||
shape_representation = self.create_geometric_curve_set_representation(is_2d=True)
|
shape_representation = self.create_geometric_curve_set_representation(is_2d=True)
|
||||||
shape_representation.RepresentationType = "Annotation2D"
|
shape_representation.RepresentationType = "Annotation2D"
|
||||||
return shape_representation
|
return shape_representation
|
||||||
@@ -180,21 +188,8 @@ class Usecase:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create_text(self):
|
def create_text(self):
|
||||||
text = self.settings["geometry"]
|
if self.settings["text_literal"]:
|
||||||
if text.align_y in ["TOP_BASELINE", "BOTTOM_BASELINE", "BOTTOM"]:
|
return self.settings["text_literal"]
|
||||||
y = "bottom"
|
|
||||||
elif text.align_y == "CENTER":
|
|
||||||
y = "middle"
|
|
||||||
elif text.align_y == "TOP":
|
|
||||||
y = "top"
|
|
||||||
|
|
||||||
if text.align_x == "LEFT":
|
|
||||||
x = "left"
|
|
||||||
elif text.align_x == "CENTER":
|
|
||||||
x = "middle"
|
|
||||||
elif text.align_x == "RIGHT":
|
|
||||||
x = "right"
|
|
||||||
|
|
||||||
origin = self.file.createIfcAxis2Placement3D(
|
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)),
|
||||||
@@ -203,7 +198,7 @@ class Usecase:
|
|||||||
|
|
||||||
# TODO: Planar extent right now is wrong ...
|
# TODO: Planar extent right now is wrong ...
|
||||||
return self.file.createIfcTextLiteralWithExtent(
|
return self.file.createIfcTextLiteralWithExtent(
|
||||||
text.body, origin, "RIGHT", self.file.createIfcPlanarExtent(1000, 1000), f"{y}-{x}"
|
"TEXT", origin, "RIGHT", self.file.createIfcPlanarExtent(1000, 1000), "bottom-left"
|
||||||
)
|
)
|
||||||
|
|
||||||
def create_variable_representation(self):
|
def create_variable_representation(self):
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import test.bootstrap
|
||||||
|
import ifcopenshell.api
|
||||||
|
|
||||||
|
|
||||||
|
class TestEditTextLiteral(test.bootstrap.IFC4):
|
||||||
|
def test_run(self):
|
||||||
|
text = self.file.createIfcTextLiteralWithExtent()
|
||||||
|
ifcopenshell.api.run("drawing.edit_text_literal", self.file, text_literal=text, attributes={
|
||||||
|
"Literal": "Literal",
|
||||||
|
"Path": "RIGHT",
|
||||||
|
"BoxAlignment": "middle",
|
||||||
|
})
|
||||||
|
assert text.Literal == "Literal"
|
||||||
|
assert text.Path == "RIGHT"
|
||||||
|
assert text.BoxAlignment == "middle"
|
||||||
Reference in New Issue
Block a user