Exemple #1
0
def main(args):
    '''
    Main function that can be called from either the command line or via qc_wrap.py
    '''
    try:
        pargs = parser.parse_args(args[1:])
    except Exception as error_msg:
        print(str(error_msg))
        return 1

    kmname = constants.get_tilename(pargs.las_file)
    print("Running %s on block: %s, %s" % (PROGNAME, kmname, time.asctime()))

    if pargs.below_poly:
        below_poly = True
        ptype = "below_poly"
    else:
        below_poly = False
    if pargs.type is not None:
        ptype = pargs.type
    else:
        ptype = "undefined"
    if below_poly:
        print("Only using points which lie below polygon mean z!")
    pc = pointcloud.fromAny(pargs.las_file)
    print("Classes in pointcloud: %s" % pc.get_classes())

    try:
        extent = np.asarray(constants.tilename_to_extent(kmname))
    except Exception:
        print("Could not get extent from tilename.")
        extent = None

    polygons = vector_io.get_geometries(pargs.ref_data, pargs.layername,
                                        pargs.layersql, extent)
    feature_count = 0
    use_local = pargs.use_local

    if pargs.schema is not None:
        report.set_schema(pargs.schema)

    reporter = report.ReportClassCheck(use_local)
    for polygon in polygons:
        if below_poly:
            if polygon.GetCoordinateDimension() < 3:
                print(
                    "Error: polygon not 3D - below_poly does not make sense!")
                continue
            a_polygon3d = array_geometry.ogrpoly2array(polygon,
                                                       flatten=False)[0]
            #warping loop here....
            if pargs.toE:
                geoid = grid.fromGDAL(GEOID_GRID, upcast=True)
                print("Using geoid from %s to warp to ellipsoidal heights." %
                      GEOID_GRID)
                toE = geoid.interpolate(a_polygon3d[:, :2].copy())
                mask = toE == geoid.nd_val
                if mask.any():
                    raise Warning(
                        "Warping to ellipsoidal heights produced no-data values!"
                    )
                a_polygon3d[:, 2] += toE
            mean_z = a_polygon3d[:, 2].mean()
            if mean_z < SENSIBLE_Z_MIN or mean_z > SENSIBLE_Z_MAX:
                msg = "Warning: This feature seems to have unrealistic mean z value: {0:.2f} m"
                print(msg.format(mean_z))
                continue
            del a_polygon3d
        else:
            mean_z = -1
        polygon.FlattenTo2D()
        feature_count += 1
        separator = "-" * 70
        print("%s\nFeature %d\n%s" % (separator, feature_count, separator))
        a_polygon = array_geometry.ogrpoly2array(polygon)
        pc_in_poly = pc.cut_to_polygon(a_polygon)

        if below_poly:
            pc_in_poly = pc_in_poly.cut_to_z_interval(-999, mean_z)
        n_all = pc_in_poly.get_size()
        freqs = [0] * (len(constants.classes) + 1)  #list of frequencies...

        if n_all > 0:
            c_all = pc_in_poly.get_classes()
            if below_poly and DEBUG:
                print("Mean z of polygon is:        %.2f m" % mean_z)
                print("Mean z of points below is:   %.2f m" %
                      pc_in_poly.z.mean())
            print("Number of points in polygon:  %d" % n_all)
            print("Classes in polygon:           %s" % str(c_all))
            # important for reporting that the order here is the same as in the table
            # definition in report.py!!
            n_found = 0
            for i, cls in enumerate(constants.classes):
                if cls in c_all:
                    pcc = pc_in_poly.cut_to_class(cls)
                    n_c = pcc.get_size()
                    f_c = n_c / float(n_all)
                    n_found += n_c
                    print("Class %d::" % cls)
                    print("   #Points:  %d" % n_c)
                    print("   Fraction: %.3f" % f_c)
                    freqs[i] = f_c
            f_other = (n_all - n_found) / float(n_all)
            freqs[-1] = f_other
        send_args = [kmname] + freqs + [n_all, ptype]
        reporter.report(*send_args, ogr_geom=polygon)
