mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
First pass at connecting to new ifcopenshell.draw. See #1153.
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user