mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-20 15:08:51 +00:00
Experimental code to merge background faces in a section cut
This commit is contained in:
@@ -2,6 +2,7 @@ import os
|
|||||||
import math
|
import math
|
||||||
import svgwrite
|
import svgwrite
|
||||||
import time
|
import time
|
||||||
|
import numpy
|
||||||
import pickle
|
import pickle
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -13,7 +14,6 @@ import OCC.BRep
|
|||||||
import OCC.BRepPrimAPI
|
import OCC.BRepPrimAPI
|
||||||
import OCC.BRepAlgoAPI
|
import OCC.BRepAlgoAPI
|
||||||
import OCC.BRepBuilderAPI
|
import OCC.BRepBuilderAPI
|
||||||
import OCC.BRepAlgo
|
|
||||||
import OCC.TopOpeBRepTool
|
import OCC.TopOpeBRepTool
|
||||||
import OCC.TopOpeBRepBuild
|
import OCC.TopOpeBRepBuild
|
||||||
import OCC.ShapeExtend
|
import OCC.ShapeExtend
|
||||||
@@ -31,6 +31,7 @@ import OCC.BRepBndLib
|
|||||||
import OCC.BRepTools
|
import OCC.BRepTools
|
||||||
import OCC.TopoDS
|
import OCC.TopoDS
|
||||||
import OCC.GeomLProp
|
import OCC.GeomLProp
|
||||||
|
import OCC.IntCurvesFace
|
||||||
|
|
||||||
from OCC.TopoDS import topods
|
from OCC.TopoDS import topods
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ class IfcCutter:
|
|||||||
self.cut_polygons = []
|
self.cut_polygons = []
|
||||||
self.ifc_files = []
|
self.ifc_files = []
|
||||||
self.unit = None
|
self.unit = None
|
||||||
|
self.resolved_pixels = set()
|
||||||
self.section_box = {
|
self.section_box = {
|
||||||
'top_left_corner': (-3., -2.45, 4.75),
|
'top_left_corner': (-3., -2.45, 4.75),
|
||||||
'projection': (0., 1., 0.),
|
'projection': (0., 1., 0.),
|
||||||
@@ -82,7 +84,18 @@ class IfcCutter:
|
|||||||
'x_axis': (1.0, 0.0, 0.0),
|
'x_axis': (1.0, 0.0, 0.0),
|
||||||
'x': 17.4,
|
'x': 17.4,
|
||||||
'y': 34.4,
|
'y': 34.4,
|
||||||
'z': 5.23,
|
'z': 1.9,
|
||||||
|
'shape': None,
|
||||||
|
'face': None
|
||||||
|
}
|
||||||
|
self.section_boxno = {
|
||||||
|
'projection': (0, 1, 0),
|
||||||
|
'x_axis': (1, 0, 0),
|
||||||
|
'y_axis': (0, 0, -1),
|
||||||
|
'top_left_corner': (-2, 2, 8),
|
||||||
|
'x': 14,
|
||||||
|
'y': 9,
|
||||||
|
'z': 2,
|
||||||
'shape': None,
|
'shape': None,
|
||||||
'face': None
|
'face': None
|
||||||
}
|
}
|
||||||
@@ -114,6 +127,14 @@ class IfcCutter:
|
|||||||
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
print('# Sort background elements')
|
print('# Sort background elements')
|
||||||
|
self.sort_background_elements(reverse=True)
|
||||||
|
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
||||||
|
start_time = time.time()
|
||||||
|
print('# Merge background_elements')
|
||||||
|
self.merge_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()
|
self.sort_background_elements()
|
||||||
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
print('# Timer logged at {:.2f} seconds'.format(time.time() - start_time))
|
||||||
|
|
||||||
@@ -158,10 +179,104 @@ class IfcCutter:
|
|||||||
with open('shapes.pickle', 'wb') as shape_file:
|
with open('shapes.pickle', 'wb') as shape_file:
|
||||||
pickle.dump(shape_map, shape_file, protocol=pickle.HIGHEST_PROTOCOL)
|
pickle.dump(shape_map, shape_file, protocol=pickle.HIGHEST_PROTOCOL)
|
||||||
|
|
||||||
def sort_background_elements(self):
|
def sort_background_elements(self, reverse=None):
|
||||||
new_list = sorted(self.background_elements, key=lambda k: k['z'])
|
if reverse:
|
||||||
|
new_list = sorted(self.background_elements, key=lambda k: -k['z'])
|
||||||
|
else:
|
||||||
|
new_list = sorted(self.background_elements, key=lambda k: k['z'])
|
||||||
self.background_elements = new_list
|
self.background_elements = new_list
|
||||||
|
|
||||||
|
def process_grid(self, face, resolution):
|
||||||
|
try:
|
||||||
|
bbox = self.get_bbox(face)
|
||||||
|
xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
current_x = 0
|
||||||
|
current_y = 0
|
||||||
|
is_visible = False
|
||||||
|
while current_x < self.section_box['x']:
|
||||||
|
current_y = 0
|
||||||
|
while current_y > -self.section_box['y']:
|
||||||
|
if current_x < xmin \
|
||||||
|
or current_x > xmax \
|
||||||
|
or current_y < ymin \
|
||||||
|
or current_y > ymax:
|
||||||
|
current_y -= resolution
|
||||||
|
continue
|
||||||
|
if (current_x, current_y) in self.resolved_pixels:
|
||||||
|
current_y -= resolution
|
||||||
|
continue
|
||||||
|
point = numpy.array((current_x, current_y, 0))
|
||||||
|
hit = self.raycast(face, point)
|
||||||
|
if hit:
|
||||||
|
is_visible = True
|
||||||
|
self.resolved_pixels.add((current_x, current_y))
|
||||||
|
current_y -= resolution
|
||||||
|
current_x += resolution
|
||||||
|
return is_visible
|
||||||
|
|
||||||
|
def merge_background_elements(self):
|
||||||
|
background_elements = []
|
||||||
|
|
||||||
|
resolution = 0.1 # 10cm
|
||||||
|
|
||||||
|
# DO CUT
|
||||||
|
total_product_shapes = len(self.cut_polygons)
|
||||||
|
n = 0
|
||||||
|
for element in self.cut_polygons:
|
||||||
|
#print('{}/{} background elements processed ...'.format(n, total_product_shapes), end='\r', flush=True)
|
||||||
|
print('{}/{} cut polygons processed ...'.format(n, total_product_shapes))
|
||||||
|
print('{} resolved pixels'.format(len(self.resolved_pixels)))
|
||||||
|
n += 1
|
||||||
|
self.process_grid(element['geometry_face'], resolution)
|
||||||
|
|
||||||
|
# DO BACKGROUND
|
||||||
|
total_product_shapes = len(self.background_elements)
|
||||||
|
n = 0
|
||||||
|
for element in self.background_elements:
|
||||||
|
#print('{}/{} background elements processed ...'.format(n, total_product_shapes), end='\r', flush=True)
|
||||||
|
print('{}/{} background elements processed ...'.format(n, total_product_shapes))
|
||||||
|
print('{} resolved pixels'.format(len(self.resolved_pixels)))
|
||||||
|
n += 1
|
||||||
|
if element['type'] != 'polygon':
|
||||||
|
background_elements.append(element)
|
||||||
|
continue
|
||||||
|
is_visible = self.process_grid(element['geometry_face'], resolution)
|
||||||
|
if is_visible:
|
||||||
|
background_elements.append(element)
|
||||||
|
|
||||||
|
print('##### BEFORE it had {} and after it had {}'.format(
|
||||||
|
len(self.background_elements), len(background_elements)))
|
||||||
|
self.background_elements = background_elements
|
||||||
|
|
||||||
|
return
|
||||||
|
# my previous attempt
|
||||||
|
fused_elements = []
|
||||||
|
previous_element = None
|
||||||
|
for element in self.background_elements:
|
||||||
|
if previous_element is None:
|
||||||
|
previous_element = element
|
||||||
|
continue
|
||||||
|
if element['type'] == previous_element['type'] \
|
||||||
|
and element['raw'].GlobalId == previous_element['raw'].GlobalId \
|
||||||
|
and element['type'] == 'polygon':
|
||||||
|
fuse = OCC.BRepAlgoAPI.BRepAlgoAPI_Fuse(
|
||||||
|
previous_element['geometry'], element['geometry']).Shape()
|
||||||
|
print('FUSING')
|
||||||
|
exp = OCC.TopExp.TopExp_Explorer(fuse, OCC.TopAbs.TopAbs_WIRE)
|
||||||
|
previous_element = {
|
||||||
|
'raw': element['raw'],
|
||||||
|
'geometry': exp.Current(),
|
||||||
|
'geometry_face': fuse,
|
||||||
|
'type': 'polygon',
|
||||||
|
'z': element['z']
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
fused_elements.append(element)
|
||||||
|
#print(element)
|
||||||
|
self.background_elements = fused_elements
|
||||||
|
|
||||||
def create_section_box(self):
|
def create_section_box(self):
|
||||||
top_left_corner = OCC.gp.gp_Pnt(
|
top_left_corner = OCC.gp.gp_Pnt(
|
||||||
self.section_box['top_left_corner'][0],
|
self.section_box['top_left_corner'][0],
|
||||||
@@ -195,14 +310,22 @@ class IfcCutter:
|
|||||||
def get_background_elements(self):
|
def get_background_elements(self):
|
||||||
total_product_shapes = len(self.product_shapes)
|
total_product_shapes = len(self.product_shapes)
|
||||||
n = 0
|
n = 0
|
||||||
|
intersections = []
|
||||||
|
compound = OCC.TopoDS.TopoDS_Compound()
|
||||||
|
builder = OCC.BRep.BRep_Builder()
|
||||||
|
builder.MakeCompound(compound)
|
||||||
for product, shape in self.product_shapes:
|
for product, shape in self.product_shapes:
|
||||||
|
builder.Add(compound, shape)
|
||||||
|
|
||||||
print('{}/{} background elements processed ...'.format(n, total_product_shapes), end='\r', flush=True)
|
print('{}/{} background elements processed ...'.format(n, total_product_shapes), end='\r', flush=True)
|
||||||
#print('Processing product {} '.format(product.Name))
|
#print('Processing product {} '.format(product.Name))
|
||||||
n += 1
|
n += 1
|
||||||
|
|
||||||
intersection = OCC.BRepAlgoAPI.BRepAlgoAPI_Common(self.section_box['shape'], shape).Shape()
|
intersection = OCC.BRepAlgoAPI.BRepAlgoAPI_Common(self.section_box['shape'], shape).Shape()
|
||||||
intersection_edges = self.get_booleaned_edges(intersection)
|
intersection_edges = self.get_booleaned_edges(intersection)
|
||||||
if len(intersection_edges) <= 0:
|
if len(intersection_edges) <= 0:
|
||||||
continue
|
continue
|
||||||
|
intersections.append(intersection)
|
||||||
|
|
||||||
transformed_intersection = OCC.BRepBuilderAPI.BRepBuilderAPI_Transform(
|
transformed_intersection = OCC.BRepBuilderAPI.BRepBuilderAPI_Transform(
|
||||||
intersection, self.transformation)
|
intersection, self.transformation)
|
||||||
@@ -226,9 +349,62 @@ class IfcCutter:
|
|||||||
self.get_split_edges(edge_face_map, face, zmax, product)
|
self.get_split_edges(edge_face_map, face, zmax, product)
|
||||||
exp.Next()
|
exp.Next()
|
||||||
|
|
||||||
def calculate_face_zpos(self, face):
|
#print('test')
|
||||||
|
#print(compound)
|
||||||
|
#hits = self.get_raycast_hits(compound)
|
||||||
|
#print(hits)
|
||||||
|
|
||||||
|
|
||||||
|
def get_raycast_hits(self, shape):
|
||||||
|
resolution = 0.1 # 5cm
|
||||||
|
hits = []
|
||||||
|
current_x = 0
|
||||||
|
current_y = 0
|
||||||
|
while current_x < self.section_box['x'] /2:
|
||||||
|
current_y = 0
|
||||||
|
while current_y < self.section_box['y']/4:
|
||||||
|
point = numpy.array(self.section_box['top_left_corner'])
|
||||||
|
point = numpy.add(point, current_x * numpy.array(self.section_box['x_axis']))
|
||||||
|
point = numpy.add(point, current_y * numpy.array(self.section_box['y_axis']))
|
||||||
|
hit = self.raycast(shape, point)
|
||||||
|
if hit:
|
||||||
|
hits.append(hit)
|
||||||
|
current_y += resolution
|
||||||
|
current_x += resolution
|
||||||
|
print('row down')
|
||||||
|
return hits
|
||||||
|
|
||||||
|
def raycast(self, shape, point):
|
||||||
|
raycast = OCC.IntCurvesFace.IntCurvesFace_ShapeIntersector()
|
||||||
|
raycast.Load(shape, 0.01)
|
||||||
|
line = OCC.gp.gp_Lin(
|
||||||
|
OCC.gp.gp_Pnt(float(point[0]), float(point[1]), float(point[2])),
|
||||||
|
OCC.gp.gp_Dir( 0, 0, -1))
|
||||||
|
raycast.Perform(line, 0, self.section_box['z'])
|
||||||
|
return raycast.NbPnt() != 0
|
||||||
|
|
||||||
|
def raycast_at_projection_dir(self, shape, point):
|
||||||
|
raycast = OCC.IntCurvesFace.IntCurvesFace_ShapeIntersector()
|
||||||
|
raycast.Load(shape, 0.01)
|
||||||
|
line = OCC.gp.gp_Lin(
|
||||||
|
OCC.gp.gp_Pnt(float(point[0]), float(point[1]), float(point[2])),
|
||||||
|
OCC.gp.gp_Dir(
|
||||||
|
self.section_box['projection'][0],
|
||||||
|
self.section_box['projection'][1],
|
||||||
|
self.section_box['projection'][2]))
|
||||||
|
raycast.Perform(line, 0, self.section_box['z'])
|
||||||
|
if raycast.NbPnt() != 0:
|
||||||
|
# The smaller WParameter is the closer z-index
|
||||||
|
# Should be the first
|
||||||
|
return { 'face': raycast.Face(1), 'z': raycast.WParameter(1) }
|
||||||
|
|
||||||
|
def get_bbox(self, shape):
|
||||||
bbox = OCC.Bnd.Bnd_Box()
|
bbox = OCC.Bnd.Bnd_Box()
|
||||||
OCC.BRepBndLib.brepbndlib_Add(face, bbox)
|
OCC.BRepBndLib.brepbndlib_Add(shape, bbox)
|
||||||
|
return bbox
|
||||||
|
|
||||||
|
def calculate_face_zpos(self, face):
|
||||||
|
bbox = self.get_bbox(face)
|
||||||
xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
|
xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
|
||||||
zpos = zmin + ((zmax - zmin)/2)
|
zpos = zmin + ((zmax - zmin)/2)
|
||||||
return zpos, zmax
|
return zpos, zmax
|
||||||
@@ -378,10 +554,12 @@ class IfcCutter:
|
|||||||
wire_shape = transformed_wire.Shape()
|
wire_shape = transformed_wire.Shape()
|
||||||
|
|
||||||
wire = topods.Wire(wire_shape)
|
wire = topods.Wire(wire_shape)
|
||||||
|
face = OCC.BRepBuilderAPI.BRepBuilderAPI_MakeFace(wire).Face()
|
||||||
|
|
||||||
self.cut_polygons.append({
|
self.cut_polygons.append({
|
||||||
'raw': product,
|
'raw': product,
|
||||||
'geometry': wire
|
'geometry': wire,
|
||||||
|
'geometry_face': face
|
||||||
})
|
})
|
||||||
|
|
||||||
def connect_edges_into_wires(self, unconnected_edges):
|
def connect_edges_into_wires(self, unconnected_edges):
|
||||||
|
|||||||
Reference in New Issue
Block a user