Add section cut multiprocessing, grids, hidden lines, stair arrows, text annotations, and leaders

This commit is contained in:
Dion Moult
2019-12-13 17:25:52 +11:00
parent 4f7925580a
commit c0cd0ce07e
5 changed files with 370 additions and 186 deletions
+119 -115
View File
@@ -11,124 +11,128 @@ bl_info = {
"category": "Import-Export"
}
import bpy
from . import ui, prop, operator
# are we running inside Blender?
import sys
bpy = sys.modules.get('bpy')
if bpy is not None:
import bpy
from . import ui, prop, operator
classes = (
operator.AssignClass,
operator.SelectClass,
operator.SelectType,
operator.SelectFeaturesDir,
operator.SelectDiffJsonFile,
operator.SelectDataDir,
operator.SelectSchemaDir,
operator.ExportIFC,
operator.ImportIFC,
operator.ColourByClass,
operator.ResetObjectColours,
operator.ApproveClass,
operator.RejectClass,
operator.SelectAudited,
operator.RejectElement,
operator.SelectExternalMaterialDir,
operator.AddSweptSolid,
operator.RemoveSweptSolid,
operator.AssignSweptSolidOuterCurve,
operator.SelectSweptSolidOuterCurve,
operator.AddSweptSolidInnerCurve,
operator.SelectSweptSolidInnerCurves,
operator.AssignSweptSolidExtrusion,
operator.SelectSweptSolidExtrusion,
operator.AssignPset,
operator.UnassignPset,
operator.AddPset,
operator.RemovePset,
operator.AddDocument,
operator.RemoveDocument,
operator.GenerateGlobalId,
operator.AddAttribute,
operator.RemoveAttribute,
operator.QuickProjectSetup,
operator.SelectGlobalId,
operator.CreateAggregate,
operator.EditAggregate,
operator.SaveAggregate,
operator.AssignClassification,
operator.UnassignClassification,
operator.RemoveClassification,
operator.FetchLibraryInformation,
operator.FetchExternalMaterial,
operator.FetchObjectPassport,
operator.AddSubcontext,
operator.RemoveSubcontext,
operator.CutSection,
operator.CreateSheets,
prop.Subcontext,
prop.BIMProperties,
prop.DocProperties,
prop.BIMLibrary,
prop.MapConversion,
prop.TargetCRS,
prop.Attribute,
prop.Pset,
prop.Document,
prop.Classification,
prop.GlobalId,
prop.BIMObjectProperties,
prop.BIMMaterialProperties,
prop.SweptSolid,
prop.BIMMeshProperties,
ui.BIM_PT_documentation,
ui.BIM_PT_bim,
ui.BIM_PT_context,
ui.BIM_PT_qa,
ui.BIM_PT_library,
ui.BIM_PT_gis,
ui.BIM_PT_diff,
ui.BIM_PT_mvd,
ui.BIM_PT_material,
ui.BIM_PT_mesh,
ui.BIM_PT_object,
)
classes = (
operator.AssignClass,
operator.SelectClass,
operator.SelectType,
operator.SelectFeaturesDir,
operator.SelectDiffJsonFile,
operator.SelectDataDir,
operator.SelectSchemaDir,
operator.ExportIFC,
operator.ImportIFC,
operator.ColourByClass,
operator.ResetObjectColours,
operator.ApproveClass,
operator.RejectClass,
operator.SelectAudited,
operator.RejectElement,
operator.SelectExternalMaterialDir,
operator.AddSweptSolid,
operator.RemoveSweptSolid,
operator.AssignSweptSolidOuterCurve,
operator.SelectSweptSolidOuterCurve,
operator.AddSweptSolidInnerCurve,
operator.SelectSweptSolidInnerCurves,
operator.AssignSweptSolidExtrusion,
operator.SelectSweptSolidExtrusion,
operator.AssignPset,
operator.UnassignPset,
operator.AddPset,
operator.RemovePset,
operator.AddDocument,
operator.RemoveDocument,
operator.GenerateGlobalId,
operator.AddAttribute,
operator.RemoveAttribute,
operator.QuickProjectSetup,
operator.SelectGlobalId,
operator.CreateAggregate,
operator.EditAggregate,
operator.SaveAggregate,
operator.AssignClassification,
operator.UnassignClassification,
operator.RemoveClassification,
operator.FetchLibraryInformation,
operator.FetchExternalMaterial,
operator.FetchObjectPassport,
operator.AddSubcontext,
operator.RemoveSubcontext,
operator.CutSection,
operator.CreateSheets,
prop.Subcontext,
prop.BIMProperties,
prop.DocProperties,
prop.BIMLibrary,
prop.MapConversion,
prop.TargetCRS,
prop.Attribute,
prop.Pset,
prop.Document,
prop.Classification,
prop.GlobalId,
prop.BIMObjectProperties,
prop.BIMMaterialProperties,
prop.SweptSolid,
prop.BIMMeshProperties,
ui.BIM_PT_documentation,
ui.BIM_PT_bim,
ui.BIM_PT_context,
ui.BIM_PT_qa,
ui.BIM_PT_library,
ui.BIM_PT_gis,
ui.BIM_PT_diff,
ui.BIM_PT_mvd,
ui.BIM_PT_material,
ui.BIM_PT_mesh,
ui.BIM_PT_object,
)
def menu_func_export(self, context):
self.layout.operator(operator.ExportIFC.bl_idname,
text="Industry Foundation Classes (.ifc)")
def menu_func_export(self, context):
self.layout.operator(operator.ExportIFC.bl_idname,
text="Industry Foundation Classes (.ifc)")
def menu_func_import(self, context):
self.layout.operator(operator.ImportIFC.bl_idname,
text="Industry Foundation Classes (.ifc)")
def menu_func_import(self, context):
self.layout.operator(operator.ImportIFC.bl_idname,
text="Industry Foundation Classes (.ifc)")
def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.app.handlers.load_post.append(prop.setDefaultProperties)
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
bpy.types.Scene.DocProperties = bpy.props.PointerProperty(type=prop.DocProperties)
bpy.types.Scene.BIMLibrary = bpy.props.PointerProperty(type=prop.BIMLibrary)
bpy.types.Scene.MapConversion = bpy.props.PointerProperty(type=prop.MapConversion)
bpy.types.Scene.TargetCRS = bpy.props.PointerProperty(type=prop.TargetCRS)
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
bpy.types.Collection.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
bpy.types.Material.BIMMaterialProperties = bpy.props.PointerProperty(type=prop.BIMMaterialProperties)
bpy.types.Mesh.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.app.handlers.load_post.append(prop.setDefaultProperties)
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
bpy.types.Scene.DocProperties = bpy.props.PointerProperty(type=prop.DocProperties)
bpy.types.Scene.BIMLibrary = bpy.props.PointerProperty(type=prop.BIMLibrary)
bpy.types.Scene.MapConversion = bpy.props.PointerProperty(type=prop.MapConversion)
bpy.types.Scene.TargetCRS = bpy.props.PointerProperty(type=prop.TargetCRS)
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
bpy.types.Collection.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
bpy.types.Material.BIMMaterialProperties = bpy.props.PointerProperty(type=prop.BIMMaterialProperties)
bpy.types.Mesh.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)
bpy.app.handlers.load_post.remove(prop.setDefaultProperties)
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
del(bpy.types.Scene.BIMProperties)
del(bpy.types.Scene.DocProperties)
del(bpy.types.Scene.MapConversion)
del(bpy.types.Scene.TargetCRS)
del(bpy.types.Object.BIMObjectProperties)
del(bpy.types.Collection.BIMObjectProperties)
del(bpy.types.Material.BIMMaterialProperties)
del(bpy.types.Mesh.BIMMeshProperties)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)
bpy.app.handlers.load_post.remove(prop.setDefaultProperties)
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
del(bpy.types.Scene.BIMProperties)
del(bpy.types.Scene.DocProperties)
del(bpy.types.Scene.MapConversion)
del(bpy.types.Scene.TargetCRS)
del(bpy.types.Object.BIMObjectProperties)
del(bpy.types.Collection.BIMObjectProperties)
del(bpy.types.Material.BIMMaterialProperties)
del(bpy.types.Mesh.BIMMeshProperties)
if __name__ == "__main__":
register()
if __name__ == "__main__":
register()
+215 -67
View File
@@ -5,7 +5,9 @@ import numpy
import pickle
import sys
from pathlib import Path
from mathutils import Vector
mathutils = sys.modules.get('mathutils')
if mathutils is not None:
from mathutils import Vector
from math import degrees
import xml.etree.ElementTree as ET
@@ -42,6 +44,80 @@ from OCC.TopoDS import topods
import ifcopenshell
import ifcopenshell.geom
cwd = os.path.dirname(os.path.realpath(__file__))
this_file = os.path.join(cwd, 'cut_ifc.py')
def get_booleaned_edges(shape):
edges = []
exp = OCC.TopExp.TopExp_Explorer(shape, OCC.TopAbs.TopAbs_EDGE)
while exp.More():
edges.append(topods.Edge(exp.Current()))
exp.Next()
return edges
def connect_edges_into_wires(unconnected_edges):
edges = OCC.TopTools.TopTools_HSequenceOfShape()
edges_handle = OCC.TopTools.Handle_TopTools_HSequenceOfShape(edges)
wires = OCC.TopTools.TopTools_HSequenceOfShape()
wires_handle = OCC.TopTools.Handle_TopTools_HSequenceOfShape(wires)
for edge in unconnected_edges:
edges.Append(edge)
OCC.ShapeAnalysis.ShapeAnalysis_FreeBounds.ConnectEdgesToWires(edges_handle, 1e-5, True, wires_handle)
return wires_handle.GetObject()
def do_cut(process_data):
global_id, shape, section, trsf_data = process_data
axis = OCC.gp.gp_Ax2(
OCC.gp.gp_Pnt(
trsf_data['top_left_corner'][0],
trsf_data['top_left_corner'][1],
trsf_data['top_left_corner'][2]),
OCC.gp.gp_Dir(
trsf_data['projection'][0],
trsf_data['projection'][1],
trsf_data['projection'][2]),
OCC.gp.gp_Dir(
trsf_data['x_axis'][0],
trsf_data['x_axis'][1],
trsf_data['x_axis'][2])
)
source = OCC.gp.gp_Ax3(axis)
destination = OCC.gp.gp_Ax3(
OCC.gp.gp_Pnt(0, 0, 0),
OCC.gp.gp_Dir(0, 0, -1),
OCC.gp.gp_Dir(1, 0, 0))
transformation = OCC.gp.gp_Trsf()
transformation.SetDisplacement(source, destination)
cut_polygons = []
section = OCC.BRepAlgoAPI.BRepAlgoAPI_Section(section, shape).Shape()
section_edges = get_booleaned_edges(section)
if len(section_edges) <= 0:
return cut_polygons
wires = connect_edges_into_wires(section_edges)
for i in range(wires.Length()):
wire_shape = wires.Value(i+1)
transformed_wire = OCC.BRepBuilderAPI.BRepBuilderAPI_Transform(
wire_shape, transformation)
wire_shape = transformed_wire.Shape()
wire = topods.Wire(wire_shape)
face = OCC.BRepBuilderAPI.BRepBuilderAPI_MakeFace(wire).Face()
points = []
exp = OCC.BRepTools.BRepTools_WireExplorer(wire)
while exp.More():
point = OCC.BRep.BRep_Tool.Pnt(exp.CurrentVertex())
points.append((point.X(), -point.Y()))
exp.Next()
cut_polygons.append({ 'global_id': global_id, 'points': points })
return cut_polygons
class IfcCutter:
def __init__(self):
self.product_shapes = []
@@ -253,10 +329,16 @@ class IfcCutter:
self.section_box['face'] = section_box.BottomFace()
source = OCC.gp.gp_Ax3(axis)
self.transformation_data = {
'top_left_corner': self.section_box['top_left_corner'],
'projection': self.section_box['projection'],
'x_axis': self.section_box['x_axis']
}
destination = OCC.gp.gp_Ax3(
OCC.gp.gp_Pnt(0, 0, 0),
OCC.gp.gp_Dir(0, 0, -1),
OCC.gp.gp_Dir(1, 0, 0))
self.transformation_dest = destination
self.transformation = OCC.gp.gp_Trsf()
self.transformation.SetDisplacement(source, destination)
@@ -489,51 +571,22 @@ class IfcCutter:
return
total_product_shapes = len(self.product_shapes)
n = 0
for product, shape in self.product_shapes:
print('{}/{} cut elements processed ...'.format(n, total_product_shapes), end='\r', flush=True)
n += 1
section = OCC.BRepAlgoAPI.BRepAlgoAPI_Section(self.section_box['face'], shape).Shape()
section_edges = self.get_booleaned_edges(section)
if len(section_edges) <= 0:
continue
wires = self.connect_edges_into_wires(section_edges)
for i in range(wires.Length()):
wire_shape = wires.Value(i+1)
process_data = [(p.GlobalId, s, self.section_box['face'], self.transformation_data) for p, s in self.product_shapes]
transformed_wire = OCC.BRepBuilderAPI.BRepBuilderAPI_Transform(
wire_shape, self.transformation)
wire_shape = transformed_wire.Shape()
import multiprocessing
import bpy
multiprocessing.set_executable(bpy.app.binary_path_python)
wire = topods.Wire(wire_shape)
face = OCC.BRepBuilderAPI.BRepBuilderAPI_MakeFace(wire).Face()
points = []
exp = OCC.BRepTools.BRepTools_WireExplorer(wire)
while exp.More():
point = OCC.BRep.BRep_Tool.Pnt(exp.CurrentVertex())
points.append((point.X(), -point.Y()))
exp.Next()
self.cut_polygons.append({
'global_id': product.GlobalId,
'points': points
})
with multiprocessing.Pool(9) as p:
results = p.map(do_cut, process_data)
for result in results:
polygons = [p for p in result if p['points']]
self.cut_polygons.extend(polygons)
if not os.path.isfile(self.cut_pickle_file):
with open(self.cut_pickle_file, 'wb') as pickle_file:
pickle.dump(self.cut_polygons, pickle_file, protocol=pickle.HIGHEST_PROTOCOL)
def connect_edges_into_wires(self, unconnected_edges):
edges = OCC.TopTools.TopTools_HSequenceOfShape()
edges_handle = OCC.TopTools.Handle_TopTools_HSequenceOfShape(edges)
wires = OCC.TopTools.TopTools_HSequenceOfShape()
wires_handle = OCC.TopTools.Handle_TopTools_HSequenceOfShape(wires)
for edge in unconnected_edges:
edges.Append(edge)
OCC.ShapeAnalysis.ShapeAnalysis_FreeBounds.ConnectEdgesToWires(edges_handle, 1e-5, True, wires_handle)
return wires_handle.GetObject()
class IfcCutterDebug(IfcCutter):
def cut(self):
@@ -672,37 +725,132 @@ class SvgWriter():
def draw_annotations(self):
x_offset = self.raw_width / 2
y_offset = self.raw_height / 2
for edge in self.ifc_cutter.annotation_obj.data.edges:
classes = ['annotation', 'dimension']
v0 = self.ifc_cutter.annotation_obj.data.vertices[edge.vertices[0]].co
v1 = self.ifc_cutter.annotation_obj.data.vertices[edge.vertices[1]].co
start = Vector(((x_offset + v0.x), (y_offset - v0.y)))
end = Vector(((x_offset + v1.x), (y_offset - v1.y)))
mid = ((end - start) / 2) + start
# TODO: hardcoded meters to mm conversion, until I properly do units
vector = end - start
if (end.y - start.y) * self.scale > 1:
perpendicular = Vector((-vector.y, vector.x)).normalized()
if self.ifc_cutter.dimension_obj:
for edge in self.ifc_cutter.dimension_obj.data.edges:
classes = ['annotation', 'dimension']
v0 = self.ifc_cutter.dimension_obj.data.vertices[edge.vertices[0]].co
v1 = self.ifc_cutter.dimension_obj.data.vertices[edge.vertices[1]].co
start = Vector(((x_offset + v0.x), (y_offset - v0.y)))
end = Vector(((x_offset + v1.x), (y_offset - v1.y)))
mid = ((end - start) / 2) + start
# TODO: hardcoded meters to mm conversion, until I properly do units
vector = end - start
if (end.y - start.y) * self.scale > 1:
perpendicular = Vector((-vector.y, vector.x)).normalized()
else:
perpendicular = Vector((vector.y, -vector.x)).normalized()
text_position = (mid * self.scale) + perpendicular
dimension = vector.length * 1000
rotation = -degrees(vector.angle(Vector((1, 0))))
line = self.svg.add(self.svg.line(start=tuple(start * self.scale),
end=tuple(end * self.scale), class_=' '.join(classes)))
line['marker-start'] = 'url(#dimension-marker)'
line['marker-end'] = 'url(#dimension-marker)'
# Standard font sizes 1.8, 2.5, 3.5, 5, 7
# Equivalent for OpenGost Type B: 2.97, 4.13, 5.78, 8.25, 11.55
self.svg.add(self.svg.text(str(round(dimension)), insert=tuple(text_position), **{
'transform': 'rotate({} {} {})'.format(
rotation,
text_position.x,
text_position.y
),
'font-size': '4.13', # 2.5
'font-family': 'OpenGost Type B TT',
'text-anchor': 'middle'
}))
for grid_obj in self.ifc_cutter.grid_objs:
for edge in grid_obj.data.edges:
classes = ['annotation', 'grid']
v0 = grid_obj.data.vertices[edge.vertices[0]].co
v1 = grid_obj.data.vertices[edge.vertices[1]].co
start = Vector(((x_offset + v0.x), (y_offset - v0.y)))
end = Vector(((x_offset + v1.x), (y_offset - v1.y)))
vector = end - start
line = self.svg.add(self.svg.line(start=tuple(start * self.scale),
end=tuple(end * self.scale), class_=' '.join(classes)))
line['marker-start'] = 'url(#grid-marker)'
line['marker-end'] = 'url(#grid-marker)'
line['stroke-dasharray'] = '12.5, 3, 3, 3'
self.svg.add(self.svg.text(grid_obj.name.split('/')[1], insert=tuple(start * self.scale), **{
'font-size': '8.25', # 5
'font-family': 'OpenGost Type B TT',
'text-anchor': 'middle',
'alignment-baseline': 'middle',
'dominant-baseline': 'middle'
}))
self.svg.add(self.svg.text(grid_obj.name.split('/')[1], insert=tuple(end * self.scale), **{
'font-size': '8.25', # 5
'font-family': 'OpenGost Type B TT',
'text-anchor': 'middle',
'alignment-baseline': 'middle',
'dominant-baseline': 'middle'
}))
if self.ifc_cutter.hidden_obj:
for edge in self.ifc_cutter.hidden_obj.data.edges:
classes = ['annotation', 'hidden']
v0 = self.ifc_cutter.hidden_obj.data.vertices[edge.vertices[0]].co
v1 = self.ifc_cutter.hidden_obj.data.vertices[edge.vertices[1]].co
start = Vector(((x_offset + v0.x), (y_offset - v0.y)))
end = Vector(((x_offset + v1.x), (y_offset - v1.y)))
vector = end - start
line = self.svg.add(self.svg.line(start=tuple(start * self.scale),
end=tuple(end * self.scale), class_=' '.join(classes)))
line['stroke-dasharray'] = '3, 2'
if self.ifc_cutter.leader_obj:
for spline in self.ifc_cutter.leader_obj.data.splines:
classes = ['annotation', 'leader']
d = ' '.join(['L {} {}'.format((x_offset + p.co.x) * self.scale, (y_offset - p.co.y) * self.scale) for p in spline.points])
d = 'M{}'.format(d[1:])
path = self.svg.add(self.svg.path(d=d, class_=' '.join(classes)))
path['marker-end'] = 'url(#leader-marker)'
if self.ifc_cutter.stair_obj:
for spline in self.ifc_cutter.stair_obj.data.splines:
classes = ['annotation', 'stair']
d = ' '.join(['L {} {}'.format((x_offset + p.co.x) * self.scale, (y_offset - p.co.y) * self.scale) for p in spline.points])
d = 'M{}'.format(d[1:])
start = Vector(((x_offset + spline.points[0].co.x), (y_offset - spline.points[0].co.y)))
next_point = Vector(((x_offset + spline.points[1].co.x), (y_offset - spline.points[1].co.y)))
text_position = (start * self.scale) - ((next_point - start).normalized() * 5)
path = self.svg.add(self.svg.path(d=d, class_=' '.join(classes)))
path['marker-start'] = 'url(#stair-marker-start)'
path['marker-end'] = 'url(#stair-marker-end)'
self.svg.add(self.svg.text('UP', insert=tuple(text_position), **{
'font-size': '4.13', # 2.5
'font-family': 'OpenGost Type B TT',
'text-anchor': 'middle',
'alignment-baseline': 'middle',
'dominant-baseline': 'middle'
}))
for text_obj in self.ifc_cutter.text_objs:
loc, rot, scale = self.ifc_cutter.camera_obj.matrix_world.decompose()
pos = (text_obj.location - self.ifc_cutter.camera_obj.location) @ rot.to_matrix()
text_position = Vector(((x_offset + pos.x), (y_offset - pos.y)))
if text_obj.data.align_x == 'CENTER':
text_anchor = 'middle'
elif text_obj.data.align_x == 'RIGHT':
text_anchor = 'end'
else:
perpendicular = Vector((vector.y, -vector.x)).normalized()
text_position = (mid * self.scale) + perpendicular
dimension = vector.length * 1000
rotation = -degrees(vector.angle(Vector((1, 0))))
line = self.svg.add(self.svg.line(start=tuple(start * self.scale),
end=tuple(end * self.scale), class_=' '.join(classes)))
line['marker-start'] = 'url(#dimension-marker)'
line['marker-end'] = 'url(#dimension-marker)'
# Standard font sizes 1.8, 2.5, 3.5, 5, 7
# Equivalent for OpenGost Type B: 2.97, 4.13, 5.78, 8.25, 11.55
self.svg.add(self.svg.text(str(round(dimension)), insert=tuple(text_position), **{
'transform': 'rotate({} {} {})'.format(
rotation,
text_position.x,
text_position.y
),
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'
self.svg.add(self.svg.text(text_obj.data.body, insert=tuple(text_position * self.scale), **{
'font-size': '4.13', # 2.5
'font-family': 'OpenGost Type B TT',
'text-anchor': 'middle'
'text-anchor': text_anchor,
'alignment-baseline': alignment_baseline,
'dominant-baseline': alignment_baseline
}))
def draw_cut_polygons(self):
@@ -1,3 +1,5 @@
.cut { fill: black; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; }
.background { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
.annotation { stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
.annotation.leader { fill: none; }
.annotation.stair { fill: none; }
@@ -1,8 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<svg baseProfile="full" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink">
<marker id="dimension-marker" markerHeight="20" markerWidth="20" refX="10" refY="15" orient="auto">
<marker id="dimension-marker" markerHeight="30" markerWidth="20" refX="10" refY="15" orient="auto">
<path d="M 0 15 L 20 15" class="annotation" style="stroke-width:1;" />
<path d="M 10 0 L 10 30" class="annotation" style="stroke-width:1;" />
<path d="M 5 20 L 15 10" class="annotation" style="stroke-width:3;" />
</marker>
<marker id="grid-marker" markerHeight="35" markerWidth="35" orient="auto" refX="17.5" refY="17.5">
<circle cx="17.5" cy="17.5" fill="white" stroke="black" r="15" style="stroke-width: 2"/>
</marker>
<marker id="leader-marker" markerHeight="7" markerWidth="10" orient="auto" refX="10" refY="3.5">
<path d="M 0 0 L 0 7 L 10 3.5" class="annotation" style="fill:black;" />
</marker>
<marker id="stair-marker-start" markerHeight="10" markerWidth="10" orient="auto" refX="5" refY="5">
<circle cx="5" cy="5" fill="black" stroke="none" r="5"/>
</marker>
<marker id="stair-marker-end" markerHeight="42" markerWidth="21" orient="auto" refX="21" refY="21">
<path d="M 0 0 L 21 21 L 0 42" class="annotation stair" style="stroke-width:2" />
</marker>
</svg>

Before

Width:  |  Height:  |  Size: 572 B

After

Width:  |  Height:  |  Size: 1.4 KiB

+21 -3
View File
@@ -788,9 +788,27 @@ class CutSection(bpy.types.Operator):
ifc_cutter.data_dir = bpy.context.scene.BIMProperties.data_dir
ifc_cutter.diagram_name = self.diagram_name
ifc_cutter.background_image = bpy.context.scene.render.filepath
ifc_cutter.annotation_obj = bpy.data.objects['{}-Annotation'.format(
self.diagram_name
)]
ifc_cutter.leader_obj = None
ifc_cutter.stair_obj = None
ifc_cutter.dimension_obj = None
ifc_cutter.hidden_obj = None
ifc_cutter.grid_objs = []
ifc_cutter.text_objs = []
for obj in bpy.context.selected_objects:
if 'Leader' in obj.name:
ifc_cutter.leader_obj = obj
elif 'Stair' in obj.name:
ifc_cutter.stair_obj = obj
elif 'Dimension' in obj.name:
ifc_cutter.dimension_obj = obj
elif 'Hidden' in obj.name:
ifc_cutter.hidden_obj = obj
elif 'IfcGrid' in obj.name:
ifc_cutter.grid_objs.append(obj)
elif obj.type == 'CAMERA':
ifc_cutter.camera_obj = obj
elif obj.type == 'FONT':
ifc_cutter.text_objs.append(obj)
ifc_cutter.section_box = {
'projection': tuple(projection),
'x_axis': tuple(x_axis),