mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-12 14:33:28 +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.selector
|
||||||
import ifcopenshell.util.representation
|
import ifcopenshell.util.representation
|
||||||
import blenderbim.bim.schema
|
import blenderbim.bim.schema
|
||||||
|
import blenderbim.tool as tool
|
||||||
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
|
||||||
@@ -146,6 +147,7 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
self.profile_code("Start drawing generation process")
|
self.profile_code("Start drawing generation process")
|
||||||
self.props = context.scene.DocProperties
|
self.props = context.scene.DocProperties
|
||||||
self.drawing_name = self.file.by_id(self.camera.BIMObjectProperties.ifc_definition_id).Name
|
self.drawing_name = self.file.by_id(self.camera.BIMObjectProperties.ifc_definition_id).Name
|
||||||
|
self.get_scale()
|
||||||
underlay_svg = self.generate_underlay(context)
|
underlay_svg = self.generate_underlay(context)
|
||||||
self.profile_code("Generate underlay")
|
self.profile_code("Generate underlay")
|
||||||
linework_svg = self.generate_linework(context)
|
linework_svg = self.generate_linework(context)
|
||||||
@@ -190,7 +192,7 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
elif "<defs>" in line:
|
elif "<defs>" in line:
|
||||||
should_skip = True
|
should_skip = True
|
||||||
continue
|
continue
|
||||||
elif "</style>" in line:
|
elif "</defs>" in line:
|
||||||
should_skip = False
|
should_skip = False
|
||||||
continue
|
continue
|
||||||
elif should_skip:
|
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")
|
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:
|
if os.path.isfile(svg_path) and self.props.should_use_linework_cache:
|
||||||
return svg_path
|
return svg_path
|
||||||
|
|
||||||
# This is a work in progress. See #1153 and #1564.
|
# This is a work in progress. See #1153 and #1564.
|
||||||
# Switch from old to new if you are testing v0.7.0
|
import ifcopenshell.draw
|
||||||
self.generate_linework_old(context, svg_path)
|
|
||||||
# self.generate_linework_new(svg_path)
|
|
||||||
return svg_path
|
|
||||||
|
|
||||||
def generate_linework_new(self, svg_path):
|
files = [tool.Ifc.get()]
|
||||||
settings = ifcopenshell.geom.settings(
|
draw_settings = ifcopenshell.draw.draw_settings()
|
||||||
APPLY_DEFAULT_MATERIALS=True,
|
draw_settings.drawing_guid = tool.Ifc.get_entity(self.camera).GlobalId
|
||||||
DISABLE_TRIANGULATION=True,
|
draw_settings.css = False
|
||||||
INCLUDE_CURVES=True,
|
draw_settings.auto_floorplan = False
|
||||||
EXCLUDE_SOLIDS_AND_SURFACES=False,
|
draw_settings.scale = self.scale
|
||||||
)
|
|
||||||
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())
|
|
||||||
|
|
||||||
def generate_linework_old(self, context, svg_path):
|
iterators = []
|
||||||
ifcconvert_path = os.path.join(cwd, "..", "..", "..", "libs", "IfcConvert")
|
for f in files:
|
||||||
subprocess.run(
|
geom_settings = ifcopenshell.geom.settings(APPLY_DEFAULT_MATERIALS=True, DISABLE_TRIANGULATION=True)
|
||||||
[
|
body_contexts = [
|
||||||
ifcconvert_path,
|
c.id()
|
||||||
context.scene.BIMProperties.ifc_file,
|
for c in self.file.by_type("IfcGeometricRepresentationSubContext")
|
||||||
"-yv",
|
if c.ContextIdentifier in ["Body", "Facetation"]
|
||||||
svg_path,
|
|
||||||
"--plan",
|
|
||||||
"--model",
|
|
||||||
"--elevation-ref=DRAWING",
|
|
||||||
"--svg-xmlns",
|
|
||||||
"--svg-project",
|
|
||||||
"--svg-poly",
|
|
||||||
"--svg-without-storeys",
|
|
||||||
"--exclude",
|
|
||||||
"entities",
|
|
||||||
"IfcSpace",
|
|
||||||
"IfcOpeningElement",
|
|
||||||
"IfcDoor",
|
|
||||||
"IfcWindow",
|
|
||||||
]
|
]
|
||||||
)
|
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
|
return svg_path
|
||||||
|
|
||||||
def generate_annotation(self, context):
|
def generate_annotation(self, context):
|
||||||
@@ -347,17 +323,7 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
camera = self.camera
|
camera = self.camera
|
||||||
svg_writer = svgwriter.SvgWriter()
|
svg_writer = svgwriter.SvgWriter()
|
||||||
|
|
||||||
if camera.data.BIMCameraProperties.diagram_scale == "CUSTOM":
|
svg_writer.human_scale = self.human_scale
|
||||||
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
|
|
||||||
|
|
||||||
drawing_style = context.scene.DocProperties.drawing_styles[
|
drawing_style = context.scene.DocProperties.drawing_styles[
|
||||||
camera.data.BIMCameraProperties.active_drawing_style_index
|
camera.data.BIMCameraProperties.active_drawing_style_index
|
||||||
@@ -371,7 +337,7 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
height = camera.data.ortho_scale
|
height = camera.data.ortho_scale
|
||||||
width = height / render.resolution_y * render.resolution_x
|
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.output = svg_path
|
||||||
svg_writer.data_dir = context.scene.BIMProperties.data_dir
|
svg_writer.data_dir = context.scene.BIMProperties.data_dir
|
||||||
svg_writer.vector_style = drawing_style.vector_style
|
svg_writer.vector_style = drawing_style.vector_style
|
||||||
@@ -418,6 +384,19 @@ class CreateDrawing(bpy.types.Operator):
|
|||||||
svg_writer.write("annotation")
|
svg_writer.write("annotation")
|
||||||
return svg_writer.output
|
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):
|
def is_landscape(self, render):
|
||||||
return render.resolution_x > render.resolution_y
|
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)
|
level_obj = annotation.Annotator.get_annotation_obj("Section Level", "curve", context)
|
||||||
|
|
||||||
width_in_mm = width * 1000
|
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
|
real_world_width_in_mm = width_in_mm * scale
|
||||||
offset_in_mm = 20
|
offset_in_mm = 20
|
||||||
offset_percentage = offset_in_mm / real_world_width_in_mm
|
offset_percentage = offset_in_mm / real_world_width_in_mm
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import bpy
|
import bpy
|
||||||
|
import ifcopenshell
|
||||||
|
import blenderbim.tool as tool
|
||||||
import blenderbim.bim.module.drawing.annotation as annotation
|
import blenderbim.bim.module.drawing.annotation as annotation
|
||||||
import blenderbim.bim.module.drawing.decoration as decoration
|
import blenderbim.bim.module.drawing.decoration as decoration
|
||||||
import enum
|
import enum
|
||||||
@@ -53,6 +55,22 @@ def purge():
|
|||||||
vector_styles_enum = []
|
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):
|
def get_diagram_scales(self, context):
|
||||||
global diagram_scales_enum
|
global diagram_scales_enum
|
||||||
if (
|
if (
|
||||||
@@ -294,8 +312,8 @@ class BIMCameraProperties(PropertyGroup):
|
|||||||
name="Target View",
|
name="Target View",
|
||||||
default="PLAN_VIEW",
|
default="PLAN_VIEW",
|
||||||
)
|
)
|
||||||
diagram_scale: EnumProperty(items=get_diagram_scales, name="Drawing Scale")
|
diagram_scale: EnumProperty(items=get_diagram_scales, name="Drawing Scale", update=update_diagram_scale)
|
||||||
custom_diagram_scale: StringProperty(name="Custom Scale")
|
custom_diagram_scale: StringProperty(name="Custom Scale", update=update_diagram_scale)
|
||||||
raster_x: IntProperty(name="Raster X", default=1000)
|
raster_x: IntProperty(name="Raster X", default=1000)
|
||||||
raster_y: IntProperty(name="Raster Y", default=1000)
|
raster_y: IntProperty(name="Raster Y", default=1000)
|
||||||
is_nts: BoolProperty(name="Is NTS")
|
is_nts: BoolProperty(name="Is NTS")
|
||||||
|
|||||||
@@ -57,23 +57,25 @@ class draw_settings:
|
|||||||
storey_heights: str = "none"
|
storey_heights: str = "none"
|
||||||
include_entities: str = ""
|
include_entities: str = ""
|
||||||
exclude_entities: str = "IfcOpeningElement"
|
exclude_entities: str = "IfcOpeningElement"
|
||||||
|
drawing_guid: str = ""
|
||||||
|
|
||||||
|
|
||||||
def main(settings, files, progress_function=DO_NOTHING):
|
def main(settings, files, iterators=None, merge_projection=True, progress_function=DO_NOTHING):
|
||||||
iterator_kwargs = {}
|
if not iterators:
|
||||||
if settings.include_entities:
|
iterator_kwargs = {}
|
||||||
iterator_kwargs["include"] = settings.include_entities.split(",")
|
if settings.include_entities:
|
||||||
elif settings.exclude_entities:
|
iterator_kwargs["include"] = settings.include_entities.split(",")
|
||||||
iterator_kwargs["exclude"] = settings.exclude_entities.split(",")
|
elif settings.exclude_entities:
|
||||||
|
iterator_kwargs["exclude"] = settings.exclude_entities.split(",")
|
||||||
|
|
||||||
# We have to keep the iterator in memory because otherwise
|
# We have to keep the iterator in memory because otherwise
|
||||||
# the styles are cleared up.
|
# the styles are cleared up.
|
||||||
iterators = list(
|
iterators = list(
|
||||||
map(
|
map(
|
||||||
functools.partial(ifcopenshell.geom.iterator, SETTINGS, **iterator_kwargs),
|
functools.partial(ifcopenshell.geom.iterator, SETTINGS, **iterator_kwargs),
|
||||||
files,
|
files,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
def yield_from_iterator(it):
|
def yield_from_iterator(it):
|
||||||
if it.initialize():
|
if it.initialize():
|
||||||
@@ -90,6 +92,12 @@ def main(settings, files, progress_function=DO_NOTHING):
|
|||||||
if settings.auto_floorplan:
|
if settings.auto_floorplan:
|
||||||
sr.setSectionHeightsFromStoreys()
|
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
|
# required for svgfill
|
||||||
sr.setPolygonal(True)
|
sr.setPolygonal(True)
|
||||||
sr.setUseNamespace(True)
|
sr.setUseNamespace(True)
|
||||||
@@ -114,10 +122,12 @@ def main(settings, files, progress_function=DO_NOTHING):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
# It is also possible to add drawing planes manually
|
# It is also possible to add drawing planes manually
|
||||||
|
import bpy
|
||||||
|
obj = bpy.context.active_object
|
||||||
sr.addDrawing(
|
sr.addDrawing(
|
||||||
obj.matrix_world.transposed()[3][0:3],
|
obj.matrix_world.transposed()[3][0:3], # location
|
||||||
-obj.matrix_world.transposed()[2][0:3],
|
obj.matrix_world.transposed()[2][0:3], # z axis (view direction)
|
||||||
-obj.matrix_world.transposed()[0][0:3],
|
obj.matrix_world.transposed()[0][0:3], # x axis
|
||||||
"Test", # drawing name
|
"Test", # drawing name
|
||||||
True # include projection
|
True # include projection
|
||||||
)
|
)
|
||||||
@@ -143,6 +153,9 @@ def main(settings, files, progress_function=DO_NOTHING):
|
|||||||
# Obtain SVG output from serializer buffer
|
# Obtain SVG output from serializer buffer
|
||||||
svg_data_1 = buffer.get_value()
|
svg_data_1 = buffer.get_value()
|
||||||
|
|
||||||
|
if not merge_projection:
|
||||||
|
return svg_data_1
|
||||||
|
|
||||||
# Parse SVG into vector of line segments
|
# Parse SVG into vector of line segments
|
||||||
#
|
#
|
||||||
# The second argument 'projection' tells the parser to only include <g> groups
|
# The second argument 'projection' tells the parser to only include <g> groups
|
||||||
|
|||||||
Reference in New Issue
Block a user