mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 19:42:24 +00:00
Proof of concept for IFC construction documentation
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import xml.etree.ElementTree as ET
|
||||
import pystache
|
||||
import ntpath
|
||||
import os
|
||||
|
||||
sheet_path = 'sheets/sheet1.svg'
|
||||
sheet_filename = ntpath.basename(sheet_path)
|
||||
sheet_name = sheet_filename[0:-4]
|
||||
|
||||
# hardcoded for testing
|
||||
data = [
|
||||
{'number': 'ASDF', 'revision': 'A'},
|
||||
{},
|
||||
{'no': '01', 'name': 'HOUSE', 'scale': '1:100'},
|
||||
{},
|
||||
{'no': '02', 'name': 'ELEVATION', 'scale': '1:100'},
|
||||
{},
|
||||
{'no': '03', 'name': 'PLAN', 'scale': '1:100'},
|
||||
{},
|
||||
{'no': '04', 'name': 'SECTION', 'scale': '1:100'},
|
||||
]
|
||||
tree = ET.parse(sheet_path)
|
||||
root = tree.getroot()
|
||||
embedded_svgs = root.findall('{http://www.w3.org/2000/svg}svg')
|
||||
n = 0
|
||||
for svg in embedded_svgs:
|
||||
use = svg.findall('{http://www.w3.org/2000/svg}use')[0]
|
||||
source = use.attrib.get('{http://www.w3.org/1999/xlink}href')
|
||||
source_path = source.split('#')[0]
|
||||
source_filename = ntpath.basename(source_path)
|
||||
source_anchor = source.split('#')[1]
|
||||
dest_filename = '{}-{}.svg'.format(source_filename[0:-4], n)
|
||||
print(dest_filename)
|
||||
os.makedirs('build/refs/{}/'.format(sheet_name), exist_ok=True)
|
||||
with open('build/refs/{}/{}'.format(sheet_name, dest_filename), 'w') as out:
|
||||
with open('sheets/{}'.format(source_path), 'r') as template:
|
||||
out.write(pystache.render(template.read(), data[n]))
|
||||
use.set('{http://www.w3.org/1999/xlink}href',
|
||||
'refs/{}/{}#{}'.format(sheet_name, dest_filename, source_anchor))
|
||||
n += 1
|
||||
|
||||
with open('build/{}'.format(sheet_filename), 'wb') as output:
|
||||
tree.write(output)
|
||||
@@ -0,0 +1,527 @@
|
||||
import os
|
||||
import math
|
||||
import svgwrite
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import OCC.gp
|
||||
import OCC.Geom
|
||||
import OCC.Bnd
|
||||
import OCC.BRepBndLib
|
||||
import OCC.BRep
|
||||
import OCC.BRepPrimAPI
|
||||
import OCC.BRepAlgoAPI
|
||||
import OCC.BRepBuilderAPI
|
||||
import OCC.BRepAlgo
|
||||
import OCC.TopOpeBRepTool
|
||||
import OCC.TopOpeBRepBuild
|
||||
import OCC.ShapeExtend
|
||||
import OCC.GProp
|
||||
import OCC.BRepGProp
|
||||
import OCC.GC
|
||||
import OCC.ShapeAnalysis
|
||||
import OCC.TopTools
|
||||
import OCC.TopExp
|
||||
import OCC.HLRAlgo
|
||||
import OCC.HLRBRep
|
||||
import OCC.TopLoc
|
||||
import OCC.Bnd
|
||||
import OCC.BRepBndLib
|
||||
import OCC.BRepTools
|
||||
import OCC.TopoDS
|
||||
import OCC.GeomLProp
|
||||
|
||||
from OCC.TopoDS import topods
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.geom
|
||||
|
||||
class IfcCutter:
|
||||
def __init__(self):
|
||||
self.product_shapes = []
|
||||
self.background_elements = []
|
||||
self.cut_polygons = []
|
||||
self.ifc_files = []
|
||||
self.unit = None
|
||||
self.section_box = {
|
||||
'top_left_corner': (-3., -2.45, 4.75),
|
||||
'projection': (0., 1., 0.),
|
||||
'x_axis': (1., 0., 0.),
|
||||
'x': 15.,
|
||||
'y': 7.,
|
||||
'z': 3.5,
|
||||
'shape': None,
|
||||
'face': None
|
||||
}
|
||||
|
||||
self.section_box = {
|
||||
'top_left_corner': (-3.097275733947754, 0.42036718130111694, 11.297039031982422),
|
||||
'projection': (0.0, 1.0000001192092896, 0.0),
|
||||
'x_axis': (1.0000001192092896, 0.0, 0.0),
|
||||
'x': 16.4,
|
||||
'y': 16.4,
|
||||
'z': 16.5,
|
||||
'shape': None,
|
||||
'face': None
|
||||
}
|
||||
self.section_box = {
|
||||
'projection': (0.0, 1.0000001192092896, 0.0),
|
||||
#'top_left_corner': (11.5675630569458, -4.225902557373047, 7.368159770965576),
|
||||
'top_left_corner': (11.5675630569458, 0.1, 7.368159770965576),
|
||||
'x_axis': (1.0000001192092896, 0.0, 0.0),
|
||||
'x': 17.4,
|
||||
'y': 8.37,
|
||||
'z': 5.23,
|
||||
'shape': None,
|
||||
'face': None
|
||||
}
|
||||
self.section_box = {
|
||||
'projection': (0.0, 3.2584136988589307e-07, -1.0),
|
||||
'top_left_corner': (12.898375511169434, 31.655664443969727, 2.339174270629883),
|
||||
'x_axis': (1.0, 0.0, 0.0),
|
||||
'x': 17.4,
|
||||
'y': 34.4,
|
||||
'z': 5.23,
|
||||
'shape': None,
|
||||
'face': None
|
||||
}
|
||||
|
||||
def cut(self):
|
||||
start_time = time.time()
|
||||
print('# Load files')
|
||||
self.load_ifc_files()
|
||||
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
||||
start_time = time.time()
|
||||
print('# Get units')
|
||||
self.get_units()
|
||||
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
||||
start_time = time.time()
|
||||
print('# Get product shapes')
|
||||
self.get_product_shapes()
|
||||
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
||||
start_time = time.time()
|
||||
print('# Create section box')
|
||||
self.create_section_box()
|
||||
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
||||
start_time = time.time()
|
||||
print('# Get cut polygons')
|
||||
self.get_cut_polygons()
|
||||
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
||||
start_time = time.time()
|
||||
print('# Get background elements')
|
||||
self.get_background_elements()
|
||||
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
||||
start_time = time.time()
|
||||
print('# Sort background elements')
|
||||
self.sort_background_elements()
|
||||
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
||||
|
||||
def load_ifc_files(self):
|
||||
for filename in Path('ifc/').glob('*.ifc'):
|
||||
print('Loading file {} ...'.format(filename))
|
||||
self.ifc_files.append(ifcopenshell.open(filename))
|
||||
|
||||
def get_units(self):
|
||||
unit_assignment = self.ifc_files[0].by_type('IfcUnitAssignment')[0]
|
||||
for unit in unit_assignment.Units:
|
||||
if unit.UnitType == 'LENGTHUNIT':
|
||||
self.unit = unit
|
||||
break
|
||||
|
||||
def get_product_shapes(self):
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set(settings.USE_PYTHON_OPENCASCADE, True)
|
||||
products = []
|
||||
for ifc_file in self.ifc_files:
|
||||
products.extend(ifc_file.by_type('IfcProduct'))
|
||||
total_products = len(products)
|
||||
for i, product in enumerate(products):
|
||||
print('{}/{} geometry processed ...'.format(i, total_products), end='\r', flush=True)
|
||||
if product.is_a('IfcOpeningElement') or product.is_a('IfcSite'):
|
||||
continue
|
||||
if product.Representation is not None:
|
||||
shape = ifcopenshell.geom.create_shape(settings, product).geometry
|
||||
self.product_shapes.append((product, shape))
|
||||
|
||||
def sort_background_elements(self):
|
||||
new_list = sorted(self.background_elements, key=lambda k: k['z'])
|
||||
self.background_elements = new_list
|
||||
|
||||
def create_section_box(self):
|
||||
top_left_corner = OCC.gp.gp_Pnt(
|
||||
self.section_box['top_left_corner'][0],
|
||||
self.section_box['top_left_corner'][1],
|
||||
self.section_box['top_left_corner'][2])
|
||||
axis = OCC.gp.gp_Ax2(
|
||||
top_left_corner,
|
||||
OCC.gp.gp_Dir(
|
||||
self.section_box['projection'][0],
|
||||
self.section_box['projection'][1],
|
||||
self.section_box['projection'][2]),
|
||||
OCC.gp.gp_Dir(
|
||||
self.section_box['x_axis'][0],
|
||||
self.section_box['x_axis'][1],
|
||||
self.section_box['x_axis'][2])
|
||||
)
|
||||
section_box = OCC.BRepPrimAPI.BRepPrimAPI_MakeBox(
|
||||
axis, self.section_box['x'], self.section_box['y'], self.section_box['z']
|
||||
)
|
||||
self.section_box['shape'] = section_box.Shape()
|
||||
self.section_box['face'] = section_box.BottomFace()
|
||||
|
||||
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))
|
||||
self.transformation = OCC.gp.gp_Trsf()
|
||||
self.transformation.SetDisplacement(source, destination)
|
||||
|
||||
def get_background_elements(self):
|
||||
total_product_shapes = len(self.product_shapes)
|
||||
n = 0
|
||||
for product, shape in self.product_shapes:
|
||||
print('{}/{} background elements processed ...'.format(n, total_product_shapes), end='\r', flush=True)
|
||||
#print('Processing product {} '.format(product.Name))
|
||||
n += 1
|
||||
intersection = OCC.BRepAlgoAPI.BRepAlgoAPI_Common(self.section_box['shape'], shape).Shape()
|
||||
intersection_edges = self.get_booleaned_edges(intersection)
|
||||
if len(intersection_edges) <= 0:
|
||||
continue
|
||||
|
||||
transformed_intersection = OCC.BRepBuilderAPI.BRepBuilderAPI_Transform(
|
||||
intersection, self.transformation)
|
||||
intersection = transformed_intersection.Shape()
|
||||
|
||||
edge_face_map = OCC.TopTools.TopTools_IndexedDataMapOfShapeListOfShape()
|
||||
OCC.TopExp.topexp.MapShapesAndAncestors(
|
||||
intersection, OCC.TopAbs.TopAbs_EDGE,
|
||||
OCC.TopAbs.TopAbs_FACE, edge_face_map)
|
||||
|
||||
exp = OCC.TopExp.TopExp_Explorer(intersection, OCC.TopAbs.TopAbs_FACE)
|
||||
while exp.More():
|
||||
face = topods.Face(exp.Current())
|
||||
zpos, zmax = self.calculate_face_zpos(face)
|
||||
self.build_new_face(face, zpos, product)
|
||||
self.get_split_edges(edge_face_map, face, zmax, product)
|
||||
exp.Next()
|
||||
|
||||
def calculate_face_zpos(self, face):
|
||||
bbox = OCC.Bnd.Bnd_Box()
|
||||
OCC.BRepBndLib.brepbndlib_Add(face, bbox)
|
||||
xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
|
||||
zpos = zmin + ((zmax - zmin)/2)
|
||||
return zpos, zmax
|
||||
|
||||
def get_split_edges(self, edge_face_map, face, zmax, product):
|
||||
exp2 = OCC.TopExp.TopExp_Explorer(face, OCC.TopAbs.TopAbs_EDGE)
|
||||
while exp2.More():
|
||||
edge = topods.Edge(exp2.Current())
|
||||
adjface = OCC.TopoDS.TopoDS_Face()
|
||||
getadj = OCC.TopOpeBRepBuild.TopOpeBRepBuild_Tools.GetAdjacentFace(face, edge, edge_face_map, adjface)
|
||||
if getadj:
|
||||
try:
|
||||
edge_angle = math.degrees(self.get_angle_between_faces(face, adjface))
|
||||
except:
|
||||
# TODO: Figure out when a math domain error might occur,
|
||||
# because it does, sometimes.
|
||||
edge_angle = 0
|
||||
if edge_angle > 30 and edge_angle < 160:
|
||||
newedge = self.build_new_edge(edge, zmax+0.01)
|
||||
if newedge:
|
||||
self.background_elements.append({
|
||||
'raw': product,
|
||||
'geometry': newedge,
|
||||
'type': 'line',
|
||||
'z': zmax+0.01
|
||||
})
|
||||
exp2.Next()
|
||||
|
||||
def get_angle_between_faces(self, f1, f2):
|
||||
return self.convert_dot_product_to_angle(
|
||||
self.get_dot_product_of_normals(
|
||||
self.get_normal(f1), self.get_normal(f2)))
|
||||
|
||||
def get_normal(self, face):
|
||||
surface = OCC.Geom.Handle_Geom_Surface(OCC.BRep.BRep_Tool.Surface(face))
|
||||
props = OCC.GeomLProp.GeomLProp_SLProps(surface, 0, 0, 1, .001)
|
||||
return props.Normal()
|
||||
|
||||
def get_dot_product_of_normals(self, n1, n2):
|
||||
return n1.X() * n2.X() + n1.Y() * n2.Y() + n1.Z() * n2.Z()
|
||||
|
||||
def convert_dot_product_to_angle(self, dp):
|
||||
return math.acos(dp)
|
||||
|
||||
def is_same_point(self, p1, p2):
|
||||
return p1.X() == p2.X() \
|
||||
and p1.Y() == p2.Y() \
|
||||
and p1.Z() == p2.Z()
|
||||
|
||||
def build_new_edge(self, edge, zpos):
|
||||
exp = OCC.TopExp.TopExp_Explorer(edge, OCC.TopAbs.TopAbs_VERTEX)
|
||||
new_vertices = []
|
||||
while exp.More():
|
||||
current_vertex = topods.Vertex(exp.Current())
|
||||
current_point = OCC.BRep.BRep_Tool.Pnt(current_vertex)
|
||||
current_point.SetZ(zpos)
|
||||
new_vertices.append(OCC.BRepBuilderAPI.BRepBuilderAPI_MakeVertex(current_point).Vertex())
|
||||
exp.Next()
|
||||
try:
|
||||
return OCC.BRepBuilderAPI.BRepBuilderAPI_MakeEdge(
|
||||
new_vertices[0], new_vertices[1]
|
||||
).Edge()
|
||||
except:
|
||||
return None
|
||||
|
||||
def build_new_face(self, face, zpos, product):
|
||||
exp = OCC.TopExp.TopExp_Explorer(face, OCC.TopAbs.TopAbs_WIRE)
|
||||
while exp.More():
|
||||
wireexp = OCC.BRepTools.BRepTools_WireExplorer(topods.Wire(exp.Current()))
|
||||
new_wire_builder = OCC.BRepBuilderAPI.BRepBuilderAPI_MakeWire()
|
||||
first_vertex = None
|
||||
previous_vertex = None
|
||||
while wireexp.More():
|
||||
current_vertex = wireexp.CurrentVertex()
|
||||
current_point = OCC.BRep.BRep_Tool.Pnt(current_vertex)
|
||||
# Dodgy technique to squash in Z axis
|
||||
current_point.SetZ(zpos)
|
||||
current_vertex = OCC.BRepBuilderAPI.BRepBuilderAPI_MakeVertex(current_point).Vertex()
|
||||
if not first_vertex:
|
||||
first_vertex = current_vertex
|
||||
if not previous_vertex:
|
||||
previous_vertex = current_vertex
|
||||
else:
|
||||
try:
|
||||
new_wire_builder.Add(topods.Edge(
|
||||
OCC.BRepBuilderAPI.BRepBuilderAPI_MakeEdge(
|
||||
previous_vertex, current_vertex
|
||||
).Edge()))
|
||||
previous_vertex = current_vertex
|
||||
except:
|
||||
pass
|
||||
wireexp.Next()
|
||||
|
||||
# make last edge
|
||||
if not wireexp.More():
|
||||
try:
|
||||
new_wire_builder.Add(topods.Edge(
|
||||
OCC.BRepBuilderAPI.BRepBuilderAPI_MakeEdge(
|
||||
current_vertex, first_vertex
|
||||
).Edge()))
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
new_wire = new_wire_builder.Wire()
|
||||
new_face = OCC.BRepBuilderAPI.BRepBuilderAPI_MakeFace(new_wire).Face()
|
||||
area = self.get_area(new_face)
|
||||
if area == 0:
|
||||
self.background_elements.append({
|
||||
'raw': product,
|
||||
'geometry': new_wire,
|
||||
'geometry_face': new_face,
|
||||
'type': 'polyline',
|
||||
'z': zpos
|
||||
})
|
||||
else:
|
||||
self.background_elements.append({
|
||||
'raw': product,
|
||||
'geometry': new_wire,
|
||||
'geometry_face': new_face,
|
||||
'type': 'polygon',
|
||||
'z': zpos
|
||||
})
|
||||
except:
|
||||
#print('Could not build face')
|
||||
pass
|
||||
exp.Next()
|
||||
|
||||
def get_area(self, shape):
|
||||
gprops = OCC.GProp.GProp_GProps()
|
||||
OCC.BRepGProp.brepgprop.SurfaceProperties(shape, gprops)
|
||||
return gprops.Mass()
|
||||
|
||||
def get_booleaned_edges(self, 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 get_cut_polygons(self):
|
||||
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)
|
||||
|
||||
transformed_wire = OCC.BRepBuilderAPI.BRepBuilderAPI_Transform(
|
||||
wire_shape, self.transformation)
|
||||
wire_shape = transformed_wire.Shape()
|
||||
|
||||
wire = topods.Wire(wire_shape)
|
||||
|
||||
self.cut_polygons.append({
|
||||
'raw': product,
|
||||
'geometry': wire
|
||||
})
|
||||
|
||||
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):
|
||||
self.occ_display = ifcopenshell.geom.utils.initialize_display()
|
||||
super().cut()
|
||||
|
||||
def create_section_box(self):
|
||||
super().create_section_box()
|
||||
self.display_everything_with_section_plane()
|
||||
|
||||
def get_cut_polygons(self):
|
||||
super().get_cut_polygons()
|
||||
self.display_cut_polygons()
|
||||
|
||||
def get_background_elements(self):
|
||||
super().get_background_elements()
|
||||
self.display_background_elements()
|
||||
|
||||
def display_everything_with_section_plane(self):
|
||||
section_face_display = ifcopenshell.geom.utils.display_shape(self.section_box['face'])
|
||||
ifcopenshell.geom.utils.set_shape_transparency(section_face_display, 0.8)
|
||||
section_box_display = ifcopenshell.geom.utils.display_shape(self.section_box['shape'])
|
||||
ifcopenshell.geom.utils.set_shape_transparency(section_box_display, 0.5)
|
||||
|
||||
transformed_box = OCC.BRepBuilderAPI.BRepBuilderAPI_Transform(
|
||||
self.section_box['shape'], self.transformation)
|
||||
box_display = ifcopenshell.geom.utils.display_shape(transformed_box.Shape())
|
||||
ifcopenshell.geom.utils.set_shape_transparency(box_display, 0.2)
|
||||
|
||||
for shape in self.product_shapes:
|
||||
ifcopenshell.geom.utils.display_shape(shape[1])
|
||||
input('Debug: showing everything with section plane.')
|
||||
|
||||
def display_cut_polygons(self):
|
||||
self.occ_display.EraseAll()
|
||||
for polygon in self.cut_polygons:
|
||||
ifcopenshell.geom.utils.display_shape(polygon['geometry'], clr='BLACK')
|
||||
face = OCC.BRepBuilderAPI.BRepBuilderAPI_MakeFace(polygon['geometry']).Face()
|
||||
face_display = ifcopenshell.geom.utils.display_shape(face)
|
||||
ifcopenshell.geom.utils.set_shape_transparency(face_display, 0.5)
|
||||
input('Debug: showing cut polygons.')
|
||||
|
||||
def display_background_elements(self):
|
||||
self.occ_display.EraseAll()
|
||||
for element in self.background_elements:
|
||||
if element['type'] == 'line':
|
||||
ifcopenshell.geom.utils.display_shape(element['geometry'], clr='PURPLE')
|
||||
elif element['type'] == 'polyline':
|
||||
ifcopenshell.geom.utils.display_shape(element['geometry_face'], clr='RED')
|
||||
elif element['type'] == 'polygon':
|
||||
ifcopenshell.geom.utils.display_shape(element['geometry_face'])
|
||||
input('Debug: showing background elements.')
|
||||
|
||||
class SvgWriter():
|
||||
def __init__(self, ifc_cutter):
|
||||
self.ifc_cutter = ifc_cutter
|
||||
self.scale = 1 / 100 # 1:100
|
||||
|
||||
def write(self):
|
||||
self.calculate_scale()
|
||||
self.svg = svgwrite.Drawing('output.svg',
|
||||
debug=False,
|
||||
size=('{}mm'.format(self.ifc_cutter.section_box['x'] * self.scale),
|
||||
'{}mm'.format(self.ifc_cutter.section_box['y'] * self.scale)),
|
||||
viewBox=('0 0 {} {}'.format(
|
||||
self.ifc_cutter.section_box['x'] * self.scale,
|
||||
self.ifc_cutter.section_box['y'] * self.scale)))
|
||||
self.add_stylesheet()
|
||||
self.draw_background_elements()
|
||||
self.draw_cut_polygons()
|
||||
self.svg.save(pretty=True)
|
||||
|
||||
def calculate_scale(self):
|
||||
# TODO: properly handle units
|
||||
if self.ifc_cutter.unit.Name == 'METRE':
|
||||
self.scale *= 1000
|
||||
|
||||
def add_stylesheet(self):
|
||||
with open('styles/default.css', 'r') as stylesheet:
|
||||
self.svg.defs.add(self.svg.style(stylesheet.read()))
|
||||
|
||||
def draw_background_elements(self):
|
||||
for element in self.ifc_cutter.background_elements:
|
||||
if element['type'] == 'polygon':
|
||||
self.draw_polygon(element, 'background')
|
||||
elif element['type'] == 'polyline':
|
||||
self.draw_polyline(element, 'background')
|
||||
elif element['type'] == 'line':
|
||||
self.draw_line(element, 'background')
|
||||
|
||||
def draw_cut_polygons(self):
|
||||
for polygon in self.ifc_cutter.cut_polygons:
|
||||
self.draw_polygon(polygon, 'cut')
|
||||
|
||||
def draw_polyline(self, element, position):
|
||||
classes = self.get_classes(element['raw'], position)
|
||||
exp = OCC.BRepTools.BRepTools_WireExplorer(element['geometry'])
|
||||
points = []
|
||||
while exp.More():
|
||||
point = OCC.BRep.BRep_Tool.Pnt(exp.CurrentVertex())
|
||||
points.append((point.X() * self.scale, -point.Y() * self.scale))
|
||||
exp.Next()
|
||||
self.svg.add(self.svg.polyline(points=points, class_=' '.join(classes)))
|
||||
|
||||
def draw_line(self, element, position):
|
||||
classes = self.get_classes(element['raw'], position)
|
||||
exp = OCC.TopExp.TopExp_Explorer(element['geometry'], OCC.TopAbs.TopAbs_VERTEX)
|
||||
points = []
|
||||
while exp.More():
|
||||
point = OCC.BRep.BRep_Tool.Pnt(topods.Vertex(exp.Current()))
|
||||
points.append((point.X() * self.scale, -point.Y() * self.scale))
|
||||
exp.Next()
|
||||
self.svg.add(self.svg.line(start=points[0], end=points[1], class_=' '.join(classes)))
|
||||
|
||||
def draw_polygon(self, polygon, position):
|
||||
classes = self.get_classes(polygon['raw'], position)
|
||||
exp = OCC.BRepTools.BRepTools_WireExplorer(polygon['geometry'])
|
||||
points = []
|
||||
while exp.More():
|
||||
point = OCC.BRep.BRep_Tool.Pnt(exp.CurrentVertex())
|
||||
points.append((point.X() * self.scale, -point.Y() * self.scale))
|
||||
exp.Next()
|
||||
self.svg.add(self.svg.polygon(points=points, class_=' '.join(classes)))
|
||||
|
||||
def get_classes(self, element, position):
|
||||
classes = [position, element.is_a()]
|
||||
for association in element.HasAssociations:
|
||||
if association.is_a('IfcRelAssociatesMaterial'):
|
||||
classes.append('material-{}'.format(association.RelatingMaterial.Name))
|
||||
classes.append('globalid-{}'.format(element.GlobalId))
|
||||
return classes
|
||||
|
||||
print('# Starting process')
|
||||
ifc_cutter = IfcCutter()
|
||||
#ifc_cutter = IfcCutterDebug()
|
||||
svg_writer = SvgWriter(ifc_cutter)
|
||||
ifc_cutter.cut()
|
||||
start_time = time.time()
|
||||
svg_writer.write()
|
||||
print('# SVG writing finished in {:.2f} seconds'.format(time.time() - start_time))
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" height="594mm" width="841mm">
|
||||
<defs />
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<use xlink:href="../templates/titleblock.svg#root" />
|
||||
</svg>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="150mm" y="50mm">
|
||||
<use xlink:href="../views/house.svg#root" />
|
||||
</svg>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="150mm" y="50mm">
|
||||
<use xlink:href="../templates/view-title.svg#root" />
|
||||
</svg>
|
||||
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="550mm" y="50mm">
|
||||
<use xlink:href="../views/elevation.svg#root" />
|
||||
</svg>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="150mm" y="50mm">
|
||||
<use xlink:href="../templates/view-title.svg#root" />
|
||||
</svg>
|
||||
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="550mm" y="50mm">
|
||||
<use xlink:href="../views/plan.svg#root" />
|
||||
</svg>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="150mm" y="50mm">
|
||||
<use xlink:href="../templates/view-title.svg#root" />
|
||||
</svg>
|
||||
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="550mm" y="50mm">
|
||||
<use xlink:href="../views/section.svg#root" />
|
||||
</svg>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="150mm" y="50mm">
|
||||
<use xlink:href="../templates/view-title.svg#root" />
|
||||
</svg>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,2 @@
|
||||
.cut {fill: black; stroke: black; stroke-linecap: 'round'; stroke-width: 0.3px; }
|
||||
.background { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.05px; }
|
||||
File diff suppressed because it is too large
Load Diff
|
After Width: | Height: | Size: 108 KiB |
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="root"
|
||||
version="1.1"
|
||||
viewBox="0 0 50.222462 10"
|
||||
height="10mm"
|
||||
width="50.222462mm">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(-27.82024,-96.649986)"
|
||||
id="layer1">
|
||||
<circle
|
||||
r="4.8499999"
|
||||
cy="101.64999"
|
||||
cx="32.82024"
|
||||
id="path853"
|
||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.30000001;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path855"
|
||||
d="m 37.67024,101.64999 40.37246,-1e-5"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<text
|
||||
id="text859"
|
||||
y="102.19775"
|
||||
x="32.820755"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:2.11666656px;text-align:center;text-anchor:middle;stroke-width:0.26458332px"
|
||||
y="102.19775"
|
||||
x="32.820755"
|
||||
id="tspan857">{{no}}</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="39.368858"
|
||||
y="99.525047"
|
||||
id="text863"><tspan
|
||||
id="tspan861"
|
||||
x="39.368858"
|
||||
y="99.525047"
|
||||
style="font-size:2.11666656px;text-align:start;text-anchor:start;stroke-width:0.26458332px">{{name}}</tspan></text>
|
||||
<text
|
||||
id="text867"
|
||||
y="104.66998"
|
||||
x="39.368858"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:2.11666656px;text-align:start;text-anchor:start;stroke-width:0.26458332px"
|
||||
y="104.66998"
|
||||
x="39.368858"
|
||||
id="tspan865">{{scale}}</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
Reference in New Issue
Block a user