def intersect_shape_by_line(topods_shape, line, low_parameter=0.0, hi_parameter=float("+inf")): """ finds the intersection of a shape and a line :param shape: any TopoDS_* :param line: gp_Lin :param low_parameter: :param hi_parameter: :return: a list with a number of tuples that corresponds to the number of intersections found the tuple contains ( gp_Pnt, TopoDS_Face, u,v,w ), respectively the intersection point, the intersecting face and the u,v,w parameters of the intersection point :raise: """ from OCC.IntCurvesFace import IntCurvesFace_ShapeIntersector shape_inter = IntCurvesFace_ShapeIntersector() shape_inter.Load(topods_shape, TOLERANCE) shape_inter.PerformNearest(line, low_parameter, hi_parameter) with assert_isdone(shape_inter, "failed to computer shape / line intersection"): return (shape_inter.Pnt(1), shape_inter.Face(1), shape_inter.UParameter(1), shape_inter.VParameter(1), shape_inter.WParameter(1))
def _intersect_shape_by_line(topods_shape, line, low_parameter=0.0, hi_parameter=float("+inf")): r"""Finds the intersection of a shape and a line Parameters ---------- topods_shape : any TopoDS_* line : gp_Lin low_parameter : float, optional (the default value is 0.0) hi_parameter : float, optional (the default value is infinity) Returns ------- a list of gp_Pnt """ shape_inter = IntCurvesFace_ShapeIntersector() shape_inter.Load(topods_shape, OCCUTILS_DEFAULT_TOLERANCE) # shape_inter.PerformNearest(line, low_parameter, hi_parameter) shape_inter.Perform(line, low_parameter, hi_parameter) with AssertIsDone(shape_inter, "failed to computer shape / line " "intersection"): points = list() # Bug correction (some intersection points were missed) # for i in range(1, shape_inter.NbPnt()): for i in range(1, shape_inter.NbPnt() + 1): points.append(shape_inter.Pnt(i)) return points
def shape_by_line(topods_shape, line, low_parameter=0.0, hi_parameter=float("+inf")): r"""Finds the intersection of a shape and a line Parameters ---------- topods_shape : any TopoDS_* line : gp_Lin low_parameter : float, optional (the default value is 0.0) hi_parameter : float, optional (the default value is infinity) Returns ------- a list with a number of tuples that corresponds to the number of intersections found. the tuple contains ( OCC.gp.gp_Pnt, TopoDS_Face, u,v,w ), respectively the intersection point, the intersecting face and the u,v,w parameters of the intersection point """ shape_inter = IntCurvesFace_ShapeIntersector() shape_inter.Load(topods_shape, OCCUTILS_DEFAULT_TOLERANCE) shape_inter.PerformNearest(line, low_parameter, hi_parameter) with AssertIsDone(shape_inter, "failed to computer shape / line intersection"): return (shape_inter.Pnt(1), shape_inter.Face(1), shape_inter.UParameter(1), shape_inter.VParameter(1), shape_inter.WParameter(1))
def intersect_shape_with_ptdir(occ_shape, pypt, pydir): occ_line = gp_Lin( gp_Ax1(gp_Pnt(pypt[0], pypt[1], pypt[2]), gp_Dir(pydir[0], pydir[1], pydir[2]))) shape_inter = IntCurvesFace_ShapeIntersector() shape_inter.Load(occ_shape, 1e-6) shape_inter.PerformNearest(occ_line, 0.0, float("+inf")) if shape_inter.IsDone(): npts = shape_inter.NbPnt() if npts != 0: return shape_inter.Pnt(1), shape_inter.Face(1) else: return None, None else: return None, None
def intersect_shape_with_ptdir(occtopology, pypt, pydir): """ This function projects a point in a direction and calculates the at which point does the point intersects the OCCtopology. Parameters ---------- occtopology : OCCtopology The OCCtopology to be projected on. OCCtopology includes: OCCshape, OCCcompound, OCCcompsolid, OCCsolid, OCCshell, OCCface, OCCwire, OCCedge, OCCvertex pypt : tuple of floats The point to be projected. A pypt is a tuple that documents the xyz coordinates of a pt e.g. (x,y,z) pydir : tuple of floats The direction of the point to be projected. A pydir is a tuple that documents the xyz vector of a dir e.g. (x,y,z) Returns ------- intersection point : pypt The point in which the projected point intersect the OCCtopology. If None means there is no intersection. intersection face : OCCface The OCCface in which the projected point hits. If None means there is no intersection. """ occ_line = gp_Lin( gp_Ax1(gp_Pnt(pypt[0], pypt[1], pypt[2]), gp_Dir(pydir[0], pydir[1], pydir[2]))) shape_inter = IntCurvesFace_ShapeIntersector() shape_inter.Load(occtopology, 1e-6) shape_inter.PerformNearest(occ_line, 0.0, float("+inf")) if shape_inter.IsDone(): npts = shape_inter.NbPnt() if npts != 0: return modify.occpt_2_pypt(shape_inter.Pnt(1)), shape_inter.Face(1) else: return None, None else: return None, None
def intersect_shape_by_line( shape: TopoDS_Shape, line: gp.gp_Lin, low_parameter: Optional[float]=0.0, hi_parameter: Optional[float]=float("+inf"), tol:Optional[float]=0.001 ): """ finds the intersection of a shape and a line :param shape: any TopoDS_* :param line: gp_Lin :param low_parameter: :param hi_parameter: IntCurvesFace_ShapeIntersector :return: a list with a number of tuples that corresponds to the number of intersections found the tuple contains ( gp_Pnt, TopoDS_Face, u,v,w ), respectively the intersection point, the intersecting face and the u,v,w parameters of the intersection point :raise: """ shape_inter = IntCurvesFace_ShapeIntersector() shape_inter.Load(shape, tol) shape_inter.PerformNearest(line, low_parameter, hi_parameter) with assert_isdone(shape_inter, "failed to computer shape / line intersection"): try: return (shape_inter.Pnt(1), shape_inter.Face(1), shape_inter.UParameter(1), shape_inter.VParameter(1), shape_inter.WParameter(1)) except: return None, None, None, None, None
def terrain_intersection_curves(self, geometry_terrain): # make shell out of tin_occface_list and create OCC object terrain_shell = construct.make_shell(geometry_terrain) terrain_intersection_curves = IntCurvesFace_ShapeIntersector() terrain_intersection_curves.Load(terrain_shell, 1e-6) return terrain_intersection_curves
def building_2d_to_3d(citygml_writer, zone_shp_path, district_shp_path, tin_occface_list, height_col, nfloor_col): """ This script extrudes buildings from the shapefile and creates intermediate floors. :param citygml_writer: the cityGML object to which the buildings are gonna be created. :param district_shp_path: path to the shapefile to be extruded of the district :param tin_occface_list: the faces of the terrain, to be used to put the buildings on top. :param height_col: :param nfloor_col: :return: """ # read district shapefile and names of buildings of the zone of analysis district_building_records = gdf.from_file(district_shp_path).set_index( 'Name') district_building_names = district_building_records.index.values zone_building_names = gdf.from_file(zone_shp_path)['Name'].values #make shell out of tin_occface_list and create OCC object terrain_shell = construct.sew_faces(tin_occface_list)[0] terrain_intersection_curves = IntCurvesFace_ShapeIntersector() terrain_intersection_curves.Load(terrain_shell, 1e-6) bsolid_list = [] #create the buildings in 3D for name in district_building_names: height = float(district_building_records.loc[name, height_col]) nfloors = int(district_building_records.loc[name, nfloor_col]) # Make floors only for the buildings of the zone of interest # for the rest just consider one high floor. # simplify geometry tol =1 for buildings of interest, tol = 5 for surroundings if name in zone_building_names: range_floors = range(nfloors + 1) floor_to_floor_height = height / nfloors geometry = district_building_records.ix[name].geometry.simplify( 1, preserve_topology=True) else: range_floors = [0, 1] floor_to_floor_height = height geometry = district_building_records.ix[name].geometry.simplify( 5, preserve_topology=True) point_list_2D = list(geometry.exterior.coords) point_list_3D = [(a, b, 0) for (a, b) in point_list_2D] # add 0 elevation #creating floor surface in pythonocc face = construct.make_polygon(point_list_3D) #get the midpt of the face face_midpt = calculate.face_midpt(face) #project the face_midpt to the terrain and get the elevation inter_pt, inter_face = calc_intersection(terrain_intersection_curves, face_midpt, (0, 0, 1)) loc_pt = (inter_pt.X(), inter_pt.Y(), inter_pt.Z()) #reconstruct the footprint with the elevation face = fetch.topo2topotype(modify.move(face_midpt, loc_pt, face)) moved_face_list = [] for floor_counter in range_floors: dist2mve = floor_counter * floor_to_floor_height #get midpt of face orig_pt = calculate.face_midpt(face) #move the pt 1 level up dest_pt = modify.move_pt(orig_pt, (0, 0, 1), dist2mve) moved_face = modify.move(orig_pt, dest_pt, face) moved_face_list.append(moved_face) #loft all the faces and form a solid vertical_shell = construct.make_loft(moved_face_list) vertical_face_list = fetch.topo_explorer(vertical_shell, "face") roof = moved_face_list[-1] footprint = moved_face_list[0] all_faces = [] all_faces.append(footprint) all_faces.extend(vertical_face_list) all_faces.append(roof) bldg_shell_list = construct.sew_faces(all_faces) # make sure all the normals are correct (they are pointing out) if bldg_shell_list: bldg_solid = construct.make_solid(bldg_shell_list[0]) bldg_solid = modify.fix_close_solid(bldg_solid) bsolid_list.append(bldg_solid) occface_list = fetch.topo_explorer(bldg_solid, "face") geometry_list = gml3dmodel.write_gml_srf_member(occface_list) citygml_writer.add_building("lod1", name, geometry_list) return bsolid_list
def building2d23d(zone_shp_path, district_shp_path, tin_occface_list, architecture_path, simplification_params, height_col, nfloor_col): """ :param zone_shp_path: path to zone geometrydatabase :param district_shp_path: path to district geometry database :param tin_occface_list: list of faces of terrain :param architecture_path: path to database of architecture properties :param simplification_params: parameters that configure the level of simplification of geometry :param height_col: name of the columns storing the height of buildings :param nfloor_col: name ofthe column storing the number of floors in buildings. :return: """ # read district shapefile and names of buildings of the zone of analysis district_building_records = gdf.from_file(district_shp_path).set_index( 'Name') district_building_names = district_building_records.index.values zone_building_names = gdf.from_file(zone_shp_path)['Name'].values architecture_wwr = gdf.from_file(architecture_path).set_index('Name') #make shell out of tin_occface_list and create OCC object terrain_shell = construct.make_shell_frm_faces(tin_occface_list)[0] terrain_intersection_curves = IntCurvesFace_ShapeIntersector() terrain_intersection_curves.Load(terrain_shell, 1e-6) #empty list where to store the closed geometries geometry_3D_zone = [] geometry_3D_surroundings = [] for name in district_building_names: height = float(district_building_records.loc[name, height_col]) nfloors = int(district_building_records.loc[name, nfloor_col]) # simplify geometry tol =1 for buildings of interest, tol = 5 for surroundings if (name in zone_building_names) and ( simplification_params['consider_floors'] == True): range_floors = range(nfloors + 1) flr2flr_height = height / nfloors geometry = district_building_records.ix[name].geometry.simplify( simplification_params['zone_geometry'], preserve_topology=True) else: range_floors = [0, 1] flr2flr_height = height geometry = district_building_records.ix[name].geometry.simplify( simplification_params['surrounding_geometry'], preserve_topology=True) # burn buildings footprint into the terrain and return the location of the new face face_footprint = burn_buildings(geometry, terrain_intersection_curves) # create floors and form a solid bldg_solid = calc_solid(face_footprint, range_floors, flr2flr_height) # now get all surfaces and create windows only if the buildings are in the area of study window_list = [] wall_list = [] if (name in zone_building_names): if (simplification_params['consider_windows'] == True): # identify building surfaces according to angle: face_list = py3dmodel.fetch.faces_frm_solid(bldg_solid) facade_list_north, facade_list_west, \ facade_list_east, facade_list_south, roof_list, footprint_list = identify_surfaces_type(face_list) # get window properties wwr_west = architecture_wwr.ix[name, "wwr_west"] wwr_east = architecture_wwr.ix[name, "wwr_east"] wwr_north = architecture_wwr.ix[name, "wwr_north"] wwr_south = architecture_wwr.ix[name, "wwr_south"] window_west, wall_west = calc_windows_walls( facade_list_west, wwr_west) if len(window_west) != 0: window_list.extend(window_west) wall_list.extend(wall_west) window_east, wall_east = calc_windows_walls( facade_list_east, wwr_east) if len(window_east) != 0: window_list.extend(window_east) wall_list.extend(wall_east) window_north, wall_north = calc_windows_walls( facade_list_north, wwr_north) if len(window_north) != 0: window_list.extend(window_north) wall_list.extend(wall_north) window_south, wall_south = calc_windows_walls( facade_list_south, wwr_south) if len(window_south) != 0: window_list.extend(window_south) wall_list.extend(wall_south) geometry_3D_zone.append({ "name": name, "windows": window_list, "walls": wall_list, "roofs": roof_list, "footprint": footprint_list }) else: facade_list, roof_list, footprint_list = gml3dmodel.identify_building_surfaces( bldg_solid) wall_list = facade_list geometry_3D_zone.append({ "name": name, "windows": window_list, "walls": wall_list, "roofs": roof_list, "footprint": footprint_list }) else: facade_list, roof_list, footprint_list = gml3dmodel.identify_building_surfaces( bldg_solid) wall_list = facade_list geometry_3D_surroundings.append({ "name": name, "windows": window_list, "walls": wall_list, "roofs": roof_list, "footprint": footprint_list }) return geometry_3D_zone, geometry_3D_surroundings
def building2d23d(locator, geometry_terrain, settings, height_col, nfloor_col): """ :param locator: InputLocator - provides paths to files in a scenario :type locator: cea.inputlocator.InputLocator :param settings: parameters that configure the level of simplification of geometry :type settings: cea.config.Section :param height_col: name of the columns storing the height of buildings :param nfloor_col: name ofthe column storing the number of floors in buildings. :return: """ consider_windows = True #legacy from config file. now it is always true district_shp_path = locator.get_district_geometry() # path to zone geometry database zone_shp_path = locator.get_zone_geometry() # path to database of architecture properties architecture_dbf_path = locator.get_building_architecture() # read district shapefile and names of buildings of the zone of analysis district_building_records = gdf.from_file(district_shp_path).set_index('Name') district_building_names = district_building_records.index.values zone_building_names = locator.get_zone_building_names() architecture_wwr = gdf.from_file(architecture_dbf_path).set_index('Name') #make shell out of tin_occface_list and create OCC object terrain_shell = construct.make_shell(geometry_terrain) terrain_intersection_curves = IntCurvesFace_ShapeIntersector() terrain_intersection_curves.Load(terrain_shell, 1e-6) #empty list where to store the closed geometries geometry_3D_zone = [] geometry_3D_surroundings = [] for name in district_building_names: print('Generating geometry for building %(name)s' % locals()) height = float(district_building_records.loc[name, height_col]) nfloors = int(district_building_records.loc[name, nfloor_col]) # simplify geometry tol =1 for buildings of interest, tol = 5 for surroundings if (name in zone_building_names) and settings.consider_floors: range_floors = range(nfloors+1) flr2flr_height = height / nfloors geometry = district_building_records.ix[name].geometry.simplify(settings.zone_geometry, preserve_topology=True) else: range_floors = [0,1] flr2flr_height = height geometry = district_building_records.ix[name].geometry.simplify(settings.surrounding_geometry, preserve_topology=True) # burn buildings footprint into the terrain and return the location of the new face face_footprint = burn_buildings(geometry, terrain_intersection_curves) # create floors and form a solid building_solid = calc_solid(face_footprint, range_floors, flr2flr_height) # now get all surfaces and create windows only if the buildings are in the area of study window_list =[] wall_list = [] orientation = [] orientation_win = [] normals_w = [] normals_win = [] if (name in zone_building_names): if (consider_windows): # identify building surfaces according to angle: face_list = py3dmodel.fetch.faces_frm_solid(building_solid) facade_list_north, facade_list_west, \ facade_list_east, facade_list_south, roof_list, footprint_list = identify_surfaces_type(face_list) # get window properties wwr_west = architecture_wwr.ix[name, "wwr_west"] wwr_east = architecture_wwr.ix[name, "wwr_east"] wwr_north = architecture_wwr.ix[name, "wwr_north"] wwr_south = architecture_wwr.ix[name, "wwr_south"] window_west, wall_west, normals_windows, normals_walls = calc_windows_walls(facade_list_west, wwr_west) if len(window_west) != 0: window_list.extend(window_west) orientation_win.extend(['west'] * len(window_west)) normals_win.extend(normals_windows) wall_list.extend(wall_west) orientation.extend(['west']*len(wall_west)) normals_w.extend(normals_walls) window_east, wall_east, normals_windows, normals_walls = calc_windows_walls(facade_list_east, wwr_east) if len(window_east) != 0: window_list.extend(window_east) orientation_win.extend(['east'] * len(window_east)) normals_win.extend(normals_windows) wall_list.extend(wall_east) orientation.extend(['east'] * len(wall_east)) normals_w.extend(normals_walls) window_north, wall_north, normals_windows_north, normals_walls_north = calc_windows_walls(facade_list_north, wwr_north) if len(window_north) != 0: window_list.extend(window_north) orientation_win.extend(['north'] * len(window_north)) normals_win.extend(normals_windows_north) wall_list.extend(wall_north) orientation.extend(['north'] * len(wall_north)) normals_w.extend(normals_walls_north) window_south, wall_south, normals_windows_south, normals_walls_south = calc_windows_walls(facade_list_south, wwr_south) if len(window_south) != 0: window_list.extend(window_south) orientation_win.extend(['south'] * len(window_south)) normals_win.extend(normals_windows_south) wall_list.extend(wall_south) orientation.extend(['south'] * len(wall_south)) normals_w.extend(normals_walls_south) geometry_3D_zone.append({"name": name, "windows": window_list, "walls": wall_list, "roofs": roof_list, "footprint": footprint_list, "orientation_walls":orientation, "orientation_windows":orientation_win, "normals_windows":normals_win, "normals_walls": normals_w }) else: facade_list, roof_list, footprint_list = gml3dmodel.identify_building_surfaces(building_solid) wall_list = facade_list geometry_3D_zone.append({"name": name, "windows": window_list, "walls": wall_list, "roofs": roof_list, "footprint": footprint_list, "orientation_walls":orientation, "orientation_windows":orientation_win, "normals_windows":normals_win, "normals_walls": normals_w}) # DO this to visualize progress while debugging!: # edges1 = calculate.visualise_face_normal_as_edges(wall_list,5) # edges2 = calculate.visualise_face_normal_as_edges(roof_list, 5) # edges3 = calculate.visualise_face_normal_as_edges(footprint_list, 5) # construct.visualise([wall_list, roof_list ,footprint_list , edges1, edges2, edges3],["WHITE","WHITE","WHITE","BLACK", "BLACK","BLACK"]) else: facade_list, roof_list, footprint_list = urbangeom.identify_building_surfaces(building_solid) wall_list = facade_list geometry_3D_surroundings.append({"name": name, "windows": window_list, "walls": wall_list, "roofs": roof_list, "footprint": footprint_list, "orientation_walls":orientation, "orientation_windows":orientation_win, "normals_windows":normals_win, "normals_walls": normals_w}) ## DO this to visualize progress while debugging!: # edges1 = calculate.visualise_face_normal_as_edges(wall_list,5) # edges2 = calculate.visualise_face_normal_as_edges(roof_list, 5) # edges3 = calculate.visualise_face_normal_as_edges(footprint_list, 5) # construct.visualise([wall_list, roof_list ,footprint_list , edges1, edges2, edges3],["WHITE","WHITE","WHITE","BLACK", "BLACK","BLACK"]) return geometry_3D_zone, geometry_3D_surroundings