def main(args):
    try:
        pargs = parser.parse_args(args[1:])
    except Exception as e:
        print(str(e))
        return 1
    kmname = constants.get_tilename(pargs.las_file)
    print("Running %s on block: %s, %s" % (progname, kmname, time.asctime()))
    lasname = pargs.las_file
    polyname = pargs.poly_data
    use_local = pargs.use_local
    if pargs.schema is not None:
        report.set_schema(pargs.schema)
    reporter = report.ReportBuildingAbsposCheck(use_local)
    ##################################
    pc = pointcloud.fromAny(lasname).cut_to_class(cut_to_classes)
    try:
        extent = np.asarray(constants.tilename_to_extent(kmname))
    except Exception as e:
        print("Could not get extent from tilename.")
        extent = None
    polys = vector_io.get_geometries(polyname, pargs.layername, pargs.layersql,
                                     extent)
    fn = 0
    sl = "-" * 65
    for poly in polys:
        n_corners_found = 0
        fn += 1
        print("%s\nChecking feature %d\n%s\n" % (sl, fn, sl))
        a_poly = array_geometry.ogrgeom2array(poly)
        pcp = pc.cut_to_polygon(a_poly)
        if pcp.get_size() < 500:
            print("Few points in polygon...")
            continue
        a_poly = a_poly[0]
        all_post = np.zeros_like(a_poly)  #array of vertices found
        all_pre = np.zeros_like(
            a_poly)  #array of vertices in polygon, correpsonding to found...
        pcp.triangulate()
        geom = pcp.get_triangle_geometry()
        m = geom[:, 1].mean()
        sd = geom[:, 1].std()
        if (m > 1.5 or 0.5 * sd > m):
            print("Feature %d, bad geometry...." % fn)
            print("{} {}".format(m, sd))
            continue
        #geom is ok - we proceed with a buffer around da house
        poly_buf = poly.Buffer(2.0)
        a_poly2 = array_geometry.ogrgeom2array(poly_buf)
        pcp = pc.cut_to_polygon(a_poly2)
        print("Points in buffer: %d" % pcp.get_size())
        pcp.triangulate()
        geom = pcp.get_triangle_geometry()
        tanv2 = tan(radians(cut_angle))**2
        #set a mask to mark the triangles we want to consider as marking the house boundary
        mask = np.logical_and(geom[:, 0] > tanv2, geom[:, 2] > z_limit)
        #we consider the 'high' lying vertices - could also just select the highest of the three vertices...
        p_mask = (pcp.z > pcp.z.min() + 2)
        #and only consider those points which lie close to the outer bd of the house...
        p_mask &= array_geometry.points_in_buffer(
            pcp.xy, a_poly, 1.2)  #a larger shift than 1.2 ??
        #this just selects vertices where p_mask is true, from triangles where mask is true - nothing else...
        bd_mask = pcp.get_boundary_vertices(mask, p_mask)
        bd_pts = pcp.xy[bd_mask]
        #subtract mean to get better numeric stability...
        xy_t = bd_pts.mean(axis=0)
        xy = bd_pts - xy_t
        a_poly -= xy_t
        if DEBUG:
            plot_points(a_poly, xy)
        #now find those corners!
        lines_ok = dict()
        found_lines = dict()
        for vertex in range(a_poly.shape[0] -
                            1):  #check line emanating from vertex...
            p1 = a_poly[vertex]
            p2 = a_poly[vertex + 1]
            ok, pts = check_distribution(p1, p2, xy)
            lines_ok[vertex] = (ok, pts)
        #now find corners
        vertex = 0  #handle the 0'th corner specially...
        while vertex < a_poly.shape[0] - 2:
            if lines_ok[vertex][0] and lines_ok[vertex + 1][0]:  #proceed
                print("%s\nCorner %d should be findable..." %
                      ("+" * 50, vertex + 1))
                corner_found = find_corner(vertex, lines_ok, found_lines,
                                           a_poly)
                all_pre[n_corners_found] = a_poly[vertex + 1]
                all_post[n_corners_found] = corner_found
                #print a_poly[vertex+1],corner_found,vertex
                n_corners_found += 1
                vertex += 1
            else:  #skip to next findable corner
                vertex += 2
        if lines_ok[0][0] and lines_ok[a_poly.shape[0] - 2][0]:
            print("Corner 0 should also be findable...")
            corner_found = find_corner(a_poly.shape[0] - 2, lines_ok,
                                       found_lines, a_poly)
            all_pre[n_corners_found] = a_poly[0]
            all_post[n_corners_found] = corner_found
            n_corners_found += 1
        print("\n********** In total for feature %d:" % fn)
        print("Corners found: %d" % n_corners_found)
        if n_corners_found > 0:
            all_post = all_post[:n_corners_found]
            all_pre = all_pre[:n_corners_found]
            all_dxy = all_post - all_pre
            mdxy = all_dxy.mean(axis=0)
            sdxy = np.std(all_dxy, axis=0)
            ndxy = norm(all_dxy)
            params = (1, mdxy[0], mdxy[1])
            print("Mean dxy:      %.3f, %.3f" % (mdxy[0], mdxy[1]))
            print("Sd      :      %.3f, %.3f" % (sdxy[0], sdxy[1]))
            print("Max absolute : %.3f m" % (ndxy.max()))
            print("Mean absolute: %.3f m" % (ndxy.mean()))
            if n_corners_found > 1:
                print("Helmert transformation (pre to post):")
                params = helmert2d(all_pre, all_post)
                print("Scale:  %.5f ppm" % ((params[0] - 1) * 1e6))
                print("dx:     %.3f m" % params[1])
                print("dy:     %.3f m" % params[2])
                print("Residuals:")
                all_post_ = params[0] * all_pre + params[1:]
                all_dxy = all_post - all_post_
                mdxy = all_dxy.mean(axis=0)
                sdxy = np.std(all_dxy, axis=0)
                ndxy = norm(all_dxy)
                print("Mean dxy:      %.3f, %.3f" % (mdxy[0], mdxy[1]))
                print("Sd      :      %.3f, %.3f" % (sdxy[0], sdxy[1]))
                print("Max absolute : %.3f m" % (ndxy.max()))
                print("Mean absolute: %.3f m" % (ndxy.mean()))
            reporter.report(kmname,
                            params[0],
                            params[1],
                            params[2],
                            n_corners_found,
                            ogr_geom=poly)
