import cv2 import json import math import matplotlib.pyplot as plt import numpy as np import overpy import sys from GeoPointCloud import GeoPointCloud import tgc_definitions import tgc_tools def drawBrushesOnImage(brushes, color, im, pc, image_scale, fill=True): for brush in brushes: center = pc.tgcToCV2(brush["position"]["x"], brush["position"]["z"], image_scale) center = (center[1], center[0]) # In point coordinates, not pixel width = brush["scale"]["x"] / image_scale height = brush["scale"]["z"] / image_scale rotation = - brush["rotation"]["y"] # Inverted degrees, cv2 bounding_box uses degrees thickness = 4 if fill: thickness = -1 # Negative thickness is a filled ellipse brush_type_name = tgc_definitions.brushes.get(int(brush["type"]), "unknown") if 'square' in brush_type_name: box_points = cv2.boxPoints((center, (2.0*width, 2.0*height), rotation)) # Squares seem to be larger than circles box_points = np.int32([box_points]) # Bug with fillPoly, needs explict cast to 32bit if fill: cv2.fillPoly(im, box_points, color, lineType=cv2.LINE_AA) else: cv2.polylines(im, box_points, True, color, thickness, lineType=cv2.LINE_AA) else: # Draw as ellipse for now '''center – The rectangle mass center. size – Width and height of the rectangle. angle – The rotation angle in a clockwise direction. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle.''' bounding_box = (center, (1.414*width, 1.414*height), rotation) # Circles seem to scale according to radius cv2.ellipse(im, bounding_box, color, thickness=thickness, lineType=cv2.LINE_AA) def drawSplinesOnImage(splines, color, im, pc, image_scale): for s in splines: # Get the shape of this spline and draw it on the image nds = [] for wp in s["waypoints"]: nds.append(pc.tgcToCV2(wp["waypoint"]["x"], wp["waypoint"]["y"], image_scale)) # Don't try to draw malformed splines if len(nds) == 0: continue # Uses points and not image pixels, so flip the x and y nds = np.array(nds) nds[:,[0, 1]] = nds[:,[1, 0]] nds = np.int32([nds]) # Bug with fillPoly, needs explict cast to 32bit thickness = int(s["width"]) if(thickness < image_scale): thickness = int(image_scale) if s["isFilled"]: cv2.fillPoly(im, nds, color, lineType=cv2.LINE_AA) else: cv2.polylines(im, nds, s["isClosed"], color, thickness, lineType=cv2.LINE_AA) def drawObjectsOnImage(objects, color, im, pc, image_scale): for ob in objects: for item in ob["Value"]["items"]: # Assuming all items are ellipses for now center = pc.tgcToCV2(item["position"]["x"], item["position"]["z"], image_scale) center = (center[1], center[0]) # In point coordinates, not pixel width = max(item["scale"]["x"] / image_scale, 8.0) height = max(item["scale"]["z"] / image_scale, 8.0) rotation = - item["rotation"]["y"] * math.pi / 180.0 # Inverted degrees, cv2 uses clockwise radians '''center – The rectangle mass center. size – Width and height of the rectangle. angle – The rotation angle in a clockwise direction. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle.''' bounding_box_of_ellipse = (center, (width, height), rotation) cv2.ellipse(im, bounding_box_of_ellipse, color, thickness=-1, lineType=cv2.LINE_AA) for cluster in ob["Value"]["clusters"]: # Assuming all items are ellipses for now center = pc.tgcToCV2(cluster["position"]["x"], cluster["position"]["z"], image_scale) center = (center[1], center[0]) # In point coordinates, not pixel width = cluster["radius"] / image_scale height = cluster["radius"] / image_scale rotation = - cluster["rotation"]["y"] * math.pi / 180.0 # Inverted degrees, cv2 uses clockwise radians '''center – The rectangle mass center. size – Width and height of the rectangle. angle – The rotation angle in a clockwise direction. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle.''' bounding_box_of_ellipse = (center, (width, height), rotation) cv2.ellipse(im, bounding_box_of_ellipse, color, thickness=-1, lineType=cv2.LINE_AA) def drawHolesOnImage(holes, color, im, pc, image_scale): for h in holes: # Get the shape of this spline and draw it on the image waypoints = [] for wp in h["waypoints"]: waypoints.append(pc.tgcToCV2(wp["x"], wp["z"], image_scale)) tees = [] for t in h["teePositions"]: tees.append(pc.tgcToCV2(t["x"], t["z"], image_scale)) # Going to skip drawing pinPositions due to low resolution # Uses points and not image pixels, so flip the x and y waypoints = np.array(waypoints) waypoints[:,[0, 1]] = waypoints[:,[1, 0]] tees = np.array(tees) tees[:,[0, 1]] = tees[:,[1, 0]] # Draw a line between each waypoint thickness = 5 for i in range(0, len(waypoints)-1): first_point = tuple(waypoints[i]) second_point = tuple(waypoints[i+1]) cv2.line(im, first_point, second_point, color, thickness=thickness, lineType=cv2.LINE_AA) # Draw a line between each tee and the second waypoint first_waypoint = tuple(waypoints[1]) for tee in tees: t = tuple(tee) cv2.line(im, t, first_waypoint, color, thickness=thickness, lineType=cv2.LINE_AA) def drawCourseAsImage(course_json): im = np.zeros((2000, 2000, 3), np.float32) # Courses are 2000m x 2000m image_scale = 1.0 # Draw one pixel per meter pc = GeoPointCloud() pc.width = 2000.0 pc.height = 2000.0 # Draw terrain first drawBrushesOnImage(course_json["userLayers"]["terrainHeight"], (0.35, 0.2, 0.0), im, pc, image_scale) drawBrushesOnImage(course_json["userLayers"]["height"], (0.5, 0.2755, 0.106), im, pc, image_scale) # Next draw surfaces in correct stacking orders uls = course_json["userLayers"]["surfaces"] ss = course_json["surfaceSplines"] # Draw real water water_color = (0.1, 0.2, 0.5) drawBrushesOnImage(course_json["userLayers"]["water"], water_color, im, pc, image_scale) # Mulch/Water Visualization Surface #2 has low priority, so draw it first # Drawing as the black/dark blue, but it will show up different depending on scene surface2_color = (0.1, 0.2, 0.25) drawSplinesOnImage([s for s in ss if s["surface"] == 8], surface2_color, im, pc, image_scale) drawBrushesOnImage([b for b in uls if b["surfaceCategory"] == 8], surface2_color, im, pc, image_scale) # Then draw heavy rough heavy_rough_color = (0, 0.3, 0.1) drawSplinesOnImage([s for s in ss if s["surface"] == 4], heavy_rough_color, im, pc, image_scale) drawBrushesOnImage([b for b in uls if b["surfaceCategory"] == 4], heavy_rough_color, im, pc, image_scale) # Then draw rough rough_color = (0.1, 0.35, 0.15) drawSplinesOnImage([s for s in ss if s["surface"] == 3], rough_color, im, pc, image_scale) drawBrushesOnImage([b for b in uls if b["surfaceCategory"] == 3], rough_color, im, pc, image_scale) # Next draw fairways fairway_color = (0, 0.75, 0.2) drawSplinesOnImage([s for s in ss if s["surface"] == 2], fairway_color, im, pc, image_scale) drawBrushesOnImage([b for b in uls if b["surfaceCategory"] == 2], fairway_color, im, pc, image_scale) # Next draw greens green_color = (0, 1.0, 0.2) drawSplinesOnImage([s for s in ss if s["surface"] == 1], green_color, im, pc, image_scale) drawBrushesOnImage([b for b in uls if b["surfaceCategory"] == 1], green_color, im, pc, image_scale) # Next draw bunkers bunker_color = (0.85, 0.85, 0.7) drawSplinesOnImage([s for s in ss if s["surface"] == 0], bunker_color, im, pc, image_scale) drawBrushesOnImage([b for b in uls if b["surfaceCategory"] == 0], bunker_color, im, pc, image_scale) # Surface #1 - Gravel? surface1_color = (0.7, 0.7, 0.7) drawSplinesOnImage([s for s in ss if s["surface"] == 7], surface1_color, im, pc, image_scale) drawBrushesOnImage([b for b in uls if b["surfaceCategory"] == 7], surface1_color, im, pc, image_scale) # Surface #3 Cart Path cart_path_color = (0.3, 0.3, 0.3) drawSplinesOnImage([s for s in ss if s["surface"] == 10], cart_path_color, im, pc, image_scale) drawBrushesOnImage([b for b in uls if b["surfaceCategory"] == 10], cart_path_color, im, pc, image_scale) # Don't draw brush or surface 5 because this is are clear generated trees # Don't draw brush or surface 6 because this is clear generated objects # Draw out of bounds as white boundaries out_of_bounds_color = (1.0, 1.0, 1.0) drawBrushesOnImage(course_json["userLayers"]["outOfBounds"], out_of_bounds_color, im, pc, image_scale, fill=False) # Draw crowds as pink boundaries crowd_color = (1.0, 0.4, 0.75) drawBrushesOnImage(course_json["userLayers"]["crowdLocations"], crowd_color, im, pc, image_scale, fill=False) # Draw objects last in yellow object_color = (0.95, 0.9, 0.2) drawObjectsOnImage(course_json["placedObjects2"], object_color, im, pc, image_scale) # Last draw holes themselves hole_color = (0.9, 0.3, 0.2) drawHolesOnImage(course_json["holes"], hole_color, im, pc, image_scale) return im if __name__ == "__main__": print("main") if len(sys.argv) < 2: print("Usage: python program.py COURSE_DIRECTORY") sys.exit(0) else: lidar_dir_path = sys.argv[1] print("Loading course file") course_json = tgc_tools.get_course_json(lidar_dir_path) im = drawCourseAsImage(course_json) fig = plt.figure() plt.imshow(im, origin='lower') plt.show()