First pass at connecting to new ifcopenshell.draw. See #1153.

This commit is contained in:
Dion Moult
2021-10-27 19:42:36 +11:00
parent 52e8ac386e
commit 2ad2a102cb
3 changed files with 94 additions and 90 deletions
@@ -31,6 +31,7 @@ import ifcopenshell.geom
import ifcopenshell.util.selector
import ifcopenshell.util.representation
import blenderbim.bim.schema
import blenderbim.tool as tool
import blenderbim.bim.module.drawing.svgwriter as svgwriter
import blenderbim.bim.module.drawing.annotation as annotation
import blenderbim.bim.module.drawing.sheeter as sheeter
@@ -146,6 +147,7 @@ class CreateDrawing(bpy.types.Operator):
self.profile_code("Start drawing generation process")
self.props = context.scene.DocProperties
self.drawing_name = self.file.by_id(self.camera.BIMObjectProperties.ifc_definition_id).Name
self.get_scale()
underlay_svg = self.generate_underlay(context)
self.profile_code("Generate underlay")
linework_svg = self.generate_linework(context)
@@ -190,7 +192,7 @@ class CreateDrawing(bpy.types.Operator):
elif "<defs>" in line:
should_skip = True
continue
elif "</style>" in line:
elif "</defs>" in line:
should_skip = False
continue
elif should_skip:
@@ -280,61 +282,35 @@ class CreateDrawing(bpy.types.Operator):
svg_path = os.path.join(context.scene.BIMProperties.data_dir, "cache", self.drawing_name + "-linework.svg")
if os.path.isfile(svg_path) and self.props.should_use_linework_cache:
return svg_path
# This is a work in progress. See #1153 and #1564.
# Switch from old to new if you are testing v0.7.0
self.generate_linework_old(context, svg_path)
# self.generate_linework_new(svg_path)
return svg_path
import ifcopenshell.draw
def generate_linework_new(self, svg_path):
settings = ifcopenshell.geom.settings(
APPLY_DEFAULT_MATERIALS=True,
DISABLE_TRIANGULATION=True,
INCLUDE_CURVES=True,
EXCLUDE_SOLIDS_AND_SURFACES=False,
)
buffer = ifcopenshell.geom.serializers.buffer()
serialiser = ifcopenshell.geom.serializers.svg(buffer, settings)
serialiser.setFile(self.file)
serialiser.setElevationRef("DRAWING")
serialiser.setUseNamespace(True)
serialiser.setAlwaysProject(True)
serialiser.setUseHlrPoly(True)
serialiser.setWithoutStoreys(True)
excluded_elements = []
for ifc_class in ["IfcSpace", "IfcOpeningElement", "IfcDoor", "IfcWindow"]:
excluded_elements += self.file.by_type(ifc_class)
for element in ifcopenshell.geom.iterate(
settings, self.file, multiprocessing.cpu_count(), exclude=excluded_elements
):
serialiser.write(element)
serialiser.finalize()
with open(svg_path, "w") as svg:
svg.write(buffer.get_value())
files = [tool.Ifc.get()]
draw_settings = ifcopenshell.draw.draw_settings()
draw_settings.drawing_guid = tool.Ifc.get_entity(self.camera).GlobalId
draw_settings.css = False
draw_settings.auto_floorplan = False
draw_settings.scale = self.scale
def generate_linework_old(self, context, svg_path):
ifcconvert_path = os.path.join(cwd, "..", "..", "..", "libs", "IfcConvert")
subprocess.run(
[
ifcconvert_path,
context.scene.BIMProperties.ifc_file,
"-yv",
svg_path,
"--plan",
"--model",
"--elevation-ref=DRAWING",
"--svg-xmlns",
"--svg-project",
"--svg-poly",
"--svg-without-storeys",
"--exclude",
"entities",
"IfcSpace",
"IfcOpeningElement",
"IfcDoor",
"IfcWindow",
iterators = []
for f in files:
geom_settings = ifcopenshell.geom.settings(APPLY_DEFAULT_MATERIALS=True, DISABLE_TRIANGULATION=True)
body_contexts = [
c.id()
for c in self.file.by_type("IfcGeometricRepresentationSubContext")
if c.ContextIdentifier in ["Body", "Facetation"]
]
)
if body_contexts:
geom_settings.set_context_ids(body_contexts)
iterators.append(
ifcopenshell.geom.iterator(geom_settings, f, multiprocessing.cpu_count(), exclude=["IfcOpeningElement", "IfcWindow", "IfcDoor"])
)
with open(svg_path, "w") as svg:
results = ifcopenshell.draw.main(draw_settings, files, iterators=iterators, merge_projection=False)
svg.write(str(results))
return svg_path
def generate_annotation(self, context):
@@ -347,17 +323,7 @@ class CreateDrawing(bpy.types.Operator):
camera = self.camera
svg_writer = svgwriter.SvgWriter()
if camera.data.BIMCameraProperties.diagram_scale == "CUSTOM":
human_scale, fraction = camera.data.BIMCameraProperties.custom_diagram_scale.split("|")
else:
human_scale, fraction = camera.data.BIMCameraProperties.diagram_scale.split("|")
numerator, denominator = fraction.split("/")
if camera.data.BIMCameraProperties.is_nts:
svg_writer.human_scale = "NTS"
else:
svg_writer.human_scale = human_scale
svg_writer.human_scale = self.human_scale
drawing_style = context.scene.DocProperties.drawing_styles[
camera.data.BIMCameraProperties.active_drawing_style_index
@@ -371,7 +337,7 @@ class CreateDrawing(bpy.types.Operator):
height = camera.data.ortho_scale
width = height / render.resolution_y * render.resolution_x
svg_writer.scale = float(numerator) / float(denominator)
svg_writer.scale = self.scale
svg_writer.output = svg_path
svg_writer.data_dir = context.scene.BIMProperties.data_dir
svg_writer.vector_style = drawing_style.vector_style
@@ -418,6 +384,19 @@ class CreateDrawing(bpy.types.Operator):
svg_writer.write("annotation")
return svg_writer.output
def get_scale(self):
if self.camera.data.BIMCameraProperties.diagram_scale == "CUSTOM":
self.human_scale, fraction = self.camera.data.BIMCameraProperties.custom_diagram_scale.split("|")
else:
self.human_scale, fraction = self.camera.data.BIMCameraProperties.diagram_scale.split("|")
if self.camera.data.BIMCameraProperties.is_nts:
self.human_scale = "NTS"
numerator, denominator = fraction.split("/")
self.scale = float(numerator) / float(denominator)
def is_landscape(self, render):
return render.resolution_x > render.resolution_y
@@ -787,12 +766,6 @@ class GenerateReferences(bpy.types.Operator):
level_obj = annotation.Annotator.get_annotation_obj("Section Level", "curve", context)
width_in_mm = width * 1000
if self.camera.data.BIMCameraProperties.diagram_scale == "CUSTOM":
human_scale, fraction = self.camera.data.BIMCameraProperties.custom_diagram_scale.split("|")
else:
human_scale, fraction = self.camera.data.BIMCameraProperties.diagram_scale.split("|")
numerator, denominator = fraction.split("/")
scale = float(numerator) / float(denominator)
real_world_width_in_mm = width_in_mm * scale
offset_in_mm = 20
offset_percentage = offset_in_mm / real_world_width_in_mm
@@ -18,6 +18,8 @@
import os
import bpy
import ifcopenshell
import blenderbim.tool as tool
import blenderbim.bim.module.drawing.annotation as annotation
import blenderbim.bim.module.drawing.decoration as decoration
import enum
@@ -53,6 +55,22 @@ def purge():
vector_styles_enum = []
def update_diagram_scale(self, context):
scale = self.diagram_scale
if scale == "CUSTOM":
scale = self.custom_diagram_scale
scale = scale.split("|")[1]
element = tool.Ifc.get_entity(context.scene.camera)
if not element:
return
pset = ifcopenshell.util.element.get_psets(element).get("EPset_Drawing")
if pset:
pset = tool.Ifc.get().by_id(pset["id"])
else:
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=element, name="EPset_Drawing")
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties={"Scale": scale})
def get_diagram_scales(self, context):
global diagram_scales_enum
if (
@@ -294,8 +312,8 @@ class BIMCameraProperties(PropertyGroup):
name="Target View",
default="PLAN_VIEW",
)
diagram_scale: EnumProperty(items=get_diagram_scales, name="Drawing Scale")
custom_diagram_scale: StringProperty(name="Custom Scale")
diagram_scale: EnumProperty(items=get_diagram_scales, name="Drawing Scale", update=update_diagram_scale)
custom_diagram_scale: StringProperty(name="Custom Scale", update=update_diagram_scale)
raster_x: IntProperty(name="Raster X", default=1000)
raster_y: IntProperty(name="Raster Y", default=1000)
is_nts: BoolProperty(name="Is NTS")
+31 -18
View File
@@ -57,23 +57,25 @@ class draw_settings:
storey_heights: str = "none"
include_entities: str = ""
exclude_entities: str = "IfcOpeningElement"
drawing_guid: str = ""
def main(settings, files, progress_function=DO_NOTHING):
iterator_kwargs = {}
if settings.include_entities:
iterator_kwargs["include"] = settings.include_entities.split(",")
elif settings.exclude_entities:
iterator_kwargs["exclude"] = settings.exclude_entities.split(",")
def main(settings, files, iterators=None, merge_projection=True, progress_function=DO_NOTHING):
if not iterators:
iterator_kwargs = {}
if settings.include_entities:
iterator_kwargs["include"] = settings.include_entities.split(",")
elif settings.exclude_entities:
iterator_kwargs["exclude"] = settings.exclude_entities.split(",")
# We have to keep the iterator in memory because otherwise
# the styles are cleared up.
iterators = list(
map(
functools.partial(ifcopenshell.geom.iterator, SETTINGS, **iterator_kwargs),
files,
# We have to keep the iterator in memory because otherwise
# the styles are cleared up.
iterators = list(
map(
functools.partial(ifcopenshell.geom.iterator, SETTINGS, **iterator_kwargs),
files,
)
)
)
def yield_from_iterator(it):
if it.initialize():
@@ -90,6 +92,12 @@ def main(settings, files, progress_function=DO_NOTHING):
if settings.auto_floorplan:
sr.setSectionHeightsFromStoreys()
if settings.drawing_guid:
sr.setElevationRefGuid(settings.drawing_guid)
sr.setWithoutStoreys(True)
# If you want to filter by IfcAnnotation ObjectType named "DRAWING"
#sr.setElevationRef("DRAWING")
# required for svgfill
sr.setPolygonal(True)
sr.setUseNamespace(True)
@@ -105,19 +113,21 @@ def main(settings, files, progress_function=DO_NOTHING):
sr.setPrintSpaceAreas(settings.space_areas)
sr.setDrawDoorArcs(settings.door_arcs)
sr.setNoCSS(not settings.css)
try:
sh = ['none', 'full', 'left'].index(settings.storey_heights)
sr.setDrawStoreyHeights(sh)
except:
raise ValueError("storey_heights should be one of {'none', 'full', 'left'}")
"""
# It is also possible to add drawing planes manually
import bpy
obj = bpy.context.active_object
sr.addDrawing(
obj.matrix_world.transposed()[3][0:3],
-obj.matrix_world.transposed()[2][0:3],
-obj.matrix_world.transposed()[0][0:3],
obj.matrix_world.transposed()[3][0:3], # location
obj.matrix_world.transposed()[2][0:3], # z axis (view direction)
obj.matrix_world.transposed()[0][0:3], # x axis
"Test", # drawing name
True # include projection
)
@@ -143,6 +153,9 @@ def main(settings, files, progress_function=DO_NOTHING):
# Obtain SVG output from serializer buffer
svg_data_1 = buffer.get_value()
if not merge_projection:
return svg_data_1
# Parse SVG into vector of line segments
#
# The second argument 'projection' tells the parser to only include <g> groups