Exemple #3
0
def zcheck_base(lasname,vectorname,angle_tolerance,xy_tolerance,z_tolerance,cut_class,reporter,buffer_dist=None,layername=None,layersql=None):
	is_roads=buffer_dist is not None #'hacky' signal that its roads we're checking
	print("Starting zcheck_base run at %s" %time.asctime())
	tstart=time.clock()
	kmname=constants.get_tilename(lasname)
	pc=pointcloud.fromAny(lasname)
	t2=time.clock()
	tread=t2-tstart
	print("Reading data took %.3f ms" %(tread*1e3))
	try:
		extent=np.asarray(constants.tilename_to_extent(kmname))
	except Exception as e:
		print("Could not get extent from tilename.")
		extent=None
	geometries=vector_io.get_geometries(vectorname,layername,layersql,extent)
	pcs=dict()
	for id in pc.get_pids():
		print("%s\n" %("+"*70))
		print("Strip id: %d" %id)
		pc_=pc.cut_to_strip(id).cut_to_class(cut_class)
		if pc_.get_size()>50:
			pcs[id]=pc_
			pcs[id].triangulate()
			pcs[id].calculate_validity_mask(angle_tolerance,xy_tolerance,z_tolerance)
		else:
			print("Not enough points....")
		
	del pc
	done=[]
	for id1 in pcs:
		pc1=pcs[id1]
		for id2 in pcs:
			if id1==id2 or (id1,id2) in done or (id2,id1) in done:
				continue
			done.append((id1,id2))
			ml="-"*70
			print("%s\nChecking strip %d against strip %d\n%s" %(ml,id1,id2,ml))
			pc2=pcs[id2]
			if not pc1.might_overlap(pc2):
				if DEBUG:
					print("Strip %d and strip %d does not seem to overlap. Continuing..." %(id1,id2))
					print("DEBUG: Strip1 bounds:\n%s\nStrip2 bounds:\n%s" %(pc1.get_bounds(),pc2.get_bounds())) 
				continue
			overlap_box=array_geometry.bbox_intersection(pc1.get_bounds(),pc2.get_bounds()) #shouldn't be None
			fn=0
			for ogr_geom in geometries:
				fn+=1
				try:
					a_geom=array_geometry.ogrgeom2array(ogr_geom)
				except Exception as e:
					print(str(e))
					continue
				if DEBUG:
					print("----- feature: %d ------" %fn)
				bbox=array_geometry.get_bounds(a_geom)
				
				if  not (pc1.might_intersect_box(bbox) and pc2.might_intersect_box(bbox)):
					if DEBUG:
						print("Feature not in strip overlap. Continuing...")
						print("DEBUG: Strip1 bounds:\n%s\nStrip2 bounds:\n%s\nPolygon bounds:\n%s" %(pc1.get_bounds(),pc2.get_bounds(),bbox)) 
					continue
				#possibly cut the geometry into pieces contained in 'overlap' bbox
				pieces=[ogr_geom]
				dim=ogr_geom.GetDimension()
				assert(dim==1 or dim==2)  #only line or polygons
				if dim==1:
					cut_geom=array_geometry.cut_geom_to_bbox(ogr_geom,overlap_box)
					n_geoms=cut_geom.GetGeometryCount()
					if n_geoms>0:
						pieces=[cut_geom.GetGeometryRef(ng).Clone() for ng in range(n_geoms)]
						print("Cut line into %d pieces..." %n_geoms)
				
				for geom_piece in pieces:
					a_geom=array_geometry.ogrgeom2array(geom_piece) 
					if buffer_dist is not None:
						pc2_in_poly=pc2.cut_to_line_buffer(a_geom,buffer_dist)
					else:
						pc2_in_poly=pc2.cut_to_polygon(a_geom)
					print("(%d,%d,%d):" %(id1,id2,fn))
					if pc2_in_poly.get_size()>5:
						stats12=check_feature(pc1,pc2_in_poly,DEBUG)
					else:
						stats12=None
						print("Not enough points ( %d ) from strip %d in 'feature' (polygon / buffer)." %(pc2_in_poly.get_size(),id2))
					
					if dim==1:
						pc1_in_poly=pc1.cut_to_line_buffer(a_geom,buffer_dist)
					else:
						pc1_in_poly=pc1.cut_to_polygon(a_geom)
					
					print("(%d,%d,%d):" %(id2,id1,fn))
					if pc1_in_poly.get_size()>5:
						stats21=check_feature(pc2,pc1_in_poly,DEBUG)
					else:
						stats21=None
						print("Not enough points ( %d ) from strip %d in 'feature' (polygon / buffer)." %(pc1_in_poly.get_size(),id1))
					if (stats12 is not None or stats21 is not None):
						c_prec=0
						n_points=0
						args12=[None]*4
						args21=[None]*4
						if stats12 is not None:
							n_points+=stats12[3]
							args12=stats12
						if stats21 is not None:
							n_points+=stats21[3]
							args21=stats21
						if stats12 is not None:
							c_prec+=(stats12[2])*(stats12[3]/float(n_points))
						if stats21 is not None:
							c_prec+=(stats21[2])*(stats21[3]/float(n_points))
						#Combined prec. now uses RMS-value.... Its simply a weightning of the two RMS'es...
						#TODO: consider setting a min bound for the combined number of points.... or a 'confidence' weight...
						args=[kmname,id1,id2]
						for i in range(4):
							args.extend([args12[i],args21[i]])
						args.append(c_prec)
						t1=time.clock()
						reporter.report(*args,ogr_geom=geom_piece)
						t2=time.clock()
						print("Reporting took %.4s ms - concurrency?" %((t2-t1)*1e3))
	tend=time.clock()
	tall=tend-tstart
	frac_read=tread/tall
	print("Finished checking tile, time spent: %.3f s, fraction spent on reading las data: %.3f" %(tall,frac_read))
	return len(done)
	
