def read_sf_polyline(sf_filepath): sf = shapefile.Reader(sf_filepath) attrib_name_list = shp2citygml.get_field_name_list(sf)[1:] shapeRecs = sf.shapeRecords() shpatt_list = [] for rec in shapeRecs: poly_atts = rec.record pypolygon_list2d = shp2citygml.get_geometry(rec) if pypolygon_list2d: pypolygon_list3d = shp2citygml.pypolygon_list2d_2_3d( pypolygon_list2d, 0.0) for polyline in pypolygon_list3d: shpatt = shapeattributes.ShapeAttributes() shpatt.set_shape(polyline) att2shpatt(shpatt, attrib_name_list, poly_atts) shpatt_list.append(shpatt) return shpatt_list
collada_filepath = "F:\\kianwee_work\\smart\\DeliveryHeightDTM\\extracted_info\\punggol_primary\\collada\\punggol_primary_extruded.dae" #dimensions of boundary bdimx = 1000 bdimy = 1000 #specify the name of the height attribute height_attrib = "heightmedi" #options to keep the geo reference or move the model to the origin geo_ref = False #=========================================================================================== #GENERATE THE 1000X1000 BOUNDARY AROUND THE SHPFILE_PT FILE #=========================================================================================== sf_pt = shapefile.Reader(shpfile_pt) shapeRecs_pt = sf_pt.shapeRecords() for rec_pt in shapeRecs_pt: pypt_list2d = shp2citygml.get_geometry(rec_pt) pypt2d = pypt_list2d[0] pypt3d = (pypt2d[0], pypt2d[1], 0.0) #create a rectangle boundary occrec = py3dmodel.construct.make_rectangle(bdimx, bdimy) #move the rec to pypt3d m_occrec = py3dmodel.modify.move((0, 0, 0), pypt3d, occrec) m_occrec = py3dmodel.fetch.topo2topotype(m_occrec) #=========================================================================================== #GET ALL THE SHAPES WITHIN THIS BOUNDARY #=========================================================================================== sf = shapefile.Reader(shpfile) shapeRecs = sf.shapeRecords()
def convert_apolygon_origlvl(rec, landuse_index, building_index, name_index, plot_ratio_index, count_shapes, citygml, building_list): poly_attribs = rec.record landuse = poly_attribs[landuse_index] landuse.strip() building = poly_attribs[building_index] building.strip() name = poly_attribs[name_index] name.strip() total_build_up = 0 constr_buildings = [] blevel_list = [] #print "CONDITIONS:", building, landuse #======================================================================================================= #if the polygon has no building attrib and has no landuse attribute it is a boundary #======================================================================================================= if building == "" and landuse == "": pypolygon_list2d = shp2citygml.get_geometry(rec) if pypolygon_list2d: pypolygon_list3d = shp2citygml.pypolygon_list2d_2_3d( pypolygon_list2d, 0.0) occface_list = py3dmodel.construct.make_occfaces_frm_pypolygons( pypolygon_list3d) occface_list2 = [] for occface in occface_list: pyptlist = py3dmodel.fetch.points_frm_occface(occface) is_anticlockwise = py3dmodel.calculate.is_anticlockwise( pyptlist, (0, 0, 1)) if is_anticlockwise: r_face = py3dmodel.modify.reverse_face(occface) #nrml = py3dmodel.calculate.face_normal(r_face) occface_list2.append(r_face) else: occface_list2.append(occface) geometry_list = gml3dmodel.write_gml_triangle(occface_list2) citygml.add_tin_relief("lod1", "terrain", geometry_list) #======================================================================================================= #if the polygon has no building attrib and has a landuse attribute it is a landuse #======================================================================================================= if building == "" and landuse != "": #the geometry is stored in parts and points pypolygon_list2d = shp2citygml.get_geometry(rec) if pypolygon_list2d: pypolygon_list3d = shp2citygml.pypolygon_list2d_2_3d( pypolygon_list2d, 0.0) occface_list = py3dmodel.construct.make_occfaces_frm_pypolygons( pypolygon_list3d) geometry_list = gml3dmodel.write_gml_srf_member(occface_list) if name.isspace(): name = "plot" + str(count_shapes) function = shp2citygml.map_osm2citygml_landuse_function(landuse) generic_attrib_dict = {"landuse": landuse} plot_ratio = poly_attribs[plot_ratio_index] if plot_ratio != None: generic_attrib_dict["plot_ratio"] = plot_ratio plot_area = shp2citygml.get_plot_area(rec) generic_attrib_dict["plot_area"] = plot_area citygml.add_landuse("lod1", name, geometry_list, function=function, generic_attrib_dict=generic_attrib_dict) #======================================================================================================= #find the buildings that belong to this plot #======================================================================================================= buildings_on_plot_list = shp2citygml.buildings_on_plot( rec, building_list) in_construction = False #check if any of the buildings are under construction for cbuilding in buildings_on_plot_list: if cbuilding["building"] == "construction": in_construction = True constr_buildings.append(cbuilding) if not in_construction: #then separate the buildings that are parkings and usable floor area parking_list = [] not_parking_list = list(buildings_on_plot_list) for building in buildings_on_plot_list: if "amenity" in building: if building["amenity"] == "parking" or building[ "amenity"] == "carpark": parking_list.append(building) not_parking_list.remove(building) #then measure the total building footprint on this plot build_footprint = 0 for not_parking in not_parking_list: bgeom_list = not_parking["geometry"] for bgeom in bgeom_list: build_footprint = build_footprint + py3dmodel.calculate.face_area( bgeom) #then measure the total parking footprint on this plot multi_parking_footprint = 0 for parking in parking_list: bgeom_list = parking["geometry"] for bgeom in bgeom_list: multi_parking_footprint = multi_parking_footprint + py3dmodel.calculate.face_area( bgeom) #base on the footprints calculate how many storeys are the buildings if build_footprint != 0: residential_height = 3 commercial_height = 4 if plot_ratio != None: total_build_up = total_build_up + (plot_area * plot_ratio) num_storeys = int( round(total_build_up / build_footprint)) if landuse == "residential": height = num_storeys * residential_height if multi_parking_footprint != 0: #base on the parking footprint estimate how high the multistorey carpark should be total_parking_area = shp2citygml.calc_residential_parking_area( total_build_up) parking_storeys = int( round(total_parking_area / multi_parking_footprint)) parking_storey_height = 2.5 parking_height = parking_storey_height * parking_storeys #write the carparks as buildings for parking in parking_list: if "building_l" in parking: blevel_list.append(parking) parking_storeys = parking["building_l"] parking_height = parking_storey_height * parking_storeys shp2citygml.building2citygml( parking, parking_height, citygml, landuse, parking_storeys) else: shp2citygml.building2citygml( parking, parking_height, citygml, landuse, parking_storeys, ) #TODO: calculate for commercial buildings in terms of parking space too else: height = num_storeys * commercial_height for not_parking in not_parking_list: if "building_l" in not_parking: blevel_list.append(not_parking) num_storeys = not_parking["building_l"] if landuse == "residential": height = residential_height * num_storeys else: height = commercial_height * num_storeys shp2citygml.building2citygml( not_parking, height, citygml, landuse, num_storeys) else: shp2citygml.building2citygml( not_parking, height, citygml, landuse, num_storeys) #================================================================================================================ #for those plots without plot ratio and might be educational or civic buildings #================================================================================================================ else: if landuse == "transport" or landuse == "recreation_ground" or landuse == "civic" or landuse == "place_of_worship" or landuse == "utility" or landuse == "health": num_storeys = 2 elif landuse == "education" or landuse == "commercial": num_storeys = 4 elif landuse == "residential": num_storeys = 10 elif landuse == "reserve": num_storeys = 1 else: num_storeys = 1 for not_parking in not_parking_list: if "building_l" in not_parking: blevel_list.append(not_parking) num_storeys = not_parking["building_l"] height = commercial_height * num_storeys shp2citygml.building2citygml( not_parking, height, citygml, landuse, num_storeys) else: height = num_storeys * commercial_height shp2citygml.building2citygml( not_parking, height, citygml, landuse, num_storeys) return total_build_up, constr_buildings, blevel_list
def convert(self): import time QtGui.QApplication.processEvents() self.progress = 0 self.update_bar() self.params.param('Result View').param('Progress').setValue("") #get the shpfile height_attrib = str( self.params.param('Height Attrib').param( 'Height Attribute').value()) bldg_footprint_shp_file = self.params.param('Shape File').param( 'Shapefile Loaded').value() dtm_tif_file = self.params.param('DTM File').param( 'DTM Loaded').value() result_directory = self.params.param('Result Directory').param( 'Result Directory Chosen').value() #viewer = self.params.param('Interactive View').param('Viewer On').value() self.timer.timeout.connect(self.update_bar) self.timer.start(20) #=========================================================================================== #FUNCTIONS #=========================================================================================== def raster_reader(input_terrain_raster): ''' __author__ = "Paul Neitzel, Kian Wee Chen" __copyright__ = "Copyright 2016, Architecture and Building Systems - ETH Zurich" __credits__ = ["Paul Neitzel", "Jimeno A. Fonseca"] __license__ = "MIT" __version__ = "0.1" __maintainer__ = "Daren Thomas" __email__ = "*****@*****.**" __status__ = "Production" ''' # read raster records raster_dataset = gdal.Open(input_terrain_raster) band = raster_dataset.GetRasterBand(1) a = band.ReadAsArray(0, 0, raster_dataset.RasterXSize, raster_dataset.RasterYSize) (y_index, x_index) = np.nonzero(a >= 0) (upper_left_x, x_size, x_rotation, upper_left_y, y_rotation, y_size) = raster_dataset.GetGeoTransform() x_coords = x_index * x_size + upper_left_x + ( x_size / 2) # add half the cell size y_coords = y_index * y_size + upper_left_y + ( y_size / 2) # to centre the point return [(x, y, z) for x, y, z in zip(x_coords, y_coords, a[y_index, x_index])] #=========================================================================================== #THE RESULT FILES #=========================================================================================== north_facade_collada_filepath = os.path.join(result_directory, "north_facade.dae") south_facade_collada_filepath = os.path.join(result_directory, "south_facade.dae") east_facade_collada_filepath = os.path.join(result_directory, "east_facade.dae") west_facade_collada_filepath = os.path.join(result_directory, "west_facade.dae") roof_collada_filepath = os.path.join(result_directory, "roof.dae") footprint_collada_filepath = os.path.join(result_directory, "footprint.dae") terrain_collada_filepath = os.path.join(result_directory, "terrain.dae") try: #=========================================================================================== #CONSTRUCT THE TERRAIN #=========================================================================================== time1 = time.clock() display_2dlist = [] #read the tif terrain file and create a tin from it pyptlist = raster_reader(dtm_tif_file) QtGui.QApplication.processEvents() self.params.param('Result View').param('Progress').setValue( "Constructing the Terrain ... ...") self.progress = 10 tin_occface_list = py3dmodel.construct.delaunay3d(pyptlist) terrain_shell = py3dmodel.construct.sew_faces(tin_occface_list)[0] #=========================================================================================== #EXTRUDE THE BUILDING #=========================================================================================== sf = shapefile.Reader(bldg_footprint_shp_file) shapeRecs = sf.shapeRecords() attrib_name_list = shp2citygml.get_field_name_list(sf) height_index = attrib_name_list.index(height_attrib) - 1 solid_list = [] face_list = [] QtGui.QApplication.processEvents() self.params.param('Result View').param('Progress').setValue( "Extruding the Buildings ... ...") self.progress = 20 cnt = 0 for rec in shapeRecs: QtGui.QApplication.processEvents() poly_attribs = rec.record height = poly_attribs[height_index] pypolygon_list2d = shp2citygml.get_geometry(rec) if pypolygon_list2d: pypolygon_list3d = shp2citygml.pypolygon_list2d_2_3d( pypolygon_list2d, 0.0) occface_list = shp2citygml.shp_pypolygon_list3d_2_occface_list( pypolygon_list3d) for occface in occface_list: if height > 0: occsolid = py3dmodel.construct.extrude( occface, (0, 0, 1), height) solid_list.append(occsolid) face_list.append(occface) cnt += 1 #move all the faces to a very high elevation and project them down onto the terrain so that we know where to place the buildings face_cmpd = py3dmodel.construct.make_compound(face_list) f_midpt = py3dmodel.calculate.get_centre_bbox(face_cmpd) loc_pt = [f_midpt[0], f_midpt[1], 1000] t_face_cmpd = py3dmodel.modify.move(f_midpt, loc_pt, face_cmpd) face_list2 = py3dmodel.fetch.topo_explorer(t_face_cmpd, "face") #face_list2 = face_list2[0:10] msolid_list = [] QtGui.QApplication.processEvents() self.params.param('Result View').param('Progress').setValue( "Placing the Buildings ... ...") self.progress = 50 fcnt = 0 for face2 in face_list2: pyptlist = py3dmodel.fetch.points_frm_occface(face2) #print "NUM PTS:", len(pyptlist) z_list = [] for pypt in pyptlist: QtGui.QApplication.processEvents() interpt, interface = py3dmodel.calculate.intersect_shape_with_ptdir( terrain_shell, pypt, (0, 0, -1)) if interpt: z = interpt[2] z_list.append(z) if z_list: min_z = min(z_list) #print min_z face = face_list[fcnt] face_midpt = py3dmodel.calculate.face_midpt(face) bldg_loc_pt = [face_midpt[0], face_midpt[1], min_z] bsolid = solid_list[fcnt] m_bsolid = py3dmodel.modify.move(face_midpt, bldg_loc_pt, bsolid) msolid_list.append(m_bsolid) fcnt += 1 self.params.param('Result View').param('Progress').setValue( "Classfying the Building Surfaces ... ...") QtGui.QApplication.processEvents() self.progress = 70 total_facade_list = [] total_roof_list = [] total_footprint_list = [] for solid in msolid_list: QtGui.QApplication.processEvents() facade_list, roof_list, footprint_list = urbangeom.identify_building_surfaces( solid) total_facade_list.extend(facade_list) total_roof_list.extend(roof_list) total_footprint_list.extend(footprint_list) n_list, s_list, e_list, w_list = urbangeom.identify_surface_direction( total_facade_list) QtGui.QApplication.processEvents() self.params.param('Result View').param('Progress').setValue( "Writing the Building Surfaces ... ...") self.progress = 100 py3dmodel.export_collada.write_2_collada( n_list, north_facade_collada_filepath) py3dmodel.export_collada.write_2_collada( s_list, south_facade_collada_filepath) py3dmodel.export_collada.write_2_collada( e_list, east_facade_collada_filepath) py3dmodel.export_collada.write_2_collada( w_list, west_facade_collada_filepath) py3dmodel.export_collada.write_2_collada(total_roof_list, roof_collada_filepath) py3dmodel.export_collada.write_2_collada( total_footprint_list, footprint_collada_filepath) py3dmodel.export_collada.write_2_collada([terrain_shell], terrain_collada_filepath) time2 = time.clock() time = (time2 - time1) / 60.0 time_str = "Total Processing Time: " + str(round(time, 2)) + " mins" QtGui.QApplication.processEvents() self.progress = 100 self.params.param('Result View').param('Progress').setValue( time_str) #if viewer == True: # cmpd = pyliburo.py3dmodel.construct.make_compound(msolid_list) # display_2dlist.append([cmpd]) # display_2dlist.append([terrain_shell]) # pyliburo.py3dmodel.construct.visualise(display_2dlist, ["RED", "WHITE"]) self.timer.stop() except: if self.progress == 10: self.params.param('Result View').param('Progress').setValue( str("there is an error at terrain construction !!!")) if self.progress == 20: self.params.param('Result View').param('Progress').setValue( str("there is an error at building extrusion !!!")) if self.progress == 50: self.params.param('Result View').param('Progress').setValue( str("there is an error at building placement !!!")) if self.progress == 70: self.params.param('Result View').param('Progress').setValue( str("there is an error at building classification !!!")) self.timer.stop()