Exemple #4
0
def main(args):
    pargs = parser.parse_args(args[1:])
    lasname = pargs.las_file
    polyname = pargs.build_polys
    kmname = constants.get_tilename(lasname)
    print("Running %s on block: %s, %s" %
          (os.path.basename(args[0]), kmname, time.asctime()))
    use_local = pargs.use_local
    if pargs.schema is not None:
        report.set_schema(pargs.schema)
    reporter = report.ReportRoofridgeCheck(use_local)
    cut_class = pargs.cut_class
    print("Using class(es): %s" % (cut_class))
    # default step values for search...
    steps1 = 32
    steps2 = 14
    search_factor = pargs.search_factor
    if search_factor != 1:
        # can turn search steps up or down
        steps1 = int(search_factor * steps1)
        steps2 = int(search_factor * steps2)
        print("Incresing search factor by: %.2f" % search_factor)
        print(
            "Running time will increase exponentionally with search factor...")
    pc = pointcloud.fromAny(lasname).cut_to_class(cut_class).cut_to_z_interval(
        Z_MIN, Z_MAX)
    try:
        extent = np.asarray(constants.tilename_to_extent(kmname))
    except Exception:
        print("Could not get extent from tilename.")
        extent = None
    polys = vector_io.get_geometries(polyname, pargs.layername, pargs.layersql,
                                     extent)
    fn = 0
    sl = "+" * 60
    is_sloppy = pargs.sloppy
    use_all = pargs.use_all
    for poly in polys:
        print(sl)
        fn += 1
        print("Checking feature number %d" % fn)
        a_poly = array_geometry.ogrgeom2array(poly)
        # secret argument to use all buildings...
        if (len(a_poly) > 1 or
                a_poly[0].shape[0] != 5) and (not use_all) and (not is_sloppy):
            print("Only houses with 4 corners accepted... continuing...")
            continue
        pcp = pc.cut_to_polygon(a_poly)
        # hmmm, these consts should perhaps be made more visible...
        if (pcp.get_size() < 500 and (not is_sloppy)) or (pcp.get_size() < 10):
            print("Few points in polygon...")
            continue
        # Go to a more numerically stable coord system - from now on only consider outer ring...
        a_poly = a_poly[0]
        xy_t = a_poly.mean(axis=0)
        a_poly -= xy_t
        pcp.xy -= xy_t
        pcp.triangulate()
        geom = pcp.get_triangle_geometry()
        m = geom[:, 1].mean()
        sd = geom[:, 1].std()
        if (m > 1.5 or 0.5 * sd > m) and (not is_sloppy):
            print("Feature %d, bad geometry...." % fn)
            print(m, sd)
            continue
        planes = cluster(pcp, steps1, steps2)
        if len(planes) < 2:
            print("Feature %d, didn't find enough planes..." % fn)
        pair, equation = find_planar_pairs(planes)
        if pair is not None:
            p1 = planes[pair[0]]
            p2 = planes[pair[1]]
            z1 = p1[0] * pcp.xy[:, 0] + p1[1] * pcp.xy[:, 1] + p1[2]
            z2 = p2[0] * pcp.xy[:, 0] + p2[1] * pcp.xy[:, 1] + p2[2]
            print("%s" % ("*" * 60))
            print("Statistics for feature %d" % fn)
            if DEBUG:
                plot3d(pcp.xy, pcp.z, z1, z2)
            intersections, distances, rotations = get_intersections(
                a_poly, equation)
            if intersections.shape[0] == 2:
                line_x = intersections[:, 0]
                line_y = intersections[:, 1]
                z_vals = p1[0] * intersections[:, 0] + p1[
                    1] * intersections[:, 1] + p1[2]
                if abs(z_vals[0] - z_vals[1]) > 0.01:
                    print("Numeric instabilty for z-calculation...")
                z_val = float(np.mean(z_vals))
                print("Z for intersection is %.2f m" % z_val)
                if abs(equation[1]) > 1e-3:
                    a = -equation[0] / equation[1]
                    b = equation[2] / equation[1]
                    line_y = a * line_x + b
                elif abs(equation[0]) > 1e-3:
                    a = -equation[1] / equation[0]
                    b = equation[2] / equation[0]
                    line_x = a * line_y + b
                if DEBUG:
                    plot_intersections(a_poly, intersections, line_x, line_y)
                # transform back to real coords
                line_x += xy_t[0]
                line_y += xy_t[1]
                wkt = "LINESTRING(%.3f %.3f %.3f, %.3f %.3f %.3f)" % (
                    line_x[0], line_y[0], z_val, line_x[1], line_y[1], z_val)
                print("WKT: %s" % wkt)
                reporter.report(kmname,
                                rotations[0],
                                distances[0],
                                distances[1],
                                wkt_geom=wkt)
            else:
                print(
                    "Hmmm - something wrong, didn't get exactly two intersections..."
                )
Exemple #5
0
def main(args):
    try:
        pargs = parser.parse_args(args[1:])
    except Exception as e:
        print(str(e))
        return 1
    kmname = constants.get_tilename(pargs.las_file)
    print("Running %s on block: %s, %s" % (progname, kmname, time.asctime()))
    lasname = pargs.las_file
    pointname = pargs.ref_data
    use_local = pargs.use_local
    if pargs.schema is not None:
        report.set_schema(pargs.schema)
    reporter = report.ReportZcheckAbs(use_local)

    try:
        extent = np.asarray(constants.tilename_to_extent(kmname))
    except Exception as e:
        print("Could not get extent from tilename.")
        extent = None
    pc_ref = None  #base reference pointcloud
    pc_refs = []  #list of possibly 'cropped' pointclouds...
    if pargs.multipoints:
        ftype = "multipoints"
        explode = False
    elif pargs.lines:
        ftype = "lines"
        explode = True
    geoms = vector_io.get_geometries(pointname,
                                     pargs.layername,
                                     pargs.layersql,
                                     extent,
                                     explode=explode)
    for geom in geoms:
        xyz = array_geometry.ogrgeom2array(geom, flatten=False)
        if xyz.shape[0] > 0:
            pc_refs.append(pointcloud.Pointcloud(xyz[:, :2], xyz[:, 2]))
    print("Found %d non-empty geometries" % len(pc_refs))
    if len(pc_refs) == 0:
        print("No input geometries in intersection...")
    if pargs.ftype is not None:
        ftype = pargs.ftype
    cut_input_to = pargs.cut_to
    print("Cutting input pointcloud to class %d" % cut_input_to)
    pc = pointcloud.fromAny(lasname).cut_to_class(
        cut_input_to)  #what to cut to here...??
    #warping loop here....
    if (pargs.toE):
        geoid = grid.fromGDAL(GEOID_GRID, upcast=True)
        print("Using geoid from %s to warp to ellipsoidal heights." %
              GEOID_GRID)
        for i in range(len(pc_refs)):
            toE = geoid.interpolate(pc_refs[i].xy)
            M = (toE == geoid.nd_val)
            if (M.any()):
                print(
                    "Warping to ellipsoidal heights produced no-data values!")
                M = np.logical_not(M)
                toE = toE[M]
                pc_refs[i] = pc_refs[i].cut(M)
            pc_refs[i].z += toE
    #Remove empty pointsets
    not_empty = []
    for pc_r in pc_refs:
        if pc_r.get_size() > 0:
            not_empty.append(pc_r)  #dont worry, just a pointer...
        else:
            raise Warning("Empty input set...")
    print("Checking %d point sets" % len(not_empty))
    #Loop over strips#

    for id in pc.get_pids():
        print("%s\n" % ("+" * 70))
        print("Strip id: %d" % id)
        pc_c = pc.cut_to_strip(id)
        if pc_c.get_size() < 50:
            print("Not enough points...")
            continue
        might_intersect = []
        for i, pc_r in enumerate(not_empty):
            if pc_c.might_overlap(pc_r):
                might_intersect.append(i)
        if len(might_intersect) == 0:
            print("Strip does not intersect any point 'patch'...")
            continue
        pc_c.triangulate()
        pc_c.calculate_validity_mask(angle_tolerance, xy_tolerance,
                                     z_tolerance)
        #now loop over the patches which might intersect this strip...
        any_checked = False
        for i in might_intersect:
            pc_r = not_empty[i].cut_to_box(*(pc_c.get_bounds()))
            if pc_r.get_size == 0:
                continue
            any_checked = True
            print("Stats for check of 'patch/set' %d against strip %d:" %
                  (i, id))
            stats = check_points(pc_c, pc_r)
            if stats is None:
                print("Not enough points in proper triangles...")
                continue
            m, sd, n = stats
            cm_x, cm_y = pc_r.xy.mean(axis=0)
            cm_z = pc_r.z.mean()
            print("Center of mass: %.2f %.2f %.2f" % (cm_x, cm_y, cm_z))
            cm_geom = ogr.Geometry(ogr.wkbPoint25D)
            cm_geom.SetPoint(0, cm_x, cm_y, cm_z)
            #what geometry should be reported, bounding box??
            reporter.report(kmname, id, ftype, m, sd, n, ogr_geom=cm_geom)
        if not any_checked:
            print("Strip did not intersect any point 'patch'...")
Exemple #6
0
def main(args):
    '''
    Run road delta check. Invoked from either command line or qc_wrap.py
    '''
    pargs = parser.parse_args(args[1:])
    lasname = pargs.las_file
    linename = pargs.lines
    kmname = constants.get_tilename(lasname)
    print("Running %s on block: %s, %s" %
          (os.path.basename(args[0]), kmname, time.asctime()))
    if pargs.schema is not None:
        report.set_schema(pargs.schema)
    reporter = report.ReportDeltaRoads(pargs.use_local)
    cut_class = pargs.cut_class
    pc = pointcloud.fromAny(lasname).cut_to_class(cut_class)
    if pc.get_size() < 5:
        print("Too few points to bother..")
        return 1

    pc.triangulate()
    geom = pc.get_triangle_geometry()
    print("Using z-steepnes limit {0:.2f} m".format(pargs.zlim))
    mask = np.logical_and(geom[:, 1] < XY_MAX, geom[:, 2] > pargs.zlim)
    geom = geom[mask]  # save for reporting
    if not mask.any():
        print("No steep triangles found...")
        return 0

    # only the centers of the interesting triangles
    centers = pc.triangulation.get_triangle_centers()[mask]
    print("{0:d} steep triangles in tile.".format(centers.shape[0]))
    try:
        extent = np.asarray(constants.tilename_to_extent(kmname))
    except Exception:
        print("Could not get extent from tilename.")
        extent = None

    lines = vector_io.get_geometries(linename, pargs.layername, pargs.layersql,
                                     extent)
    feature_count = 0
    for line in lines:
        xy = array_geometry.ogrline2array(line, flatten=True)
        if xy.shape[0] == 0:
            print("Seemingly an unsupported geometry...")
            continue

        # select the triangle centers which lie within line_buffer of the road segment
        mask = array_geometry.points_in_buffer(centers, xy, LINE_BUFFER)
        critical = centers[mask]

        print("*" * 50)
        print("{0:d} steep centers along line {1:d}".format(
            critical.shape[0], feature_count))
        feature_count += 1

        if critical.shape[0] > 0:
            z_box = geom[mask][:, 2]
            z1 = z_box.max()
            z2 = z_box.min()
            wkt = "MULTIPOINT("
            for point in critical:
                wkt += "{0:.2f} {1:.2f},".format(point[0], point[1])
            wkt = wkt[:-1] + ")"
            reporter.report(kmname, z1, z2, wkt_geom=wkt)
def main(args):
    try:
        pargs = parser.parse_args(args[1:])
    except Exception as e:
        print(str(e))
        return 1
    kmname = constants.get_tilename(pargs.las_file)
    print("Running %s on block: %s, %s" % (progname, kmname, time.asctime()))
    lasname = pargs.las_file
    polyname = pargs.poly_data
    use_local = pargs.use_local
    if pargs.schema is not None:
        report.set_schema(pargs.schema)
    reporter = report.ReportBuildingRelposCheck(use_local)
    ##################################
    pc = pointcloud.fromAny(lasname).cut_to_z_interval(
        -10, 200).cut_to_class(cut_to_classes)
    try:
        extent = np.asarray(constants.tilename_to_extent(kmname))
    except Exception as e:
        print("Could not get extent from tilename.")
        extent = None
    polys = vector_io.get_geometries(polyname)
    fn = 0
    sl = "-" * 65
    pcs = dict()
    for id in pc.get_pids():
        print("%s\n" % ("+" * 70))
        print("Strip id: %d" % id)
        pc_ = pc.cut_to_strip(id)
        if pc_.get_size() > 500:
            pcs[id] = pc_
        else:
            print("Not enough points....")
    del pc
    done = []
    for id1 in pcs:
        pc1 = pcs[id1]
        for id2 in pcs:
            if id1 == id2 or (id1, id2) in done or (id2, id1) in done:
                continue
            done.append((id1, id2))
            pc2 = pcs[id2]
            ml = "-" * 70
            print("%s\nChecking strip %d against strip %d\n%s" %
                  (ml, id1, id2, ml))
            if not pc1.might_overlap(pc2):
                if DEBUG:
                    print(
                        "Strip %d and strip %d does not seem to overlap. Continuing..."
                        % (id1, id2))
                    print("DEBUG: Strip1 bounds:\n%s\nStrip2 bounds:\n%s" %
                          (pc1.get_bounds(), pc2.get_bounds()))
                continue
            for poly in polys:
                centroid = poly.Centroid()
                centroid.FlattenTo2D()
                if LIGHT_DEBUG:
                    print("Geom type: %s" % centroid.GetGeometryName())
                n_corners_found = 0
                fn += 1
                print("%s\nChecking feature %d\n%s\n" % (sl, fn, sl))
                a_poly = array_geometry.ogrgeom2array(poly)
                pcp1 = pc1.cut_to_polygon(a_poly)
                if pcp1.get_size() < 300:
                    print("Few (%d) points in polygon..." % pcp1.get_size())
                    continue
                pcp2 = pc2.cut_to_polygon(a_poly)
                if pcp2.get_size() < 300:
                    print("Few (%d) points in polygon..." % pcp2.get_size())
                    continue
                a_poly = a_poly[0]
                poly_buf = poly.Buffer(2.0)
                xy_t = a_poly.mean(
                    axis=0
                )  #transform later to center of mass system for numerical stability...
                #transform a_poly coords to center of mass system here
                a_poly -= xy_t
                a_poly2 = array_geometry.ogrgeom2array(poly_buf)
                #dicts to store the found corners in the two strips...
                found1 = dict()
                found2 = dict()
                for pc, pcp, store in [(pc1, pcp1, found1),
                                       (pc2, pcp2, found2)]:
                    pcp.triangulate()
                    geom = pcp.get_triangle_geometry()
                    m = geom[:, 1].mean()
                    sd = geom[:, 1].std()
                    if (m > 1.5 or 0.5 * sd > m):
                        print("Feature %d, bad geometry...." % fn)
                        print("{} {}".format(m, sd))
                        break
                    #geom is ok - we proceed with a buffer around da house
                    pcp = pc.cut_to_polygon(a_poly2)
                    ######
                    ## Transform pointcloud to center of mass system here...
                    #######
                    pcp.xy -= xy_t
                    print("Points in buffer: %d" % pcp.get_size())
                    pcp.triangulate()
                    geom = pcp.get_triangle_geometry()
                    tanv2 = tan(radians(cut_angle))**2
                    #set a mask to mark the triangles we want to consider as marking the house boundary
                    mask = np.logical_and(geom[:, 0] > tanv2,
                                          geom[:, 2] > z_limit)
                    #we consider the 'high' lying vertices - could also just select the highest of the three vertices...
                    p_mask = (pcp.z > pcp.z.min() + 2)
                    #and only consider those points which lie close to the outer bd of the house...
                    p_mask &= array_geometry.points_in_buffer(
                        pcp.xy, a_poly, 1.2)  #a larger shift than 1.2 ??
                    #this just selects vertices where p_mask is true, from triangles where mask is true - nothing else...
                    bd_mask = pcp.get_boundary_vertices(mask, p_mask)
                    xy = pcp.xy[bd_mask]

                    print("Boundary points: %d" % xy.shape[0])
                    if DEBUG:
                        plot_points(a_poly, xy)
                    #now find those corners!
                    lines_ok = dict()
                    found_lines = dict()
                    for vertex in range(
                            a_poly.shape[0] -
                            1):  #check line emanating from vertex...
                        p1 = a_poly[vertex]
                        p2 = a_poly[vertex + 1]
                        ok, pts = check_distribution(p1, p2, xy)
                        lines_ok[vertex] = (ok, pts)
                    #now find corners
                    vertex = 0  #handle the 0'th corner specially...
                    while vertex < a_poly.shape[0] - 2:
                        if lines_ok[vertex][0] and lines_ok[vertex +
                                                            1][0]:  #proceed
                            print("%s\nCorner %d should be findable..." %
                                  ("+" * 50, vertex + 1))
                            corner_found = find_corner(vertex, lines_ok,
                                                       found_lines, a_poly)
                            diff = norm2(a_poly[vertex + 1] - corner_found)
                            if (
                                    diff < TOL_CORNER
                            ):  #seems reasonable that this is a true corner...
                                store[vertex + 1] = corner_found
                                n_corners_found += 1
                            #print a_poly[vertex+1],corner_found,vertex
                            vertex += 1
                        else:  #skip to next findable corner
                            vertex += 2
                    if lines_ok[0][0] and lines_ok[a_poly.shape[0] - 2][0]:
                        print("Corner 0 should also be findable...")
                        corner_found = find_corner(a_poly.shape[0] - 2,
                                                   lines_ok, found_lines,
                                                   a_poly)
                        diff = norm2(a_poly[0] - corner_found)
                        if (diff < TOL_CORNER
                            ):  #seems reasonable that this is a true corner...
                            store[0] = corner_found
                            n_corners_found += 1
                    print("Corners found: %d" % n_corners_found)
                    if n_corners_found == 0:  #no need to do another check...
                        break
                print(
                    "Found %d corners in strip %d, and %d corners in strip %d"
                    % (len(found1), id1, len(found2), id2))
                if len(found1) > 0 and len(found2) > 0:
                    match1 = []
                    match2 = []
                    for cn in found1:
                        if cn in found2:
                            match1.append(found1[cn])
                            match2.append(found2[cn])
                    if len(match1) > 0:
                        match1 = np.array(match1)
                        match2 = np.array(match2)
                        n_corners_found = match1.shape[0]
                        print("\n********** In total for feature %d:" % fn)
                        print("Corners found in both strips: %d" %
                              n_corners_found)
                        all_dxy = match1 - match2
                        mdxy = all_dxy.mean(axis=0)
                        sdxy = np.std(all_dxy, axis=0)
                        ndxy = norm(all_dxy)
                        params = (1, mdxy[0], mdxy[1])
                        print("Mean dxy:      %.3f, %.3f" % (mdxy[0], mdxy[1]))
                        print("Sd      :      %.3f, %.3f" % (sdxy[0], sdxy[1]))
                        print("Max absolute : %.3f m" % (ndxy.max()))
                        print("Mean absolute: %.3f m" % (ndxy.mean()))
                        if n_corners_found > 1:
                            print(
                                "Helmert transformation (corners1 to corners2):"
                            )
                            params = helmert2d(match1, match2)  #2->1 or 1->2 ?
                            print("Scale:  %.5f ppm" % ((params[0] - 1) * 1e6))
                            print("dx:     %.3f m" % params[1])
                            print("dy:     %.3f m" % params[2])
                            print("Residuals:")
                            match2_ = params[0] * match1 + params[1:]
                            all_dxy = match2_ - match2
                            mdxy_ = all_dxy.mean(axis=0)
                            sdxy_ = np.std(all_dxy, axis=0)
                            ndxy_ = norm(all_dxy)
                            if DEBUG or LIGHT_DEBUG:
                                plot3([match1, match2, match2_])
                            #center of mass distances only!!
                            cm_vector = (match2.mean(axis=0) -
                                         match1.mean(axis=0))
                            cm_dist = norm2(cm_vector)
                            print("Mean dxy:      %.3f, %.3f" %
                                  (mdxy_[0], mdxy_[1]))
                            print("Sd      :      %.3f, %.3f" %
                                  (sdxy_[0], sdxy_[1]))
                            print("Max absolute : %.3f m" % (ndxy_.max()))
                            print("Mean absolute: %.3f m" % (ndxy_.mean()))
                            reporter.report(kmname,
                                            id1,
                                            id2,
                                            cm_vector[0],
                                            cm_vector[1],
                                            cm_dist,
                                            params[0],
                                            params[1],
                                            params[2],
                                            sdxy_[0],
                                            sdxy_[1],
                                            n_corners_found,
                                            ogr_geom=centroid)
Exemple #8
0
def main(args):
    pargs = parser.parse_args(args[1:])
    lasname = pargs.las_file
    polyname = pargs.build_polys
    kmname = constants.get_tilename(lasname)
    print("Running %s on block: %s, %s" % (os.path.basename(args[0]), kmname, time.asctime()))
    if pargs.schema is not None:
        report.set_schema(pargs.schema)
    reporter = report.ReportRoofridgeStripCheck(pargs.use_local)
    cut_class = pargs.cut_class
    # default step values for search...
    steps1 = 30
    steps2 = 13
    search_factor = pargs.search_factor
    if search_factor != 1:
        # can turn search steps up or down
        steps1 = int(search_factor * steps1)
        steps2 = int(search_factor * steps2)
        print("Incresing search factor by: %.2f" % search_factor)
        print("Running time will increase exponentionally with search factor...")
    pc = pointcloud.fromAny(lasname).cut_to_class(cut_class).cut_to_z_interval(Z_MIN, Z_MAX)
    try:
        extent = np.asarray(constants.tilename_to_extent(kmname))
    except Exception:
        print("Could not get extent from tilename.")
        extent = None
    polys = vector_io.get_geometries(polyname, pargs.layername, pargs.layersql, extent)
    fn = 0
    sl = "+" * 60
    is_sloppy = pargs.sloppy
    use_all = pargs.use_all
    for poly in polys:
        print(sl)
        fn += 1
        print("Checking feature number %d" % fn)
        a_poly = array_geometry.ogrgeom2array(poly)
        # secret argument to use all buildings...
        if (len(a_poly) > 1 or a_poly[0].shape[0] != 5) and (not use_all) and (not is_sloppy):
            print("Only houses with 4 corners accepted... continuing...")
            continue
        pcp = pc.cut_to_polygon(a_poly)
        strips = pcp.get_pids()
        if len(strips) != 2:
            print("Not exactly two overlapping strips... continuing...")
            continue
        # Go to a more numerically stable coord system - from now on only consider outer ring...
        a_poly = a_poly[0]
        xy_t = a_poly.mean(axis=0)  # center of mass system
        a_poly -= xy_t
        lines = []  # for storing the two found lines...
        for sid in strips:
            print("-*-" * 15)
            print("Looking at strip %d" % sid)
            pcp_ = pcp.cut_to_strip(sid)
            # hmmm, these consts should perhaps be made more visible...
            if (pcp_.get_size() < 500 and (not is_sloppy)) or (pcp_.get_size() < 10):
                print("Few points in polygon... %d" % pcp_.get_size())
                continue
            pcp_.xy -= xy_t
            pcp_.triangulate()
            geom = pcp_.get_triangle_geometry()
            m = geom[:, 1].mean()
            sd = geom[:, 1].std()
            if (m > 1.5 or 0.5 * sd > m) and (not is_sloppy):
                print("Feature %d, strip %d, bad geometry...." % (fn, sid))
                break
            planes = cluster(pcp_, steps1, steps2)
            if len(planes) < 2:
                print("Feature %d, strip %d, didn't find enough planes..." % (fn, sid))
            pair, equation = find_planar_pairs(planes)
            if pair is not None:
                p1 = planes[pair[0]]
                print("%s" % ("*" * 60))
                print("Statistics for feature %d" % fn)

                # Now we need to find some points on the line near the house... (0,0) is
                # the center of mass
                norm_normal = equation[0]**2 + equation[1]**2
                if norm_normal < 1e-10:
                    print("Numeric instablity, small normal")
                    break
                # this should be on the line
                cm_line = np.asarray(equation[:2]) * (equation[2] / norm_normal)
                line_dir = np.asarray((-equation[1], equation[0])) / (sqrt(norm_normal))
                end1 = cm_line + line_dir * LINE_RAD
                end2 = cm_line - line_dir * LINE_RAD
                intersections = np.vstack((end1, end2))
                line_x = intersections[:, 0]
                line_y = intersections[:, 1]
                z_vals = p1[0] * intersections[:, 0] + p1[1] * intersections[:, 1] + p1[2]
                if abs(z_vals[0] - z_vals[1]) > 0.01:
                    print("Numeric instabilty for z-calculation...")
                z_val = float(np.mean(z_vals))
                print("Z for intersection is %.2f m" % z_val)
                # transform back to real coords
                line_x += xy_t[0]
                line_y += xy_t[1]
                wkt = "LINESTRING(%.3f %.3f %.3f, %.3f %.3f %.3f)" % (
                    line_x[0], line_y[0], z_val, line_x[1], line_y[1], z_val)
                print("WKT: %s" % wkt)
                lines.append([sid, wkt, z_val, cm_line, line_dir])

        if len(lines) == 2:
            # check for parallelity
            id1 = lines[0][0]
            id2 = lines[1][0]
            z1 = lines[0][2]
            z2 = lines[1][2]
            if abs(z1 - z2) > 0.5:
                print("Large difference in z-values for the two lines!")
            else:
                ids = "{0:d}_{1:d}".format(id1, id2)
                inner_prod = (lines[0][4] * lines[1][4]).sum()
                inner_prod = max(-1, inner_prod)
                inner_prod = min(1, inner_prod)

                if DEBUG:
                    print("Inner product: %.4f" % inner_prod)

                ang = abs(degrees(acos(inner_prod)))
                if ang > 175:
                    ang = abs(180 - ang)
                if ang < 15:
                    v = (lines[0][3] - lines[1][3])
                    d = np.sqrt((v**2).sum())
                    if d < 5:
                        for line in lines:
                            reporter.report(kmname, id1, id2, ids, d, ang,
                                            line[2], wkt_geom=line[1])
                    else:
                        print("Large distance between centers %s, %s, %.2f" %
                              (lines[0][3], lines[1][3], d))
                else:
                    print("Pair found - but not very well aligned - angle: %.2f" % ang)
        else:
            print("Pair not found...")