diff --git a/workflow-test/README.md b/workflow-test/README.md new file mode 100644 index 0000000..dec39cc --- /dev/null +++ b/workflow-test/README.md @@ -0,0 +1,40 @@ +THIS IS STOLE ENTIRELY FROM HERE: https://github.com/stereolabs/zed-sdk/tree/master/object%20detection/custom%20detector/python/pytorch_yolov8 + +# ZED SDK - Object Detection + +This sample shows how to detect custom objects using the official Pytorch implementation of YOLOv8 from a ZED camera and ingest them into the ZED SDK to extract 3D informations and tracking for each objects. + +## Getting Started + + - Get the latest [ZED SDK](https://www.stereolabs.com/developers/release/) and [pyZED Package](https://www.stereolabs.com/docs/app-development/python/install/) + - Check the [Documentation](https://www.stereolabs.com/docs/object-detection/custom-od/) + +## Setting up + + - Install yolov8 using pip + +```sh +pip install ultralytics +``` + +## Run the program + +*NOTE: The ZED v1 is not compatible with this module* + +``` +python detector.py --weights yolov8m.pt # [--img_size 512 --conf_thres 0.1 --svo path/to/file.svo] +``` + +### Features + + - The camera point cloud is displayed in a 3D OpenGL view + - 3D bounding boxes around detected objects are drawn + - Objects classes and confidences can be changed + +## Training your own model + +This sample can use any model trained with YOLOv8, including custom trained one. For a getting started on how to trained a model on a custom dataset with YOLOv5, see here https://docs.ultralytics.com/tutorials/train-custom-datasets/ + +## Support + +If you need assistance go to our Community site at https://community.stereolabs.com/ \ No newline at end of file diff --git a/workflow-test/cv_viewer/tracking_viewer.py b/workflow-test/cv_viewer/tracking_viewer.py new file mode 100644 index 0000000..dcdf51a --- /dev/null +++ b/workflow-test/cv_viewer/tracking_viewer.py @@ -0,0 +1,248 @@ +import cv2 +import numpy as np + +from cv_viewer.utils import * +import pyzed.sl as sl +import math +from collections import deque + + +# ---------------------------------------------------------------------- +# 2D LEFT VIEW +# ---------------------------------------------------------------------- + + +def cvt(pt, scale): + """ + Function that scales point coordinates + """ + out = [pt[0] * scale[0], pt[1] * scale[1]] + return out + + +def get_image_position(bounding_box_image, img_scale): + out_position = np.zeros(2) + out_position[0] = (bounding_box_image[0][0] + (bounding_box_image[2][0] - bounding_box_image[0][0]) * 0.5) * \ + img_scale[0] + out_position[1] = (bounding_box_image[0][1] + (bounding_box_image[2][1] - bounding_box_image[0][1]) * 0.5) * \ + img_scale[1] + return out_position + + +def render_2D(left_display, img_scale, objects, is_tracking_on): + overlay = left_display.copy() + + line_thickness = 2 + for obj in objects.object_list: + if render_object(obj, is_tracking_on): + base_color = generate_color_id_u(obj.id) + # Display image scaled 2D bounding box + top_left_corner = cvt(obj.bounding_box_2d[0], img_scale) + top_right_corner = cvt(obj.bounding_box_2d[1], img_scale) + bottom_right_corner = cvt(obj.bounding_box_2d[2], img_scale) + bottom_left_corner = cvt(obj.bounding_box_2d[3], img_scale) + + # Creation of the 2 horizontal lines + cv2.line(left_display, (int(top_left_corner[0]), int(top_left_corner[1])), + (int(top_right_corner[0]), int(top_right_corner[1])), base_color, line_thickness) + cv2.line(left_display, (int(bottom_left_corner[0]), int(bottom_left_corner[1])), + (int(bottom_right_corner[0]), int(bottom_right_corner[1])), base_color, line_thickness) + # Creation of 2 vertical lines + draw_vertical_line(left_display, bottom_left_corner, top_left_corner, base_color, line_thickness) + draw_vertical_line(left_display, bottom_right_corner, top_right_corner, base_color, line_thickness) + + # Scaled ROI + roi_height = int(top_right_corner[0] - top_left_corner[0]) + roi_width = int(bottom_left_corner[1] - top_left_corner[1]) + overlay_roi = overlay[int(top_left_corner[1]):int(top_left_corner[1] + roi_width), + int(top_left_corner[0]):int(top_left_corner[0] + roi_height)] + + if obj.mask.is_init(): + overlay_roi[obj.mask.numpy() != 0] = base_color + + # Display Object label as text + position_image = get_image_position(obj.bounding_box_2d, img_scale) + text_position = (int(position_image[0] - 20), int(position_image[1] - 12)) + text = "class " + str(obj.raw_label) + text_color = (255, 255, 255, 255) + cv2.putText(left_display, text, text_position, cv2.FONT_HERSHEY_COMPLEX_SMALL, 0.5, text_color, 1) + + # Diplay Object distance to camera as text + if np.isfinite(obj.position[2]): + text = str(round(abs(obj.position[2]), 1)) + "M" + text_position = (int(position_image[0] - 20), int(position_image[1])) + cv2.putText(left_display, text, text_position, cv2.FONT_HERSHEY_COMPLEX_SMALL, 0.5, text_color, 1) + + # Here, overlay is as the left image, but with opaque masks on each detected objects + cv2.addWeighted(left_display, 0.7, overlay, 0.3, 0.0, left_display) + + +# ---------------------------------------------------------------------- +# 2D TRACKING VIEW +# ---------------------------------------------------------------------- + +class TrackingViewer: + def __init__(self, res, fps, D_max): + # Window size + self.window_width = res.width + self.window_height = res.height + + # Visualisation settings + self.has_background_ready = False + self.background = np.full((self.window_height, self.window_width, 4), [245, 239, 239, 255], np.uint8) + + # Invert Z due to Y axis of ocv window + # Show objects between [z_min, 0] (z_min < 0) + self.z_min = -D_max + # Show objects between [x_min, x_max] + self.x_min = self.z_min + self.x_max = -self.x_min + + # Conversion from world position to pixel coordinates + self.x_step = (self.x_max - self.x_min) / self.window_width + self.z_step = abs(self.z_min) / self.window_height + + self.camera_calibration = sl.CalibrationParameters() + + # List of alive tracks + self.tracklets = [] + + def set_camera_calibration(self, calib): + self.camera_calibration = calib + self.has_background_ready = False + + def generate_view(self, objects, current_camera_pose, tracking_view, tracking_enabled): + # To get position in WORLD reference + for obj in objects.object_list: + pos = obj.position + tmp_pos = sl.Translation() + tmp_pos.init_vector(pos[0], pos[1], pos[2]) + new_pos = ( + tmp_pos * current_camera_pose.get_orientation()).get() + current_camera_pose.get_translation().get() + obj.position = np.array([new_pos[0], new_pos[1], new_pos[2]]) + + # Initialize visualisation + if not self.has_background_ready: + self.generate_background() + + np.copyto(tracking_view, self.background, 'no') + + if tracking_enabled: + # First add new points and remove the ones that are too old + current_timestamp = objects.timestamp.get_seconds() + self.add_to_tracklets(objects, current_timestamp) + self.prune_old_points(current_timestamp) + + # Draw all tracklets + self.draw_tracklets(tracking_view, current_camera_pose) + else: + self.draw_points(objects.object_list, tracking_view, current_camera_pose) + + def add_to_tracklets(self, objects, current_timestamp): + for obj in objects.object_list: + if (obj.tracking_state != sl.OBJECT_TRACKING_STATE.OK) or (not np.isfinite(obj.position[0])) or ( + obj.id < 0): + continue + + new_object = True + for i in range(len(self.tracklets)): + if self.tracklets[i].id == obj.id: + new_object = False + self.tracklets[i].add_point(obj, current_timestamp) + + # In case this object does not belong to existing tracks + if (new_object): + self.tracklets.append(Tracklet(obj, obj.label, current_timestamp)) + + def prune_old_points(self, ts): + track_to_delete = [] + for it in self.tracklets: + if ((ts - it.last_timestamp) > (3)): + track_to_delete.append(it) + + for it in track_to_delete: + self.tracklets.remove(it) + + # ---------------------------------------------------------------------- + # Drawing functions + # ---------------------------------------------------------------------- + + def draw_points(self, objects, tracking_view, current_camera_pose): + for obj in objects: + if (not np.isfinite(obj.position[0])): + continue + clr = generate_color_id_u(obj.id) + pt = TrackPoint(obj.position) + cv_start_point = self.to_cv_point(pt.get_xyz(), current_camera_pose) + cv2.circle(tracking_view, (int(cv_start_point[0]), int(cv_start_point[1])), 6, clr, 2) + + def draw_tracklets(self, tracking_view, current_camera_pose): + for track in self.tracklets: + clr = generate_color_id_u(track.id) + cv_start_point = self.to_cv_point(track.positions[0].get_xyz(), current_camera_pose) + for point_index in range(1, len(track.positions)): + cv_end_point = self.to_cv_point(track.positions[point_index].get_xyz(), current_camera_pose) + cv2.line(tracking_view, (int(cv_start_point[0]), int(cv_start_point[1])), + (int(cv_end_point[0]), int(cv_end_point[1])), clr, 3) + cv_start_point = cv_end_point + cv2.circle(tracking_view, (int(cv_start_point[0]), int(cv_start_point[1])), 6, clr, -1) + + def generate_background(self): + camera_color = [255, 230, 204, 255] + + # Get FOV intersection with window borders + fov = 2.0 * math.atan( + self.camera_calibration.left_cam.image_size.width / (2.0 * self.camera_calibration.left_cam.fx)) + + z_at_x_max = self.x_max / math.tan(fov / 2.0) + left_intersection_pt = self.to_cv_point(self.x_min, -z_at_x_max) + right_intersection_pt = self.to_cv_point(self.x_max, -z_at_x_max) + + # Drawing camera + camera_pts = np.array([left_intersection_pt + , right_intersection_pt + , [int(self.window_width / 2), self.window_height]] + , dtype=np.int32) + cv2.fillConvexPoly(self.background, camera_pts, camera_color) + + def to_cv_point(self, x, z): + out = [] + if isinstance(x, float) and isinstance(z, float): + out = [int((x - self.x_min) / self.x_step), int((z - self.z_min) / self.z_step)] + elif isinstance(x, list) and isinstance(z, sl.Pose): + # Go to camera current pose + rotation = z.get_rotation_matrix() + rotation.inverse() + tmp = x - (z.get_translation() * rotation.get_orientation()).get() + new_position = sl.Translation() + new_position.init_vector(tmp[0], tmp[1], tmp[2]) + out = [int(((new_position.get()[0] - self.x_min) / self.x_step) + 0.5), + int(((new_position.get()[2] - self.z_min) / self.z_step) + 0.5)] + elif isinstance(x, TrackPoint) and isinstance(z, sl.Pose): + pos = x.get_xyz() + out = self.to_cv_point(pos, z) + else: + print("Unhandled argument type") + return out + + +class TrackPoint: + def __init__(self, pos_): + self.x = pos_[0] + self.y = pos_[1] + self.z = pos_[2] + + def get_xyz(self): + return [self.x, self.y, self.z] + + +class Tracklet: + def __init__(self, obj_, type_, timestamp_): + self.id = obj_.id + self.object_type = type_ + self.positions = deque() + self.add_point(obj_, timestamp_) + + def add_point(self, obj_, timestamp_): + self.positions.append(TrackPoint(obj_.position)) + self.last_timestamp = timestamp_ diff --git a/workflow-test/cv_viewer/utils.py b/workflow-test/cv_viewer/utils.py new file mode 100644 index 0000000..825bdbb --- /dev/null +++ b/workflow-test/cv_viewer/utils.py @@ -0,0 +1,38 @@ +import cv2 +import numpy as np +import pyzed.sl as sl + +id_colors = [(232, 176, 59), + (175, 208, 25), + (102, 205, 105), + (185, 0, 255), + (99, 107, 252)] + + +def render_object(object_data, is_tracking_on): + if is_tracking_on: + return object_data.tracking_state == sl.OBJECT_TRACKING_STATE.OK + else: + return (object_data.tracking_state == sl.OBJECT_TRACKING_STATE.OK) or ( + object_data.tracking_state == sl.OBJECT_TRACKING_STATE.OFF) + + +def generate_color_id_u(idx): + arr = [] + if idx < 0: + arr = [236, 184, 36, 255] + else: + color_idx = idx % 5 + arr = [id_colors[color_idx][0], id_colors[color_idx][1], id_colors[color_idx][2], 255] + return arr + + +def draw_vertical_line(left_display, start_pt, end_pt, clr, thickness): + n_steps = 7 + pt1 = [((n_steps - 1) * start_pt[0] + end_pt[0]) / n_steps + , ((n_steps - 1) * start_pt[1] + end_pt[1]) / n_steps] + pt4 = [(start_pt[0] + (n_steps - 1) * end_pt[0]) / n_steps + , (start_pt[1] + (n_steps - 1) * end_pt[1]) / n_steps] + + cv2.line(left_display, (int(start_pt[0]), int(start_pt[1])), (int(pt1[0]), int(pt1[1])), clr, thickness) + cv2.line(left_display, (int(pt4[0]), int(pt4[1])), (int(end_pt[0]), int(end_pt[1])), clr, thickness) diff --git a/workflow-test/detector.py b/workflow-test/detector.py new file mode 100644 index 0000000..29a1327 --- /dev/null +++ b/workflow-test/detector.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python3 + +import sys +import numpy as np + +import argparse +import torch +import cv2 +import pyzed.sl as sl +from ultralytics import YOLO + +from threading import Lock, Thread +from time import sleep + +import ogl_viewer.viewer as gl +import cv_viewer.tracking_viewer as cv_viewer + +lock = Lock() +run_signal = False +exit_signal = False + + +def xywh2abcd(xywh, im_shape): + output = np.zeros((4, 2)) + + # Center / Width / Height -> BBox corners coordinates + x_min = (xywh[0] - 0.5*xywh[2]) #* im_shape[1] + x_max = (xywh[0] + 0.5*xywh[2]) #* im_shape[1] + y_min = (xywh[1] - 0.5*xywh[3]) #* im_shape[0] + y_max = (xywh[1] + 0.5*xywh[3]) #* im_shape[0] + + # A ------ B + # | Object | + # D ------ C + + output[0][0] = x_min + output[0][1] = y_min + + output[1][0] = x_max + output[1][1] = y_min + + output[2][0] = x_max + output[2][1] = y_max + + output[3][0] = x_min + output[3][1] = y_max + return output + +def detections_to_custom_box(detections, im0): + output = [] + for i, det in enumerate(detections): + xywh = det.xywh[0] + + # Creating ingestable objects for the ZED SDK + obj = sl.CustomBoxObjectData() + obj.bounding_box_2d = xywh2abcd(xywh, im0.shape) + obj.label = det.cls + obj.probability = det.conf + obj.is_grounded = False + output.append(obj) + return output + + +def torch_thread(weights, img_size, conf_thres=0.2, iou_thres=0.45): + global image_net, exit_signal, run_signal, detections + + print("Intializing Network...") + + model = YOLO(weights) + + while not exit_signal: + if run_signal: + lock.acquire() + + img = cv2.cvtColor(image_net, cv2.COLOR_RGBA2RGB) + # https://docs.ultralytics.com/modes/predict/#video-suffixes + det = model.predict(img, save=False, imgsz=img_size, conf=conf_thres, iou=iou_thres)[0].cpu().numpy().boxes + + # ZED CustomBox format (with inverse letterboxing tf applied) + detections = detections_to_custom_box(det, image_net) + lock.release() + run_signal = False + sleep(0.01) + + +def main(): + global image_net, exit_signal, run_signal, detections + + capture_thread = Thread(target=torch_thread, kwargs={'weights': opt.weights, 'img_size': opt.img_size, "conf_thres": opt.conf_thres}) + capture_thread.start() + + print("Initializing Camera...") + + zed = sl.Camera() + + input_type = sl.InputType() + if opt.svo is not None: + input_type.set_from_svo_file(opt.svo) + + # Create a InitParameters object and set configuration parameters + init_params = sl.InitParameters(input_t=input_type, svo_real_time_mode=True) + init_params.coordinate_units = sl.UNIT.METER + init_params.depth_mode = sl.DEPTH_MODE.ULTRA # QUALITY + init_params.coordinate_system = sl.COORDINATE_SYSTEM.RIGHT_HANDED_Y_UP + init_params.depth_maximum_distance = 50 + + runtime_params = sl.RuntimeParameters() + status = zed.open(init_params) + + if status != sl.ERROR_CODE.SUCCESS: + print(repr(status)) + exit() + + image_left_tmp = sl.Mat() + + print("Initialized Camera") + + positional_tracking_parameters = sl.PositionalTrackingParameters() + # If the camera is static, uncomment the following line to have better performances and boxes sticked to the ground. + # positional_tracking_parameters.set_as_static = True + zed.enable_positional_tracking(positional_tracking_parameters) + + obj_param = sl.ObjectDetectionParameters() + obj_param.detection_model = sl.OBJECT_DETECTION_MODEL.CUSTOM_BOX_OBJECTS + obj_param.enable_tracking = True + obj_param.enable_segmentation = False # designed to give person pixel mask with internal OD + zed.enable_object_detection(obj_param) + + objects = sl.Objects() + obj_runtime_param = sl.ObjectDetectionRuntimeParameters() + + # Display + camera_infos = zed.get_camera_information() + camera_res = camera_infos.camera_configuration.resolution + # Create OpenGL viewer + viewer = gl.GLViewer() + point_cloud_res = sl.Resolution(min(camera_res.width, 720), min(camera_res.height, 404)) + point_cloud_render = sl.Mat() + viewer.init(camera_infos.camera_model, point_cloud_res, obj_param.enable_tracking) + point_cloud = sl.Mat(point_cloud_res.width, point_cloud_res.height, sl.MAT_TYPE.F32_C4, sl.MEM.CPU) + image_left = sl.Mat() + # Utilities for 2D display + display_resolution = sl.Resolution(min(camera_res.width, 1280), min(camera_res.height, 720)) + image_scale = [display_resolution.width / camera_res.width, display_resolution.height / camera_res.height] + image_left_ocv = np.full((display_resolution.height, display_resolution.width, 4), [245, 239, 239, 255], np.uint8) + + # Utilities for tracks view + camera_config = camera_infos.camera_configuration + tracks_resolution = sl.Resolution(400, display_resolution.height) + track_view_generator = cv_viewer.TrackingViewer(tracks_resolution, camera_config.fps, init_params.depth_maximum_distance) + track_view_generator.set_camera_calibration(camera_config.calibration_parameters) + image_track_ocv = np.zeros((tracks_resolution.height, tracks_resolution.width, 4), np.uint8) + # Camera pose + cam_w_pose = sl.Pose() + + while viewer.is_available() and not exit_signal: + if zed.grab(runtime_params) == sl.ERROR_CODE.SUCCESS: + # -- Get the image + lock.acquire() + zed.retrieve_image(image_left_tmp, sl.VIEW.LEFT) + image_net = image_left_tmp.get_data() + lock.release() + run_signal = True + + # -- Detection running on the other thread + while run_signal: + sleep(0.001) + + # Wait for detections + lock.acquire() + # -- Ingest detections + zed.ingest_custom_box_objects(detections) + lock.release() + zed.retrieve_objects(objects, obj_runtime_param) + + # -- Display + # Retrieve display data + zed.retrieve_measure(point_cloud, sl.MEASURE.XYZRGBA, sl.MEM.CPU, point_cloud_res) + point_cloud.copy_to(point_cloud_render) + zed.retrieve_image(image_left, sl.VIEW.LEFT, sl.MEM.CPU, display_resolution) + zed.get_position(cam_w_pose, sl.REFERENCE_FRAME.WORLD) + + # 3D rendering + viewer.updateData(point_cloud_render, objects) + # 2D rendering + np.copyto(image_left_ocv, image_left.get_data()) + cv_viewer.render_2D(image_left_ocv, image_scale, objects, obj_param.enable_tracking) + global_image = cv2.hconcat([image_left_ocv, image_track_ocv]) + # Tracking view + track_view_generator.generate_view(objects, cam_w_pose, image_track_ocv, objects.is_tracked) + + cv2.imshow("ZED | 2D View and Birds View", global_image) + key = cv2.waitKey(10) + if key == 27 or key == ord('q') or key == ord('Q'): + exit_signal = True + else: + exit_signal = True + + viewer.exit() + exit_signal = True + zed.close() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--weights', type=str, default='yolov8m.pt', help='model.pt path(s)') + parser.add_argument('--svo', type=str, default=None, help='optional svo file, if not passed, use the plugged camera instead') + parser.add_argument('--img_size', type=int, default=416, help='inference size (pixels)') + parser.add_argument('--conf_thres', type=float, default=0.4, help='object confidence threshold') + opt = parser.parse_args() + + with torch.no_grad(): + main() diff --git a/workflow-test/ogl_viewer/viewer.py b/workflow-test/ogl_viewer/viewer.py new file mode 100644 index 0000000..102a4d1 --- /dev/null +++ b/workflow-test/ogl_viewer/viewer.py @@ -0,0 +1,769 @@ +from OpenGL.GL import * +from OpenGL.GLUT import * +from OpenGL.GLU import * + +import ctypes +import sys +import math +from threading import Lock +import numpy as np +import array +from enum import IntEnum + +from cv_viewer.utils import * +import ogl_viewer.zed_model as zm +import pyzed.sl as sl + +VERTEX_SHADER = """ +# version 330 core +layout(location = 0) in vec3 in_Vertex; +layout(location = 1) in vec4 in_Color; +uniform mat4 u_mvpMatrix; +out vec4 b_color; +void main() { + b_color = in_Color; + gl_Position = u_mvpMatrix * vec4(in_Vertex, 1); +} +""" + +FRAGMENT_SHADER = """ +# version 330 core +in vec4 b_color; +layout(location = 0) out vec4 out_Color; +void main() { + out_Color = b_color; +} +""" + +POINTCLOUD_VERTEX_SHADER = """ +#version 330 core +layout(location = 0) in vec4 in_VertexRGBA; +uniform mat4 u_mvpMatrix; +out vec4 b_color; +void main() { + uint vertexColor = floatBitsToUint(in_VertexRGBA.w); + vec3 clr_int = vec3((vertexColor & uint(0x000000FF)), (vertexColor & uint(0x0000FF00)) >> 8, (vertexColor & uint(0x00FF0000)) >> 16); + b_color = vec4(clr_int.r / 255.0f, clr_int.g / 255.0f, clr_int.b / 255.0f, 1.f); + gl_Position = u_mvpMatrix * vec4(in_VertexRGBA.xyz, 1); +} +""" + +POINTCLOUD_FRAGMENT_SHADER = """ +#version 330 core +in vec4 b_color; +layout(location = 0) out vec4 out_Color; +void main() { + out_Color = b_color; +} +""" + +M_PI = 3.1415926 + +GRID_SIZE = 9.0 + + +def generate_color_id(_idx): + clr = np.divide(generate_color_id_u(_idx), 255.0) + clr[0], clr[2] = clr[2], clr[0] + return clr + + +class Shader: + def __init__(self, _vs, _fs): + + self.program_id = glCreateProgram() + vertex_id = self.compile(GL_VERTEX_SHADER, _vs) + fragment_id = self.compile(GL_FRAGMENT_SHADER, _fs) + + glAttachShader(self.program_id, vertex_id) + glAttachShader(self.program_id, fragment_id) + glBindAttribLocation(self.program_id, 0, "in_vertex") + glBindAttribLocation(self.program_id, 1, "in_texCoord") + glLinkProgram(self.program_id) + + if glGetProgramiv(self.program_id, GL_LINK_STATUS) != GL_TRUE: + info = glGetProgramInfoLog(self.program_id) + glDeleteProgram(self.program_id) + glDeleteShader(vertex_id) + glDeleteShader(fragment_id) + raise RuntimeError('Error linking program: %s' % (info)) + glDeleteShader(vertex_id) + glDeleteShader(fragment_id) + + def compile(self, _type, _src): + try: + shader_id = glCreateShader(_type) + if shader_id == 0: + print("ERROR: shader type {0} does not exist".format(_type)) + exit() + + glShaderSource(shader_id, _src) + glCompileShader(shader_id) + if glGetShaderiv(shader_id, GL_COMPILE_STATUS) != GL_TRUE: + info = glGetShaderInfoLog(shader_id) + glDeleteShader(shader_id) + raise RuntimeError('Shader compilation failed: %s' % (info)) + return shader_id + except: + glDeleteShader(shader_id) + raise + + def get_program_id(self): + return self.program_id + + +class Simple3DObject: + def __init__(self, _is_static, pts_size=3, clr_size=3): + self.is_init = False + self.drawing_type = GL_TRIANGLES + self.is_static = _is_static + self.clear() + self.pt_type = pts_size + self.clr_type = clr_size + + def add_pt(self, _pts): # _pts [x,y,z] + for pt in _pts: + self.vertices.append(pt) + + def add_clr(self, _clrs): # _clr [r,g,b] + for clr in _clrs: + self.colors.append(clr) + + def add_point_clr(self, _pt, _clr): + self.add_pt(_pt) + self.add_clr(_clr) + self.indices.append(len(self.indices)) + + def add_line(self, _p1, _p2, _clr): + self.add_point_clr(_p1, _clr) + self.add_point_clr(_p2, _clr) + + def addFace(self, p1, p2, p3, clr): + self.add_point_clr(p1, clr) + self.add_point_clr(p2, clr) + self.add_point_clr(p3, clr) + + def add_full_edges(self, _pts, _clr): + start_id = int(len(self.vertices) / 3) + + for i in range(len(_pts)): + self.add_pt(_pts[i]) + self.add_clr(_clr) + + box_links_top = np.array([0, 1, 1, 2, 2, 3, 3, 0]) + i = 0 + while i < box_links_top.size: + self.indices.append(start_id + box_links_top[i]) + self.indices.append(start_id + box_links_top[i + 1]) + i = i + 2 + + box_links_bottom = np.array([4, 5, 5, 6, 6, 7, 7, 4]) + i = 0 + while i < box_links_bottom.size: + self.indices.append(start_id + box_links_bottom[i]) + self.indices.append(start_id + box_links_bottom[i + 1]) + i = i + 2 + + def __add_single_vertical_line(self, _top_pt, _bottom_pt, _clr): + current_pts = np.array( + [_top_pt, + ((GRID_SIZE - 1) * np.array(_top_pt) + np.array(_bottom_pt)) / GRID_SIZE, + ((GRID_SIZE - 2) * np.array(_top_pt) + np.array(_bottom_pt) * 2) / GRID_SIZE, + (2 * np.array(_top_pt) + np.array(_bottom_pt) * (GRID_SIZE - 2)) / GRID_SIZE, + (np.array(_top_pt) + np.array(_bottom_pt) * (GRID_SIZE - 1)) / GRID_SIZE, + _bottom_pt + ], np.float32) + start_id = int(len(self.vertices) / 3) + for i in range(len(current_pts)): + self.add_pt(current_pts[i]) + if (i == 2 or i == 3): + _clr[3] = 0 + else: + _clr[3] = 0.75 + self.add_clr(_clr) + + box_links = np.array([0, 1, 1, 2, 2, 3, 3, 4, 4, 5]) + i = 0 + while i < box_links.size: + self.indices.append(start_id + box_links[i]) + self.indices.append(start_id + box_links[i + 1]) + i = i + 2 + + def add_vertical_edges(self, _pts, _clr): + self.__add_single_vertical_line(_pts[0], _pts[4], _clr) + self.__add_single_vertical_line(_pts[1], _pts[5], _clr) + self.__add_single_vertical_line(_pts[2], _pts[6], _clr) + self.__add_single_vertical_line(_pts[3], _pts[7], _clr) + + def add_top_face(self, _pts, _clr): + _clr[3] = 0.5 + for pt in _pts: + self.add_point_clr(pt, _clr) + + def __add_quad(self, _quad_pts, _alpha1, _alpha2, _clr): + for i in range(len(_quad_pts)): + self.add_pt(_quad_pts[i]) + if i < 2: + _clr[3] = _alpha1 + else: + _clr[3] = _alpha2 + self.add_clr(_clr) + + self.indices.append(len(self.indices)) + self.indices.append(len(self.indices)) + self.indices.append(len(self.indices)) + self.indices.append(len(self.indices)) + + def add_vertical_faces(self, _pts, _clr): + # For each face, we need to add 4 quads (the first 2 indexes are always the top points of the quad) + quads = [[0, 3, 7, 4] # Front face + , [3, 2, 6, 7] # Right face + , [2, 1, 5, 6] # Back face + , [1, 0, 4, 5]] # Left face + + alpha = .5 + + # Create gradually fading quads + for quad in quads: + quad_pts_1 = [ + _pts[quad[0]], + _pts[quad[1]], + ((GRID_SIZE - 0.5) * np.array(_pts[quad[1]]) + 0.5 * np.array(_pts[quad[2]])) / GRID_SIZE, + ((GRID_SIZE - 0.5) * np.array(_pts[quad[0]]) + 0.5 * np.array(_pts[quad[3]])) / GRID_SIZE + ] + self.__add_quad(quad_pts_1, alpha, alpha, _clr) + + quad_pts_2 = [ + ((GRID_SIZE - 0.5) * np.array(_pts[quad[0]]) + 0.5 * np.array(_pts[quad[3]])) / GRID_SIZE, + ((GRID_SIZE - 0.5) * np.array(_pts[quad[1]]) + 0.5 * np.array(_pts[quad[2]])) / GRID_SIZE, + ((GRID_SIZE - 1.0) * np.array(_pts[quad[1]]) + np.array(_pts[quad[2]])) / GRID_SIZE, + ((GRID_SIZE - 1.0) * np.array(_pts[quad[0]]) + np.array(_pts[quad[3]])) / GRID_SIZE + ] + self.__add_quad(quad_pts_2, alpha, 2 * alpha / 3, _clr) + + quad_pts_3 = [ + ((GRID_SIZE - 1.0) * np.array(_pts[quad[0]]) + np.array(_pts[quad[3]])) / GRID_SIZE, + ((GRID_SIZE - 1.0) * np.array(_pts[quad[1]]) + np.array(_pts[quad[2]])) / GRID_SIZE, + ((GRID_SIZE - 1.5) * np.array(_pts[quad[1]]) + 1.5 * np.array(_pts[quad[2]])) / GRID_SIZE, + ((GRID_SIZE - 1.5) * np.array(_pts[quad[0]]) + 1.5 * np.array(_pts[quad[3]])) / GRID_SIZE + ] + self.__add_quad(quad_pts_3, 2 * alpha / 3, alpha / 3, _clr) + + quad_pts_4 = [ + ((GRID_SIZE - 1.5) * np.array(_pts[quad[0]]) + 1.5 * np.array(_pts[quad[3]])) / GRID_SIZE, + ((GRID_SIZE - 1.5) * np.array(_pts[quad[1]]) + 1.5 * np.array(_pts[quad[2]])) / GRID_SIZE, + ((GRID_SIZE - 2.0) * np.array(_pts[quad[1]]) + 2.0 * np.array(_pts[quad[2]])) / GRID_SIZE, + ((GRID_SIZE - 2.0) * np.array(_pts[quad[0]]) + 2.0 * np.array(_pts[quad[3]])) / GRID_SIZE + ] + self.__add_quad(quad_pts_4, alpha / 3, 0.0, _clr) + + quad_pts_5 = [ + (np.array(_pts[quad[1]]) * 2.0 + (GRID_SIZE - 2.0) * np.array(_pts[quad[2]])) / GRID_SIZE, + (np.array(_pts[quad[0]]) * 2.0 + (GRID_SIZE - 2.0) * np.array(_pts[quad[3]])) / GRID_SIZE, + (np.array(_pts[quad[0]]) * 1.5 + (GRID_SIZE - 1.5) * np.array(_pts[quad[3]])) / GRID_SIZE, + (np.array(_pts[quad[1]]) * 1.5 + (GRID_SIZE - 1.5) * np.array(_pts[quad[2]])) / GRID_SIZE + ] + self.__add_quad(quad_pts_5, 0.0, alpha / 3, _clr) + + quad_pts_6 = [ + (np.array(_pts[quad[1]]) * 1.5 + (GRID_SIZE - 1.5) * np.array(_pts[quad[2]])) / GRID_SIZE, + (np.array(_pts[quad[0]]) * 1.5 + (GRID_SIZE - 1.5) * np.array(_pts[quad[3]])) / GRID_SIZE, + (np.array(_pts[quad[0]]) + (GRID_SIZE - 1.0) * np.array(_pts[quad[3]])) / GRID_SIZE, + (np.array(_pts[quad[1]]) + (GRID_SIZE - 1.0) * np.array(_pts[quad[2]])) / GRID_SIZE + ] + self.__add_quad(quad_pts_6, alpha / 3, 2 * alpha / 3, _clr) + + quad_pts_7 = [ + (np.array(_pts[quad[1]]) + (GRID_SIZE - 1.0) * np.array(_pts[quad[2]])) / GRID_SIZE, + (np.array(_pts[quad[0]]) + (GRID_SIZE - 1.0) * np.array(_pts[quad[3]])) / GRID_SIZE, + (np.array(_pts[quad[0]]) * 0.5 + (GRID_SIZE - 0.5) * np.array(_pts[quad[3]])) / GRID_SIZE, + (np.array(_pts[quad[1]]) * 0.5 + (GRID_SIZE - 0.5) * np.array(_pts[quad[2]])) / GRID_SIZE + ] + self.__add_quad(quad_pts_7, 2 * alpha / 3, alpha, _clr) + + quad_pts_8 = [ + (np.array(_pts[quad[0]]) * 0.5 + (GRID_SIZE - 0.5) * np.array(_pts[quad[3]])) / GRID_SIZE, + (np.array(_pts[quad[1]]) * 0.5 + (GRID_SIZE - 0.5) * np.array(_pts[quad[2]])) / GRID_SIZE, + np.array(_pts[quad[2]]), np.array(_pts[quad[3]]) + ] + self.__add_quad(quad_pts_8, alpha, alpha, _clr) + + def push_to_GPU(self): + if (self.is_init == False): + self.vboID = glGenBuffers(3) + self.is_init = True + + if (self.is_static): + type_draw = GL_STATIC_DRAW + else: + type_draw = GL_DYNAMIC_DRAW + + if len(self.vertices): + glBindBuffer(GL_ARRAY_BUFFER, self.vboID[0]) + glBufferData(GL_ARRAY_BUFFER, len(self.vertices) * self.vertices.itemsize, + (GLfloat * len(self.vertices))(*self.vertices), type_draw) + + if len(self.colors): + glBindBuffer(GL_ARRAY_BUFFER, self.vboID[1]) + glBufferData(GL_ARRAY_BUFFER, len(self.colors) * self.colors.itemsize, + (GLfloat * len(self.colors))(*self.colors), type_draw) + + if len(self.indices): + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.vboID[2]) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, len(self.indices) * self.indices.itemsize, + (GLuint * len(self.indices))(*self.indices), type_draw) + + self.elementbufferSize = len(self.indices) + + def init(self, res): + if (self.is_init == False): + self.vboID = glGenBuffers(3) + self.is_init = True + + if (self.is_static): + type_draw = GL_STATIC_DRAW + else: + type_draw = GL_DYNAMIC_DRAW + + self.elementbufferSize = res.width * res.height + + glBindBuffer(GL_ARRAY_BUFFER, self.vboID[0]) + glBufferData(GL_ARRAY_BUFFER, self.elementbufferSize * self.pt_type * self.vertices.itemsize, None, type_draw) + + if (self.clr_type): + glBindBuffer(GL_ARRAY_BUFFER, self.vboID[1]) + glBufferData(GL_ARRAY_BUFFER, self.elementbufferSize * self.clr_type * self.colors.itemsize, None, + type_draw) + + for i in range(0, self.elementbufferSize): + self.indices.append(i + 1) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.vboID[2]) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, len(self.indices) * self.indices.itemsize, + (GLuint * len(self.indices))(*self.indices), type_draw) + + def setPoints(self, pc): + glBindBuffer(GL_ARRAY_BUFFER, self.vboID[0]) + glBufferSubData(GL_ARRAY_BUFFER, 0, self.elementbufferSize * self.pt_type * self.vertices.itemsize, + ctypes.c_void_p(pc.get_pointer())) + glBindBuffer(GL_ARRAY_BUFFER, 0) + + def clear(self): + self.vertices = array.array('f') + self.colors = array.array('f') + self.indices = array.array('I') + self.elementbufferSize = 0 + + def set_drawing_type(self, _type): + self.drawing_type = _type + + def draw(self): + if (self.elementbufferSize): + glEnableVertexAttribArray(0) + glBindBuffer(GL_ARRAY_BUFFER, self.vboID[0]) + glVertexAttribPointer(0, self.pt_type, GL_FLOAT, GL_FALSE, 0, None) + + if (self.clr_type): + glEnableVertexAttribArray(1) + glBindBuffer(GL_ARRAY_BUFFER, self.vboID[1]) + glVertexAttribPointer(1, self.clr_type, GL_FLOAT, GL_FALSE, 0, None) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.vboID[2]) + glDrawElements(self.drawing_type, self.elementbufferSize, GL_UNSIGNED_INT, None) + + glDisableVertexAttribArray(0) + glDisableVertexAttribArray(1) + + +class GLViewer: + def __init__(self): + self.available = False + self.mutex = Lock() + self.camera = CameraGL() + self.wheelPosition = 0. + self.mouse_button = [False, False] + self.mouseCurrentPosition = [0., 0.] + self.previousMouseMotion = [0., 0.] + self.mouseMotion = [0., 0.] + self.zedModel = Simple3DObject(True) + self.BBox_faces = Simple3DObject(False, 3, 4) + self.BBox_edges = Simple3DObject(False, 3, 4) + self.point_cloud = Simple3DObject(False, 4) + self.is_tracking_on = False # Show tracked objects only + + def init(self, camera_model, res, is_tracking_on): + glutInit(sys.argv) + wnd_w = int(glutGet(GLUT_SCREEN_WIDTH) * 0.9) + wnd_h = int(glutGet(GLUT_SCREEN_HEIGHT) * 0.9) + glutInitWindowSize(wnd_w, wnd_h) + glutInitWindowPosition(int(wnd_w * 0.05), int(wnd_h * 0.05)) + + glutInitDisplayMode(GLUT_DOUBLE | GLUT_SRGB | GLUT_DEPTH) + glutCreateWindow("ZED Object Detection") + glViewport(0, 0, wnd_w, wnd_h) + + glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, + GLUT_ACTION_CONTINUE_EXECUTION) + + glEnable(GL_DEPTH_TEST) + + glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + + glEnable(GL_LINE_SMOOTH) + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) + + self.is_tracking_on = is_tracking_on + + # Compile and create the shader for 3D objects + self.shader_image = Shader(VERTEX_SHADER, FRAGMENT_SHADER) + self.shader_image_MVP = glGetUniformLocation(self.shader_image.get_program_id(), "u_mvpMatrix") + + self.shader_pc = Shader(POINTCLOUD_VERTEX_SHADER, POINTCLOUD_FRAGMENT_SHADER) + self.shader_pc_MVP = glGetUniformLocation(self.shader_pc.get_program_id(), "u_mvpMatrix") + + self.bckgrnd_clr = np.array([223 / 255., 230 / 255., 233 / 255.]) + + if camera_model == sl.MODEL.ZED: + for i in range(0, zm.NB_ALLUMINIUM_TRIANGLES * 3, 3): + for j in range(3): + index = int(zm.alluminium_triangles[i + j] - 1) + self.zedModel.add_point_clr( + [zm.vertices[index * 3], zm.vertices[index * 3 + 1], zm.vertices[index * 3 + 2]], + [zm.ALLUMINIUM_COLOR.r, zm.ALLUMINIUM_COLOR.g, zm.ALLUMINIUM_COLOR.b]) + + for i in range(0, zm.NB_DARK_TRIANGLES * 3, 3): + for j in range(3): + index = int(zm.dark_triangles[i + j] - 1) + self.zedModel.add_point_clr( + [zm.vertices[index * 3], zm.vertices[index * 3 + 1], zm.vertices[index * 3 + 2]], + [zm.DARK_COLOR.r, zm.DARK_COLOR.g, zm.DARK_COLOR.b]) + elif camera_model == sl.MODEL.ZED_M: + for i in range(0, zm.NB_AL_ZEDM_TRI * 3, 3): + for j in range(3): + index = int(zm.al_triangles_m[i + j] - 1) + self.zedModel.add_point_clr( + [zm.vertices_m[index * 3], zm.vertices_m[index * 3 + 1], zm.vertices_m[index * 3 + 2]], + [zm.ALLUMINIUM_COLOR.r, zm.ALLUMINIUM_COLOR.g, zm.ALLUMINIUM_COLOR.b]) + + for i in range(0, zm.NB_DARK_ZEDM_TRI * 3, 3): + for j in range(3): + index = int(zm.dark_triangles_m[i + j] - 1) + self.zedModel.add_point_clr( + [zm.vertices_m[index * 3], zm.vertices_m[index * 3 + 1], zm.vertices_m[index * 3 + 2]], + [zm.DARK_COLOR.r, zm.DARK_COLOR.g, zm.DARK_COLOR.b]) + + for i in range(0, zm.NB_GRAY_ZEDM_TRI * 3, 3): + for j in range(3): + index = int(zm.gray_triangles_m[i + j] - 1) + self.zedModel.add_point_clr( + [zm.vertices_m[index * 3], zm.vertices_m[index * 3 + 1], zm.vertices_m[index * 3 + 2]], + [zm.GRAY_COLOR.r, zm.GRAY_COLOR.g, zm.GRAY_COLOR.b]) + + for i in range(0, zm.NB_YELLOW_ZEDM_TRI * 3, 3): + for j in range(3): + index = int(zm.yellow_triangles_m[i + j] - 1) + self.zedModel.add_point_clr( + [zm.vertices_m[index * 3], zm.vertices_m[index * 3 + 1], zm.vertices_m[index * 3 + 2]], + [zm.YELLOW_COLOR.r, zm.YELLOW_COLOR.g, zm.YELLOW_COLOR.b]) + + elif camera_model == sl.MODEL.ZED2: + for i in range(0, zm.NB_ALLUMINIUM_TRIANGLES * 3, 3): + for j in range(3): + index = int(zm.alluminium_triangles[i + j] - 1) + self.zedModel.add_point_clr( + [zm.vertices[index * 3], zm.vertices[index * 3 + 1], zm.vertices[index * 3 + 2]], + [zm.DARK_COLOR.r, zm.DARK_COLOR.g, zm.DARK_COLOR.b]) + + for i in range(0, zm.NB_DARK_TRIANGLES * 3, 3): + for j in range(3): + index = int(zm.dark_triangles[i + j] - 1) + self.zedModel.add_point_clr( + [zm.vertices[index * 3], zm.vertices[index * 3 + 1], zm.vertices[index * 3 + 2]], + [zm.GRAY_COLOR.r, zm.GRAY_COLOR.g, zm.GRAY_COLOR.b]) + self.zedModel.set_drawing_type(GL_TRIANGLES) + self.zedModel.push_to_GPU() + + self.point_cloud.init(res) + self.point_cloud.set_drawing_type(GL_POINTS) + + self.BBox_edges.set_drawing_type(GL_LINES) + self.BBox_faces.set_drawing_type(GL_QUADS) + + # Register GLUT callback functions + glutDisplayFunc(self.draw_callback) + glutIdleFunc(self.idle) + glutKeyboardFunc(self.keyPressedCallback) + glutCloseFunc(self.close_func) + glutMouseFunc(self.on_mouse) + glutMotionFunc(self.on_mousemove) + glutReshapeFunc(self.on_resize) + + self.available = True + + def is_available(self): + if self.available: + glutMainLoopEvent() + return self.available + + def render_object(self, _object_data): # _object_data of type sl.ObjectData + if self.is_tracking_on: + return (_object_data.tracking_state == sl.OBJECT_TRACKING_STATE.OK) + else: + return ( + _object_data.tracking_state == sl.OBJECT_TRACKING_STATE.OK or _object_data.tracking_state == sl.OBJECT_TRACKING_STATE.OFF) + + def updateData(self, pc, _objs): + self.mutex.acquire() + self.point_cloud.setPoints(pc) + + # Clear frame objects + self.BBox_edges.clear() + self.BBox_faces.clear() + + for i in range(len(_objs.object_list)): + if self.render_object(_objs.object_list[i]): + bounding_box = np.array(_objs.object_list[i].bounding_box) + if bounding_box.any(): + color_id = generate_color_id(_objs.object_list[i].id) + self.create_bbox_rendering(bounding_box, color_id) + + self.mutex.release() + + def create_bbox_rendering(self, _bbox, _bbox_clr): + # First create top and bottom full edges + self.BBox_edges.add_full_edges(_bbox, _bbox_clr) + # Add faded vertical edges + self.BBox_edges.add_vertical_edges(_bbox, _bbox_clr) + # Add faces + self.BBox_faces.add_vertical_faces(_bbox, _bbox_clr) + # Add top face + self.BBox_faces.add_top_face(_bbox, _bbox_clr) + + def idle(self): + if self.available: + glutPostRedisplay() + + def exit(self): + if self.available: + self.available = False + + def close_func(self): + if self.available: + self.available = False + + def keyPressedCallback(self, key, x, y): + if ord(key) == 27: # 'Esc' key + self.close_func() + + def on_mouse(self, *args, **kwargs): + (key, Up, x, y) = args + if key == 0: + self.mouse_button[0] = (Up == 0) + elif key == 2: + self.mouse_button[1] = (Up == 0) + elif (key == 3): + self.wheelPosition = self.wheelPosition + 1 + elif (key == 4): + self.wheelPosition = self.wheelPosition - 1 + + self.mouseCurrentPosition = [x, y] + self.previousMouseMotion = [x, y] + + def on_mousemove(self, *args, **kwargs): + (x, y) = args + self.mouseMotion[0] = x - self.previousMouseMotion[0] + self.mouseMotion[1] = y - self.previousMouseMotion[1] + self.previousMouseMotion = [x, y] + glutPostRedisplay() + + def on_resize(self, Width, Height): + glViewport(0, 0, Width, Height) + self.camera.setProjection(Height / Width) + + def draw_callback(self): + if self.available: + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + glClearColor(self.bckgrnd_clr[0], self.bckgrnd_clr[1], self.bckgrnd_clr[2], 1.) + + self.mutex.acquire() + self.update() + self.draw() + self.mutex.release() + + glutSwapBuffers() + glutPostRedisplay() + + def update(self): + if (self.mouse_button[0]): + r = sl.Rotation() + vert = self.camera.vertical_ + tmp = vert.get() + vert.init_vector(tmp[0] * 1., tmp[1] * 1., tmp[2] * 1.) + r.init_angle_translation(self.mouseMotion[0] * 0.002, vert) + self.camera.rotate(r) + + r.init_angle_translation(self.mouseMotion[1] * 0.002, self.camera.right_) + self.camera.rotate(r) + + if (self.mouse_button[1]): + t = sl.Translation() + tmp = self.camera.right_.get() + scale = self.mouseMotion[0] * -0.01 + t.init_vector(tmp[0] * scale, tmp[1] * scale, tmp[2] * scale) + self.camera.translate(t) + + tmp = self.camera.up_.get() + scale = self.mouseMotion[1] * 0.01 + t.init_vector(tmp[0] * scale, tmp[1] * scale, tmp[2] * scale) + self.camera.translate(t) + + if (self.wheelPosition != 0): + t = sl.Translation() + tmp = self.camera.forward_.get() + scale = self.wheelPosition * -0.065 + t.init_vector(tmp[0] * scale, tmp[1] * scale, tmp[2] * scale) + self.camera.translate(t) + + self.BBox_edges.push_to_GPU() + self.BBox_faces.push_to_GPU() + + self.camera.update() + + self.mouseMotion = [0., 0.] + self.wheelPosition = 0 + + def draw(self): + vpMatrix = self.camera.getViewProjectionMatrix() + + glUseProgram(self.shader_pc.get_program_id()) + glUniformMatrix4fv(self.shader_pc_MVP, 1, GL_TRUE, (GLfloat * len(vpMatrix))(*vpMatrix)) + glPointSize(1.2) + self.point_cloud.draw() + glUseProgram(0) + + glUseProgram(self.shader_image.get_program_id()) + glUniformMatrix4fv(self.shader_image_MVP, 1, GL_TRUE, (GLfloat * len(vpMatrix))(*vpMatrix)) + glLineWidth(4.) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + self.zedModel.draw() + self.BBox_faces.draw() + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) + glLineWidth(2.) + self.BBox_edges.draw() + glUseProgram(0) + + +class CameraGL: + def __init__(self): + self.ORIGINAL_FORWARD = sl.Translation() + self.ORIGINAL_FORWARD.init_vector(0, 0, 1) + self.ORIGINAL_UP = sl.Translation() + self.ORIGINAL_UP.init_vector(0, 1, 0) + self.ORIGINAL_RIGHT = sl.Translation() + self.ORIGINAL_RIGHT.init_vector(1, 0, 0) + self.znear = 0.5 + self.zfar = 100. + self.horizontalFOV = 70. + self.orientation_ = sl.Orientation() + self.position_ = sl.Translation() + self.forward_ = sl.Translation() + self.up_ = sl.Translation() + self.right_ = sl.Translation() + self.vertical_ = sl.Translation() + self.vpMatrix_ = sl.Matrix4f() + self.offset_ = sl.Translation() + self.offset_.init_vector(0, 0, 5) + self.projection_ = sl.Matrix4f() + self.projection_.set_identity() + self.setProjection(1.78) + + self.position_.init_vector(0., 0., 0.) + tmp = sl.Translation() + tmp.init_vector(0, 0, -.1) + tmp2 = sl.Translation() + tmp2.init_vector(0, 1, 0) + self.setDirection(tmp, tmp2) + + def update(self): + dot_ = sl.Translation.dot_translation(self.vertical_, self.up_) + if (dot_ < 0.): + tmp = self.vertical_.get() + self.vertical_.init_vector(tmp[0] * -1., tmp[1] * -1., tmp[2] * -1.) + transformation = sl.Transform() + + tmp_position = self.position_.get() + tmp = (self.offset_ * self.orientation_).get() + new_position = sl.Translation() + new_position.init_vector(tmp_position[0] + tmp[0], tmp_position[1] + tmp[1], tmp_position[2] + tmp[2]) + transformation.init_orientation_translation(self.orientation_, new_position) + transformation.inverse() + self.vpMatrix_ = self.projection_ * transformation + + def setProjection(self, im_ratio): + fov_x = self.horizontalFOV * 3.1416 / 180. + fov_y = self.horizontalFOV * im_ratio * 3.1416 / 180. + + self.projection_[(0, 0)] = 1. / math.tan(fov_x * .5) + self.projection_[(1, 1)] = 1. / math.tan(fov_y * .5) + self.projection_[(2, 2)] = -(self.zfar + self.znear) / (self.zfar - self.znear) + self.projection_[(3, 2)] = -1. + self.projection_[(2, 3)] = -(2. * self.zfar * self.znear) / (self.zfar - self.znear) + self.projection_[(3, 3)] = 0. + + def getViewProjectionMatrix(self): + tmp = self.vpMatrix_.m + vpMat = array.array('f') + for row in tmp: + for v in row: + vpMat.append(v) + return vpMat + + def getViewProjectionMatrixRT(self, tr): + tmp = self.vpMatrix_ + tmp.transpose() + tr.transpose() + tmp = (tr * tmp).m + vpMat = array.array('f') + for row in tmp: + for v in row: + vpMat.append(v) + return vpMat + + def setDirection(self, dir, vert): + dir.normalize() + tmp = dir.get() + dir.init_vector(tmp[0] * -1., tmp[1] * -1., tmp[2] * -1.) + self.orientation_.init_translation(self.ORIGINAL_FORWARD, dir) + self.updateVectors() + self.vertical_ = vert + if (sl.Translation.dot_translation(self.vertical_, self.up_) < 0.): + tmp = sl.Rotation() + tmp.init_angle_translation(3.14, self.ORIGINAL_FORWARD) + self.rotate(tmp) + + def translate(self, t): + ref = self.position_.get() + tmp = t.get() + self.position_.init_vector(ref[0] + tmp[0], ref[1] + tmp[1], ref[2] + tmp[2]) + + def setPosition(self, p): + self.position_ = p + + def rotate(self, r): + tmp = sl.Orientation() + tmp.init_rotation(r) + self.orientation_ = tmp * self.orientation_ + self.updateVectors() + + def setRotation(self, r): + self.orientation_.init_rotation(r) + self.updateVectors() + + def updateVectors(self): + self.forward_ = self.ORIGINAL_FORWARD * self.orientation_ + self.up_ = self.ORIGINAL_UP * self.orientation_ + right = self.ORIGINAL_RIGHT + tmp = right.get() + right.init_vector(tmp[0] * -1., tmp[1] * -1., tmp[2] * -1.) + self.right_ = right * self.orientation_ diff --git a/workflow-test/ogl_viewer/zed_model.py b/workflow-test/ogl_viewer/zed_model.py new file mode 100644 index 0000000..f0a23ff --- /dev/null +++ b/workflow-test/ogl_viewer/zed_model.py @@ -0,0 +1,2736 @@ +import numpy as np + + +class Color: + def __init__(self, pr, pg, pb): + self.r = pr + self.g = pg + self.b = pb + + +NB_ALLUMINIUM_TRIANGLES = 54 +NB_DARK_TRIANGLES = 54 +ALLUMINIUM_COLOR = Color(0.79, 0.82, 0.93) +DARK_COLOR = Color(0.07, 0.07, 0.07) + +vertices = np.array([ + -0.068456, -0.016299, 0.016299 + , -0.068456, 0.016299, 0.016299 + , -0.068456, 0.016299, -0.016299 + , -0.068456, -0.016299, -0.016299 + , -0.076606, 0.014115, 0.016299 + , -0.082572, 0.008150, 0.016299 + , -0.084755, -0.000000, 0.016299 + , -0.082572, -0.008150, 0.016299 + , -0.076606, -0.014115, 0.016299 + , -0.076606, -0.014115, -0.016299 + , -0.082572, -0.008150, -0.016299 + , -0.084755, -0.000000, -0.016299 + , -0.082572, 0.008150, -0.016299 + , -0.076606, 0.014115, -0.016299 + , -0.053494, -0.009779, -0.016299 + , -0.048604, -0.008469, -0.016299 + , -0.045024, -0.004890, -0.016299 + , -0.043714, 0.000000, -0.016299 + , -0.045024, 0.004890, -0.016299 + , -0.048604, 0.008469, -0.016299 + , -0.053494, 0.009779, -0.016299 + , -0.058383, 0.008469, -0.016299 + , -0.061963, 0.004890, -0.016299 + , -0.063273, 0.000000, -0.016299 + , -0.061963, -0.004890, -0.016299 + , -0.058383, -0.008469, -0.016299 + , 0.000000, -0.016299, -0.016299 + , 0.068456, -0.016299, 0.016299 + , 0.000000, 0.016299, -0.016299 + , 0.068456, 0.016299, 0.016299 + , 0.068456, 0.016299, -0.016299 + , 0.068456, -0.016299, -0.016299 + , 0.076606, 0.014115, 0.016299 + , 0.082572, 0.008150, 0.016299 + , 0.084755, -0.000000, 0.016299 + , 0.082572, -0.008150, 0.016299 + , 0.076606, -0.014115, 0.016299 + , 0.076606, -0.014115, -0.016299 + , 0.082572, -0.008150, -0.016299 + , 0.084755, -0.000000, -0.016299 + , 0.082572, 0.008150, -0.016299 + , 0.076606, 0.014115, -0.016299 + , 0.053494, -0.009779, -0.016299 + , 0.048604, -0.008469, -0.016299 + , 0.045024, -0.004890, -0.016299 + , 0.043714, 0.000000, -0.016299 + , 0.045024, 0.004890, -0.016299 + , 0.048604, 0.008469, -0.016299 + , 0.053494, 0.009779, -0.016299 + , 0.058383, 0.008469, -0.016299 + , 0.061963, 0.004890, -0.016299 + , 0.063273, 0.000000, -0.016299 + , 0.061963, -0.004890, -0.016299 + , 0.058383, -0.008469, -0.016299 + , 0.053494, 0.000000, -0.016299 + , -0.053494, 0.000000, -0.016299 +]) + +alluminium_triangles = np.array([ + 1, 10, 4 + , 6, 14, 13 + , 7, 13, 12 + , 8, 12, 11 + , 9, 11, 10 + , 5, 3, 14 + , 44, 45, 55 + , 47, 48, 55 + , 43, 44, 55 + , 46, 47, 55 + , 52, 53, 55 + , 48, 49, 55 + , 54, 43, 55 + , 50, 51, 55 + , 53, 54, 55 + , 49, 50, 55 + , 45, 46, 55 + , 51, 52, 55 + , 27, 32, 28 + , 38, 28, 32 + , 42, 34, 41 + , 41, 35, 40 + , 40, 36, 39 + , 39, 37, 38 + , 31, 33, 42 + , 27, 1, 4 + , 20, 19, 56 + , 22, 21, 56 + , 23, 22, 56 + , 24, 23, 56 + , 19, 18, 56 + , 21, 20, 56 + , 17, 16, 56 + , 26, 25, 56 + , 15, 26, 56 + , 18, 17, 56 + , 16, 15, 56 + , 25, 24, 56 + , 2, 29, 3 + , 31, 29, 30 + , 1, 9, 10 + , 6, 5, 14 + , 7, 6, 13 + , 8, 7, 12 + , 9, 8, 11 + , 5, 2, 3 + , 38, 37, 28 + , 42, 33, 34 + , 41, 34, 35 + , 40, 35, 36 + , 39, 36, 37 + , 31, 30, 33 + , 27, 28, 1 + , 2, 30, 29 +]) + +dark_triangles = np.array([ + 23, 3, 22 + , 13, 10, 11 + , 4, 14, 3 + , 11, 12, 13 + , 9, 6, 8 + , 1, 5, 9 + , 8, 6, 7 + , 1, 30, 2 + , 21, 22, 3 + , 23, 24, 3 + , 24, 25, 4 + , 3, 24, 4 + , 25, 26, 4 + , 26, 15, 4 + , 16, 17, 27 + , 17, 18, 27 + , 18, 19, 29 + , 27, 18, 29 + , 19, 20, 29 + , 20, 21, 29 + , 3, 29, 21 + , 16, 27, 15 + , 27, 4, 15 + , 51, 50, 31 + , 38, 41, 39 + , 32, 42, 38 + , 39, 41, 40 + , 34, 37, 36 + , 28, 33, 30 + , 36, 35, 34 + , 49, 31, 50 + , 51, 31, 52 + , 52, 32, 53 + , 31, 32, 52 + , 53, 32, 54 + , 54, 32, 43 + , 44, 27, 45 + , 45, 27, 46 + , 46, 29, 47 + , 27, 29, 46 + , 47, 29, 48 + , 48, 29, 49 + , 31, 49, 29 + , 44, 43, 27 + , 27, 43, 32 + , 13, 14, 10 + , 4, 10, 14 + , 9, 5, 6 + , 1, 2, 5 + , 1, 28, 30 + , 38, 42, 41 + , 32, 31, 42 + , 34, 33, 37 + , 28, 37, 33 +]) + +vertices_m = np.array([ + 0.030800, 0.013300, 0.000001 + , 0.058785, 0.013300, -0.002250 + , 0.058785, 0.013300, 0.002251 + , 0.059839, 0.013300, -0.001999 + , 0.060770, 0.013300, -0.001351 + , 0.059839, 0.013300, 0.002000 + , 0.060770, 0.013300, 0.001352 + , 0.002815, 0.013300, -0.002250 + , 0.002815, 0.013300, 0.002251 + , 0.001761, 0.013300, -0.001999 + , 0.000830, 0.013300, -0.001351 + , 0.001761, 0.013300, 0.002000 + , 0.000830, 0.013300, 0.001352 + , 0.061449, 0.013300, -0.000563 + , 0.061449, 0.013300, 0.000564 + , 0.000152, 0.013300, 0.000564 + , 0.000152, 0.013300, -0.000563 + , 0.030800, -0.013333, 0.000001 + , 0.058785, -0.013333, -0.002250 + , 0.058785, -0.013333, 0.002251 + , 0.059839, -0.013333, -0.001999 + , 0.060770, -0.013333, -0.001351 + , 0.059839, -0.013333, 0.002000 + , 0.060770, -0.013333, 0.001352 + , 0.002815, -0.013333, -0.002250 + , 0.002815, -0.013333, 0.002251 + , 0.001761, -0.013333, -0.001999 + , 0.000830, -0.013333, -0.001351 + , 0.001761, -0.013333, 0.002000 + , 0.000830, -0.013333, 0.001352 + , 0.061449, -0.013333, 0.000564 + , 0.061449, -0.013333, -0.000563 + , 0.000152, -0.013333, -0.000563 + , 0.000152, -0.013333, 0.000564 + , -0.031684, 0.009412, 0.000501 + , -0.031809, 0.008300, 0.000501 + , -0.028977, 0.012805, 0.000501 + , -0.029926, 0.012209, 0.000501 + , -0.026809, 0.013300, 0.000501 + , -0.027920, 0.013175, 0.000501 + , -0.030718, 0.011417, 0.000501 + , -0.031314, 0.010469, 0.000501 + , -0.031809, -0.008310, 0.000501 + , -0.031684, -0.009431, 0.000501 + , -0.028977, -0.012824, 0.000501 + , -0.029926, -0.012228, 0.000501 + , -0.026847, -0.013300, 0.000500 + , -0.027920, -0.013194, 0.000501 + , -0.030718, -0.011437, 0.000501 + , -0.031314, -0.010488, 0.000501 + , -0.031684, 0.009412, -0.000500 + , -0.031809, 0.008300, -0.000500 + , -0.028977, 0.012805, -0.000500 + , -0.029926, 0.012209, -0.000500 + , -0.026809, 0.013300, -0.000500 + , -0.027920, 0.013175, -0.000500 + , -0.030718, 0.011417, -0.000500 + , -0.031314, 0.010469, -0.000500 + , -0.031809, -0.008310, -0.000500 + , -0.031684, -0.009431, -0.000500 + , -0.029926, -0.012228, -0.000500 + , -0.028977, -0.012824, -0.000500 + , -0.027920, -0.013194, -0.000500 + , -0.026847, -0.013300, -0.000500 + , -0.031314, -0.010488, -0.000500 + , -0.030718, -0.011437, -0.000500 + , -0.031809, 0.006354, -0.000500 + , -0.031809, 0.006354, 0.000501 + , -0.031809, -0.006364, -0.000500 + , -0.031809, -0.006364, 0.000501 + , -0.031809, 0.005707, -0.000700 + , -0.031809, 0.005707, 0.000701 + , -0.031809, -0.005716, -0.000700 + , -0.031809, -0.005716, 0.000701 + , -0.031809, 0.005128, -0.001423 + , -0.031809, 0.005128, 0.001424 + , -0.031809, -0.005138, -0.001423 + , -0.031809, -0.005138, 0.001424 + , -0.031809, 0.004146, -0.002297 + , -0.031809, 0.004146, 0.002299 + , -0.031809, -0.004156, -0.002297 + , -0.031809, -0.004156, 0.002299 + , -0.031809, 0.003313, -0.002495 + , -0.031809, 0.003313, 0.002497 + , -0.031809, -0.003322, -0.002495 + , -0.031809, -0.003322, 0.002497 + , -0.031809, -0.000005, 0.000001 + , -0.026800, 0.013300, -0.000500 + , -0.026800, 0.013300, 0.000501 + , 0.088376, 0.013300, -0.000500 + , 0.088376, 0.013300, 0.000501 + , 0.093228, 0.009412, 0.000501 + , 0.093353, 0.008300, 0.000501 + , 0.090522, 0.012805, 0.000501 + , 0.091470, 0.012209, 0.000501 + , 0.089464, 0.013175, 0.000501 + , 0.092262, 0.011417, 0.000501 + , 0.092858, 0.010469, 0.000501 + , 0.093353, -0.008310, 0.000501 + , 0.093228, -0.009431, 0.000501 + , 0.090522, -0.012824, 0.000501 + , 0.091470, -0.012228, 0.000501 + , 0.088376, -0.013321, 0.000501 + , 0.089464, -0.013194, 0.000501 + , 0.092262, -0.011437, 0.000501 + , 0.092858, -0.010488, 0.000501 + , 0.093228, 0.009412, -0.000500 + , 0.093353, 0.008300, -0.000500 + , 0.090522, 0.012805, -0.000500 + , 0.091470, 0.012209, -0.000500 + , 0.089464, 0.013175, -0.000500 + , 0.092262, 0.011417, -0.000500 + , 0.092858, 0.010469, -0.000500 + , 0.093353, -0.008310, -0.000500 + , 0.093228, -0.009431, -0.000500 + , 0.091470, -0.012228, -0.000500 + , 0.090522, -0.012824, -0.000500 + , 0.089464, -0.013194, -0.000500 + , 0.088376, -0.013321, -0.000500 + , 0.092858, -0.010488, -0.000500 + , 0.092262, -0.011437, -0.000500 + , -0.001600, 0.000000, -0.018000 + , 0.017592, 0.000000, -0.018000 + , 0.007996, -0.009596, -0.018000 + , 0.007996, -0.009763, -0.008431 + , 0.007996, 0.009763, -0.008431 + , 0.007996, 0.009596, -0.018000 + , -0.001767, 0.000000, -0.008431 + , 0.002258, -0.007899, -0.008431 + , 0.002356, -0.007764, -0.018000 + , 0.005033, -0.009127, -0.018000 + , 0.004982, -0.009286, -0.008431 + , 0.000097, -0.005738, -0.008431 + , 0.000232, -0.005640, -0.018000 + , -0.001131, -0.002963, -0.018000 + , -0.001290, -0.003014, -0.008431 + , 0.000097, 0.005738, -0.008431 + , 0.000232, 0.005640, -0.018000 + , -0.001131, 0.002963, -0.018000 + , -0.001290, 0.003014, -0.008431 + , 0.002258, 0.007899, -0.008431 + , 0.002356, 0.007764, -0.018000 + , 0.005033, 0.009127, -0.018000 + , 0.004982, 0.009286, -0.008431 + , 0.017759, 0.000000, -0.008431 + , 0.013734, 0.007899, -0.008431 + , 0.013636, 0.007764, -0.018000 + , 0.010959, 0.009127, -0.018000 + , 0.011010, 0.009286, -0.008431 + , 0.015895, 0.005738, -0.008431 + , 0.015760, 0.005640, -0.018000 + , 0.017123, 0.002963, -0.018000 + , 0.017282, 0.003014, -0.008431 + , 0.015895, -0.005738, -0.008431 + , 0.015760, -0.005640, -0.018000 + , 0.017123, -0.002963, -0.018000 + , 0.017282, -0.003014, -0.008431 + , 0.013734, -0.007899, -0.008431 + , 0.013636, -0.007764, -0.018000 + , 0.010959, -0.009127, -0.018000 + , 0.011010, -0.009286, -0.008431 + , 0.004827, 0.009763, -0.007940 + , 0.007996, 0.010264, -0.007940 + , -0.001767, -0.003169, -0.007940 + , -0.002269, 0.000000, -0.007940 + , 0.004827, -0.009763, -0.007940 + , 0.001963, -0.008304, -0.007940 + , 0.007996, -0.010264, -0.007940 + , -0.000308, -0.006033, -0.007940 + , -0.001767, 0.003169, -0.007940 + , -0.000308, 0.006033, -0.007940 + , 0.001963, 0.008304, -0.007940 + , 0.011165, -0.009763, -0.007940 + , 0.017759, 0.003169, -0.007940 + , 0.018260, -0.000000, -0.007940 + , 0.011165, 0.009763, -0.007940 + , 0.014029, 0.008304, -0.007940 + , 0.016300, 0.006033, -0.007940 + , 0.017759, -0.003169, -0.007940 + , 0.016300, -0.006033, -0.007940 + , 0.014029, -0.008304, -0.007940 + , 0.002356, -0.007764, -0.019500 + , 0.005033, -0.009127, -0.019500 + , 0.007996, -0.009596, -0.019500 + , 0.000232, -0.005640, -0.019500 + , -0.001600, 0.000000, -0.019500 + , -0.001131, -0.002963, -0.019500 + , 0.000232, 0.005640, -0.019500 + , -0.001131, 0.002963, -0.019500 + , 0.002356, 0.007764, -0.019500 + , 0.007996, 0.009596, -0.019500 + , 0.005033, 0.009127, -0.019500 + , 0.013636, 0.007764, -0.019500 + , 0.010959, 0.009127, -0.019500 + , 0.015760, 0.005640, -0.019500 + , 0.017592, 0.000000, -0.019500 + , 0.017123, 0.002963, -0.019500 + , 0.015760, -0.005640, -0.019500 + , 0.017123, -0.002963, -0.019500 + , 0.013636, -0.007764, -0.019500 + , 0.010959, -0.009127, -0.019500 + , 0.002356, -0.007764, -0.022997 + , 0.005033, -0.009127, -0.022997 + , 0.007996, -0.009596, -0.022997 + , 0.000232, -0.005640, -0.022997 + , -0.001600, 0.000000, -0.022997 + , -0.001131, -0.002963, -0.022997 + , 0.000232, 0.005640, -0.022997 + , -0.001131, 0.002963, -0.022997 + , 0.002356, 0.007764, -0.022997 + , 0.007996, 0.009596, -0.022997 + , 0.005033, 0.009127, -0.022997 + , 0.013636, 0.007764, -0.022997 + , 0.010959, 0.009127, -0.022997 + , 0.015760, 0.005640, -0.022997 + , 0.017592, 0.000000, -0.022997 + , 0.017123, 0.002963, -0.022997 + , 0.015760, -0.005640, -0.022997 + , 0.017123, -0.002963, -0.022997 + , 0.013636, -0.007764, -0.022997 + , 0.010959, -0.009127, -0.022997 + , 0.002745, -0.007227, -0.022997 + , 0.005238, -0.008497, -0.022997 + , 0.007996, -0.008933, -0.022997 + , 0.000769, -0.005250, -0.022997 + , -0.000937, 0.000000, -0.022997 + , -0.000501, -0.002758, -0.022997 + , 0.000769, 0.005250, -0.022997 + , -0.000501, 0.002758, -0.022997 + , 0.002745, 0.007227, -0.022997 + , 0.007996, 0.008933, -0.022997 + , 0.005238, 0.008497, -0.022997 + , 0.013246, 0.007227, -0.022997 + , 0.010754, 0.008497, -0.022997 + , 0.015223, 0.005250, -0.022997 + , 0.016929, 0.000000, -0.022997 + , 0.016493, 0.002758, -0.022997 + , 0.015223, -0.005250, -0.022997 + , 0.016493, -0.002758, -0.022997 + , 0.013246, -0.007227, -0.022997 + , 0.010754, -0.008497, -0.022997 + , 0.004095, -0.005369, -0.022203 + , 0.005947, -0.006313, -0.022203 + , 0.007996, -0.006637, -0.022203 + , 0.002626, -0.003901, -0.022203 + , 0.001359, 0.000000, -0.022203 + , 0.001683, -0.002049, -0.022203 + , 0.002626, 0.003901, -0.022203 + , 0.001683, 0.002049, -0.022203 + , 0.004095, 0.005369, -0.022203 + , 0.007996, 0.006637, -0.022203 + , 0.005947, 0.006313, -0.022203 + , 0.011897, 0.005369, -0.022203 + , 0.010045, 0.006313, -0.022203 + , 0.013365, 0.003901, -0.022203 + , 0.014633, 0.000000, -0.022203 + , 0.014308, 0.002049, -0.022203 + , 0.013365, -0.003901, -0.022203 + , 0.014308, -0.002049, -0.022203 + , 0.011897, -0.005369, -0.022203 + , 0.010045, -0.006313, -0.022203 + , 0.004446, -0.004886, -0.021500 + , 0.006131, -0.005744, -0.021500 + , 0.007996, -0.006039, -0.021500 + , 0.003110, -0.003549, -0.021500 + , 0.001957, 0.000000, -0.021500 + , 0.002252, -0.001865, -0.021500 + , 0.003110, 0.003549, -0.021500 + , 0.002252, 0.001865, -0.021500 + , 0.004446, 0.004886, -0.021500 + , 0.007996, 0.006039, -0.021500 + , 0.006131, 0.005744, -0.021500 + , 0.011545, 0.004886, -0.021500 + , 0.009861, 0.005744, -0.021500 + , 0.012882, 0.003549, -0.021500 + , 0.014035, 0.000000, -0.021500 + , 0.013740, 0.001865, -0.021500 + , 0.012882, -0.003549, -0.021500 + , 0.013740, -0.001865, -0.021500 + , 0.011545, -0.004886, -0.021500 + , 0.009861, -0.005744, -0.021500 + , 0.004446, -0.004886, -0.020078 + , 0.006131, -0.005744, -0.020078 + , 0.007996, -0.006039, -0.020078 + , 0.003110, -0.003549, -0.020078 + , 0.001957, 0.000000, -0.020078 + , 0.002252, -0.001865, -0.020078 + , 0.003110, 0.003549, -0.020078 + , 0.002252, 0.001865, -0.020078 + , 0.004446, 0.004886, -0.020078 + , 0.007996, 0.006039, -0.020078 + , 0.006131, 0.005744, -0.020078 + , 0.011545, 0.004886, -0.020078 + , 0.009861, 0.005744, -0.020078 + , 0.012882, 0.003549, -0.020078 + , 0.014035, 0.000000, -0.020078 + , 0.013740, 0.001865, -0.020078 + , 0.012882, -0.003549, -0.020078 + , 0.013740, -0.001865, -0.020078 + , 0.011545, -0.004886, -0.020078 + , 0.009861, -0.005744, -0.020078 + , -0.026847, -0.013300, -0.006500 + , -0.031847, -0.008300, -0.006500 + , -0.029965, -0.012209, -0.006500 + , -0.027959, -0.013175, -0.006500 + , -0.029016, -0.012805, -0.006500 + , -0.031352, -0.010469, -0.006500 + , -0.030756, -0.011417, -0.006500 + , -0.031722, -0.009412, -0.006500 + , 0.088353, -0.013310, -0.006500 + , -0.031847, 0.008300, -0.006500 + , -0.026847, 0.013300, -0.006500 + , -0.030756, 0.011417, -0.006500 + , -0.031722, 0.009412, -0.006500 + , -0.031352, 0.010469, -0.006500 + , -0.029016, 0.012805, -0.006500 + , -0.029965, 0.012209, -0.006500 + , -0.027959, 0.013175, -0.006500 + , 0.088353, 0.013300, -0.006500 + , 0.093353, 0.008300, -0.006500 + , 0.091470, 0.012209, -0.006500 + , 0.089464, 0.013175, -0.006500 + , 0.090522, 0.012805, -0.006500 + , 0.092858, 0.010469, -0.006500 + , 0.092262, 0.011417, -0.006500 + , 0.093228, 0.009412, -0.006500 + , 0.093353, -0.008310, -0.006500 + , 0.091470, -0.012228, -0.006500 + , 0.089464, -0.013194, -0.006500 + , 0.090522, -0.012824, -0.006500 + , 0.092858, -0.010488, -0.006500 + , 0.092262, -0.011437, -0.006500 + , 0.093228, -0.009431, -0.006500 + , -0.031722, -0.009412, -0.002250 + , -0.031809, -0.004156, -0.002297 + , -0.029016, -0.012805, -0.002250 + , -0.029965, -0.012209, -0.002250 + , -0.026847, -0.013300, -0.002250 + , -0.027959, -0.013175, -0.002250 + , -0.030756, -0.011417, -0.002250 + , -0.031352, -0.010469, -0.002250 + , 0.088353, -0.013310, -0.002250 + , -0.031809, 0.004146, -0.002297 + , -0.027959, 0.013175, -0.002250 + , -0.026847, 0.013300, -0.002250 + , -0.031352, 0.010469, -0.002250 + , -0.030756, 0.011417, -0.002250 + , -0.031722, 0.009412, -0.002250 + , -0.029965, 0.012209, -0.002250 + , -0.029016, 0.012805, -0.002250 + , 0.088353, 0.013300, -0.002250 + , 0.093228, 0.009412, -0.002250 + , 0.093353, 0.008300, -0.002250 + , 0.090522, 0.012805, -0.002250 + , 0.091470, 0.012209, -0.002250 + , 0.089464, 0.013175, -0.002250 + , 0.092262, 0.011417, -0.002250 + , 0.092858, 0.010469, -0.002250 + , 0.093353, -0.008310, -0.002250 + , 0.093228, -0.009431, -0.002250 + , 0.090522, -0.012824, -0.002250 + , 0.091470, -0.012228, -0.002250 + , 0.089464, -0.013194, -0.002250 + , 0.092262, -0.011437, -0.002250 + , 0.092858, -0.010488, -0.002250 + , 0.002815, -0.013333, -0.002250 + , 0.001761, 0.013300, -0.001999 + , 0.058785, -0.013333, -0.002250 + , 0.059839, 0.013300, -0.001999 + , -0.031722, -0.009412, -0.000500 + , -0.031847, -0.006340, -0.000500 + , -0.029016, -0.012805, -0.000500 + , -0.029965, -0.012209, -0.000500 + , -0.026847, -0.013300, -0.000500 + , -0.027959, -0.013175, -0.000500 + , -0.030756, -0.011417, -0.000500 + , -0.031352, -0.010469, -0.000500 + , 0.000152, -0.013333, -0.000563 + , -0.031847, 0.006354, -0.000500 + , -0.027959, 0.013175, -0.000500 + , -0.026847, 0.013300, -0.000500 + , -0.031352, 0.010469, -0.000500 + , -0.030756, 0.011417, -0.000500 + , -0.031722, 0.009412, -0.000500 + , -0.029965, 0.012209, -0.000500 + , -0.029016, 0.012805, -0.000500 + , 0.088353, 0.013300, -0.000500 + , 0.061448, 0.013300, -0.000563 + , 0.093228, 0.009412, -0.000500 + , 0.093353, 0.008300, -0.000500 + , 0.090522, 0.012805, -0.000500 + , 0.091470, 0.012209, -0.000500 + , 0.089464, 0.013175, -0.000500 + , 0.092262, 0.011417, -0.000500 + , 0.092858, 0.010469, -0.000500 + , 0.093353, -0.008310, -0.000500 + , 0.093228, -0.009431, -0.000500 + , 0.090522, -0.012824, -0.000500 + , 0.091470, -0.012228, -0.000500 + , 0.088353, -0.013310, -0.000500 + , 0.089464, -0.013194, -0.000500 + , 0.092262, -0.011437, -0.000500 + , 0.092858, -0.010488, -0.000500 + , 0.000151, 0.013300, -0.000563 + , 0.061448, -0.013333, -0.000563 + , 0.058800, 0.013300, -0.002250 + , 0.002815, 0.013300, -0.002250 + , 0.000830, 0.013300, -0.001351 + , 0.060770, 0.013300, -0.001351 + , 0.060770, -0.013333, -0.001351 + , 0.059839, -0.013333, -0.001999 + , 0.000830, -0.013333, -0.001351 + , 0.001761, -0.013333, -0.001999 + , -0.026844, -0.011518, -0.007940 + , -0.026847, -0.011634, -0.007898 + , -0.027589, -0.011551, -0.007898 + , -0.027563, -0.011437, -0.007940 + , -0.028294, -0.011304, -0.007898 + , -0.028243, -0.011199, -0.007940 + , -0.028926, -0.010907, -0.007898 + , -0.028854, -0.010816, -0.007940 + , -0.029454, -0.010379, -0.007898 + , -0.029363, -0.010306, -0.007940 + , -0.029852, -0.009746, -0.007898 + , -0.029747, -0.009696, -0.007940 + , -0.030098, -0.009041, -0.007898 + , -0.029985, -0.009016, -0.007940 + , -0.030181, -0.008300, -0.007898 + , -0.030066, -0.008297, -0.007940 + , -0.030181, 0.008300, -0.007898 + , -0.030065, 0.008296, -0.007940 + , -0.030098, 0.009041, -0.007898 + , -0.029985, 0.009015, -0.007940 + , -0.029852, 0.009746, -0.007898 + , -0.029747, 0.009696, -0.007940 + , -0.029454, 0.010379, -0.007898 + , -0.029363, 0.010306, -0.007940 + , -0.028926, 0.010907, -0.007898 + , -0.028854, 0.010816, -0.007940 + , -0.028294, 0.011304, -0.007898 + , -0.028243, 0.011199, -0.007940 + , -0.027589, 0.011551, -0.007898 + , -0.027563, 0.011437, -0.007940 + , -0.026847, 0.011634, -0.007898 + , -0.026844, 0.011518, -0.007940 + , 0.088349, 0.011518, -0.007940 + , 0.088353, 0.011634, -0.007898 + , 0.089094, 0.011551, -0.007898 + , 0.089068, 0.011437, -0.007940 + , 0.089799, 0.011304, -0.007898 + , 0.089749, 0.011199, -0.007940 + , 0.090432, 0.010907, -0.007898 + , 0.090359, 0.010816, -0.007940 + , 0.090960, 0.010379, -0.007898 + , 0.090869, 0.010306, -0.007940 + , 0.091357, 0.009746, -0.007898 + , 0.091252, 0.009696, -0.007940 + , 0.091604, 0.009041, -0.007898 + , 0.091490, 0.009016, -0.007940 + , 0.091637, 0.008187, -0.007940 + , 0.091724, 0.008300, -0.007867 + , 0.088353, -0.011644, -0.007898 + , 0.088349, -0.011528, -0.007940 + , 0.089094, -0.011570, -0.007898 + , 0.089069, -0.011456, -0.007940 + , 0.089799, -0.011323, -0.007898 + , 0.089749, -0.011219, -0.007940 + , 0.090432, -0.010926, -0.007898 + , 0.090359, -0.010835, -0.007940 + , 0.090960, -0.010398, -0.007898 + , 0.090869, -0.010325, -0.007940 + , 0.091357, -0.009766, -0.007898 + , 0.091252, -0.009715, -0.007940 + , 0.091604, -0.009061, -0.007898 + , 0.091490, -0.009035, -0.007940 + , 0.091724, -0.008310, -0.007867 + , 0.091637, -0.008196, -0.007940 + , -0.031809, -0.003322, -0.002495 + , -0.031809, 0.003313, -0.002495 + , -0.031809, 0.005707, -0.000700 + , -0.031809, 0.005128, -0.001423 + , -0.031809, -0.005716, -0.000700 + , -0.031809, -0.005138, -0.001423 + , 0.061397, 0.000000, -0.018000 + , 0.080589, 0.000000, -0.018000 + , 0.070993, -0.009596, -0.018000 + , 0.070993, -0.009763, -0.008431 + , 0.070993, 0.009763, -0.008431 + , 0.070993, 0.009596, -0.018000 + , 0.061230, 0.000000, -0.008431 + , 0.065255, -0.007899, -0.008431 + , 0.065353, -0.007764, -0.018000 + , 0.068030, -0.009127, -0.018000 + , 0.067979, -0.009286, -0.008431 + , 0.063094, -0.005738, -0.008431 + , 0.063229, -0.005640, -0.018000 + , 0.061866, -0.002963, -0.018000 + , 0.061707, -0.003014, -0.008431 + , 0.063094, 0.005738, -0.008431 + , 0.063229, 0.005640, -0.018000 + , 0.061866, 0.002963, -0.018000 + , 0.061707, 0.003014, -0.008431 + , 0.065255, 0.007899, -0.008431 + , 0.065353, 0.007764, -0.018000 + , 0.068030, 0.009127, -0.018000 + , 0.067979, 0.009286, -0.008431 + , 0.080756, 0.000000, -0.008431 + , 0.076731, 0.007899, -0.008431 + , 0.076633, 0.007764, -0.018000 + , 0.073956, 0.009127, -0.018000 + , 0.074007, 0.009286, -0.008431 + , 0.078892, 0.005738, -0.008431 + , 0.078757, 0.005640, -0.018000 + , 0.080120, 0.002963, -0.018000 + , 0.080279, 0.003014, -0.008431 + , 0.078892, -0.005738, -0.008431 + , 0.078757, -0.005640, -0.018000 + , 0.080120, -0.002963, -0.018000 + , 0.080279, -0.003014, -0.008431 + , 0.076731, -0.007899, -0.008431 + , 0.076633, -0.007764, -0.018000 + , 0.073956, -0.009127, -0.018000 + , 0.074007, -0.009286, -0.008431 + , 0.067824, 0.009763, -0.007940 + , 0.070993, 0.010264, -0.007940 + , 0.061230, -0.003169, -0.007940 + , 0.060728, 0.000000, -0.007940 + , 0.067824, -0.009763, -0.007940 + , 0.064960, -0.008304, -0.007940 + , 0.070993, -0.010264, -0.007940 + , 0.062688, -0.006033, -0.007940 + , 0.061230, 0.003169, -0.007940 + , 0.062688, 0.006033, -0.007940 + , 0.064960, 0.008304, -0.007940 + , 0.074162, -0.009763, -0.007940 + , 0.080756, 0.003169, -0.007940 + , 0.081257, -0.000000, -0.007940 + , 0.074162, 0.009763, -0.007940 + , 0.077026, 0.008304, -0.007940 + , 0.079297, 0.006033, -0.007940 + , 0.080756, -0.003169, -0.007940 + , 0.079297, -0.006033, -0.007940 + , 0.077026, -0.008304, -0.007940 + , 0.065353, -0.007764, -0.019500 + , 0.068030, -0.009127, -0.019500 + , 0.070993, -0.009596, -0.019500 + , 0.063229, -0.005640, -0.019500 + , 0.061397, 0.000000, -0.019500 + , 0.061866, -0.002963, -0.019500 + , 0.063229, 0.005640, -0.019500 + , 0.061866, 0.002963, -0.019500 + , 0.065353, 0.007764, -0.019500 + , 0.070993, 0.009596, -0.019500 + , 0.068030, 0.009127, -0.019500 + , 0.076633, 0.007764, -0.019500 + , 0.073956, 0.009127, -0.019500 + , 0.078757, 0.005640, -0.019500 + , 0.080589, 0.000000, -0.019500 + , 0.080120, 0.002963, -0.019500 + , 0.078757, -0.005640, -0.019500 + , 0.080120, -0.002963, -0.019500 + , 0.076633, -0.007764, -0.019500 + , 0.073956, -0.009127, -0.019500 + , 0.065353, -0.007764, -0.022997 + , 0.068030, -0.009127, -0.022997 + , 0.070993, -0.009596, -0.022997 + , 0.063229, -0.005640, -0.022997 + , 0.061397, 0.000000, -0.022997 + , 0.061866, -0.002963, -0.022997 + , 0.063229, 0.005640, -0.022997 + , 0.061866, 0.002963, -0.022997 + , 0.065353, 0.007764, -0.022997 + , 0.070993, 0.009596, -0.022997 + , 0.068030, 0.009127, -0.022997 + , 0.076633, 0.007764, -0.022997 + , 0.073956, 0.009127, -0.022997 + , 0.078757, 0.005640, -0.022997 + , 0.080589, 0.000000, -0.022997 + , 0.080120, 0.002963, -0.022997 + , 0.078757, -0.005640, -0.022997 + , 0.080120, -0.002963, -0.022997 + , 0.076633, -0.007764, -0.022997 + , 0.073956, -0.009127, -0.022997 + , 0.065742, -0.007227, -0.022997 + , 0.068235, -0.008497, -0.022997 + , 0.070993, -0.008933, -0.022997 + , 0.063766, -0.005250, -0.022997 + , 0.062060, 0.000000, -0.022997 + , 0.062496, -0.002758, -0.022997 + , 0.063766, 0.005250, -0.022997 + , 0.062496, 0.002758, -0.022997 + , 0.065742, 0.007227, -0.022997 + , 0.070993, 0.008933, -0.022997 + , 0.068235, 0.008497, -0.022997 + , 0.076243, 0.007227, -0.022997 + , 0.073751, 0.008497, -0.022997 + , 0.078220, 0.005250, -0.022997 + , 0.079926, 0.000000, -0.022997 + , 0.079490, 0.002758, -0.022997 + , 0.078220, -0.005250, -0.022997 + , 0.079490, -0.002758, -0.022997 + , 0.076243, -0.007227, -0.022997 + , 0.073751, -0.008497, -0.022997 + , 0.067092, -0.005369, -0.022203 + , 0.068944, -0.006313, -0.022203 + , 0.070993, -0.006637, -0.022203 + , 0.065623, -0.003901, -0.022203 + , 0.064356, 0.000000, -0.022203 + , 0.064680, -0.002049, -0.022203 + , 0.065623, 0.003901, -0.022203 + , 0.064680, 0.002049, -0.022203 + , 0.067092, 0.005369, -0.022203 + , 0.070993, 0.006637, -0.022203 + , 0.068944, 0.006313, -0.022203 + , 0.074894, 0.005369, -0.022203 + , 0.073042, 0.006313, -0.022203 + , 0.076362, 0.003901, -0.022203 + , 0.077630, 0.000000, -0.022203 + , 0.077305, 0.002049, -0.022203 + , 0.076362, -0.003901, -0.022203 + , 0.077305, -0.002049, -0.022203 + , 0.074894, -0.005369, -0.022203 + , 0.073042, -0.006313, -0.022203 + , 0.067443, -0.004886, -0.021500 + , 0.069128, -0.005744, -0.021500 + , 0.070993, -0.006039, -0.021500 + , 0.066107, -0.003549, -0.021500 + , 0.064954, 0.000000, -0.021500 + , 0.065249, -0.001865, -0.021500 + , 0.066107, 0.003549, -0.021500 + , 0.065249, 0.001865, -0.021500 + , 0.067443, 0.004886, -0.021500 + , 0.070993, 0.006039, -0.021500 + , 0.069128, 0.005744, -0.021500 + , 0.074542, 0.004886, -0.021500 + , 0.072858, 0.005744, -0.021500 + , 0.075879, 0.003549, -0.021500 + , 0.077032, 0.000000, -0.021500 + , 0.076737, 0.001865, -0.021500 + , 0.075879, -0.003549, -0.021500 + , 0.076737, -0.001865, -0.021500 + , 0.074542, -0.004886, -0.021500 + , 0.072858, -0.005744, -0.021500 + , 0.067443, -0.004886, -0.020078 + , 0.069128, -0.005744, -0.020078 + , 0.070993, -0.006039, -0.020078 + , 0.066107, -0.003549, -0.020078 + , 0.064954, 0.000000, -0.020078 + , 0.065249, -0.001865, -0.020078 + , 0.066107, 0.003549, -0.020078 + , 0.065249, 0.001865, -0.020078 + , 0.067443, 0.004886, -0.020078 + , 0.070993, 0.006039, -0.020078 + , 0.069128, 0.005744, -0.020078 + , 0.074542, 0.004886, -0.020078 + , 0.072858, 0.005744, -0.020078 + , 0.075879, 0.003549, -0.020078 + , 0.077032, 0.000000, -0.020078 + , 0.076737, 0.001865, -0.020078 + , 0.075879, -0.003549, -0.020078 + , 0.076737, -0.001865, -0.020078 + , 0.074542, -0.004886, -0.020078 + , 0.072858, -0.005744, -0.020078 + , -0.026847, -0.013300, 0.006300 + , 0.088353, -0.013310, 0.006300 + , 0.002815, -0.013333, 0.002250 + , -0.026847, 0.013300, 0.006300 + , 0.002815, 0.013300, 0.002250 + , 0.058800, 0.013300, 0.002250 + , 0.088353, 0.013300, 0.006300 + , -0.026847, -0.013300, 0.002250 + , -0.026847, -0.013300, 0.000500 + , -0.027959, -0.013175, 0.006300 + , -0.029016, -0.012805, 0.006300 + , -0.026847, 0.013300, 0.000500 + , 0.000151, 0.013300, 0.000563 + , 0.000830, 0.013300, 0.001351 + , -0.029965, -0.012209, 0.006300 + , 0.001761, 0.013300, 0.001999 + , -0.030756, -0.011417, 0.006300 + , -0.031352, -0.010469, 0.006300 + , -0.031722, -0.009412, 0.006300 + , -0.031847, -0.008300, 0.006300 + , -0.026847, 0.013300, 0.002250 + , -0.031847, 0.008300, 0.006300 + , -0.027959, 0.013175, 0.006300 + , -0.031722, 0.009412, 0.006300 + , -0.031352, 0.010469, 0.006300 + , -0.029016, 0.012805, 0.006300 + , -0.030756, 0.011417, 0.006300 + , -0.029965, 0.012209, 0.006300 + , -0.027959, -0.013175, 0.000500 + , -0.027959, -0.013175, 0.002250 + , -0.029016, -0.012805, 0.000500 + , -0.029016, -0.012805, 0.002250 + , -0.029965, -0.012209, 0.000500 + , -0.029965, -0.012209, 0.002250 + , -0.030756, -0.011417, 0.000500 + , -0.030756, -0.011417, 0.002250 + , -0.031352, -0.010469, 0.000500 + , -0.031352, -0.010469, 0.002250 + , -0.031722, -0.009412, 0.000500 + , -0.031722, -0.009412, 0.002250 + , -0.031847, -0.006364, 0.000500 + , -0.031809, -0.004156, 0.002299 + , -0.031847, 0.006354, 0.000500 + , -0.031809, 0.004146, 0.002299 + , -0.031722, 0.009412, 0.000500 + , -0.031722, 0.009412, 0.002250 + , -0.027959, 0.013175, 0.002250 + , -0.027959, 0.013175, 0.000500 + , -0.031352, 0.010469, 0.000500 + , -0.031352, 0.010469, 0.002250 + , -0.029016, 0.012805, 0.002250 + , -0.029016, 0.012805, 0.000500 + , -0.030756, 0.011417, 0.000500 + , -0.030756, 0.011417, 0.002250 + , -0.029965, 0.012209, 0.002250 + , -0.029965, 0.012209, 0.000500 + , 0.059839, 0.013300, 0.001999 + , 0.060770, 0.013300, 0.001351 + , 0.088353, 0.013300, 0.002250 + , 0.058785, -0.013333, 0.002250 + , 0.089464, 0.013175, 0.006300 + , 0.090522, 0.012805, 0.006300 + , 0.091470, 0.012209, 0.006300 + , 0.092262, 0.011417, 0.006300 + , 0.092858, 0.010469, 0.006300 + , 0.093228, 0.009412, 0.006300 + , 0.093353, 0.008300, 0.006300 + , 0.088353, -0.013310, 0.002250 + , 0.059839, -0.013333, 0.001999 + , 0.060770, -0.013333, 0.001351 + , 0.061448, 0.013300, 0.000563 + , 0.088353, 0.013300, 0.000500 + , 0.088353, -0.013310, 0.000500 + , 0.061448, -0.013333, 0.000563 + , 0.093353, -0.008310, 0.006300 + , 0.089464, -0.013194, 0.006300 + , 0.093228, -0.009431, 0.006300 + , 0.092858, -0.010488, 0.006300 + , 0.090522, -0.012824, 0.006300 + , 0.092262, -0.011437, 0.006300 + , 0.091470, -0.012228, 0.006300 + , 0.089464, 0.013175, 0.002250 + , 0.090522, 0.012805, 0.002250 + , 0.091470, 0.012209, 0.002250 + , 0.089464, 0.013175, 0.000500 + , 0.090522, 0.012805, 0.000500 + , 0.092262, 0.011417, 0.002250 + , 0.091470, 0.012209, 0.000500 + , 0.092858, 0.010469, 0.002250 + , 0.092262, 0.011417, 0.000500 + , 0.093228, 0.009412, 0.002250 + , 0.093353, 0.008300, 0.002250 + , 0.092858, 0.010469, 0.000500 + , 0.093228, 0.009412, 0.000500 + , 0.093353, 0.008300, 0.000500 + , 0.093353, -0.008310, 0.002250 + , 0.093353, -0.008310, 0.000500 + , 0.093228, -0.009431, 0.002250 + , 0.089464, -0.013194, 0.002250 + , 0.092858, -0.010488, 0.002250 + , 0.090522, -0.012824, 0.002250 + , 0.092262, -0.011437, 0.002250 + , 0.091470, -0.012228, 0.002250 + , 0.093228, -0.009431, 0.000500 + , 0.089464, -0.013194, 0.000500 + , 0.092858, -0.010488, 0.000500 + , 0.090522, -0.012824, 0.000500 + , 0.092262, -0.011437, 0.000500 + , 0.091470, -0.012228, 0.000500 + , 0.000152, -0.013333, 0.000564 + , 0.000830, -0.013333, 0.001352 + , 0.001761, -0.013333, 0.002000 + , -0.026591, -0.013201, 0.006500 + , 0.088097, -0.013211, 0.006500 + , -0.026591, 0.013201, 0.006500 + , 0.088097, 0.013201, 0.006500 + , 0.088477, 0.011982, 0.006500 + , -0.026591, 0.011982, 0.006500 + , -0.027698, -0.013077, 0.006500 + , -0.028751, -0.012710, 0.006500 + , -0.029695, -0.012119, 0.006500 + , -0.030483, -0.011333, 0.006500 + , -0.031076, -0.010391, 0.006500 + , -0.031445, -0.009342, 0.006500 + , -0.031569, -0.008238, 0.006500 + , -0.027698, 0.013077, 0.006500 + , -0.031445, 0.009342, 0.006500 + , -0.031569, 0.008238, 0.006500 + , -0.028751, 0.012710, 0.006500 + , -0.031076, 0.010391, 0.006500 + , -0.029695, 0.012118, 0.006500 + , -0.030483, 0.011332, 0.006500 + , -0.027703, -0.011897, 0.006500 + , -0.026192, -0.011982, 0.006500 + , -0.028399, -0.011645, 0.006500 + , -0.029024, -0.011241, 0.006500 + , -0.029545, -0.010703, 0.006500 + , -0.029937, -0.010058, 0.006500 + , -0.030180, -0.009340, 0.006500 + , -0.030263, -0.008585, 0.006500 + , -0.030263, 0.008585, 0.006500 + , -0.030180, 0.009340, 0.006500 + , -0.027703, 0.011897, 0.006500 + , -0.029937, 0.010059, 0.006500 + , -0.028399, 0.011646, 0.006500 + , -0.029545, 0.010703, 0.006500 + , -0.029024, 0.011241, 0.006500 + , 0.088477, -0.011992, 0.006500 + , 0.089204, 0.013077, 0.006500 + , 0.090256, 0.012710, 0.006500 + , 0.091200, 0.012118, 0.006500 + , 0.091989, 0.011332, 0.006500 + , 0.092582, 0.010391, 0.006500 + , 0.092950, 0.009342, 0.006500 + , 0.093075, 0.008238, 0.006500 + , 0.089204, -0.013096, 0.006500 + , 0.092950, -0.009361, 0.006500 + , 0.093075, -0.008248, 0.006500 + , 0.090256, -0.012729, 0.006500 + , 0.092582, -0.010410, 0.006500 + , 0.091200, -0.012138, 0.006500 + , 0.091989, -0.011352, 0.006500 + , 0.089209, 0.011897, 0.006500 + , 0.089905, 0.011646, 0.006500 + , 0.090529, 0.011241, 0.006500 + , 0.091050, 0.010703, 0.006500 + , 0.091443, 0.010059, 0.006500 + , 0.091686, 0.009340, 0.006500 + , 0.091768, 0.008585, 0.006500 + , 0.091768, -0.008595, 0.006500 + , 0.091686, -0.009360, 0.006500 + , 0.089209, -0.011916, 0.006500 + , 0.091443, -0.010078, 0.006500 + , 0.089905, -0.011665, 0.006500 + , 0.091050, -0.010723, 0.006500 + , 0.090529, -0.011260, 0.006500 + , -0.031809, -0.003322, 0.002497 + , -0.031809, 0.003313, 0.002497 + , -0.031809, 0.005707, 0.000701 + , -0.031809, 0.005128, 0.001424 + , -0.031809, -0.005138, 0.001424 + , -0.031809, -0.005716, 0.000701 + , 0.070993, -0.000000, -0.021500 + , 0.076551, 0.004038, -0.021500 + , 0.075030, 0.005558, -0.021500 + , 0.073114, 0.006534, -0.021500 + , 0.077863, 0.000000, -0.021500 + , 0.077527, 0.002121, -0.021500 + , 0.065435, -0.004038, -0.021500 + , 0.066955, -0.005558, -0.021500 + , 0.068872, -0.006534, -0.021500 + , 0.076551, -0.004038, -0.021500 + , 0.077527, -0.002121, -0.021500 + , 0.065435, 0.004038, -0.021500 + , 0.064459, 0.002121, -0.021500 + , 0.064123, 0.000000, -0.021500 + , 0.068872, 0.006534, -0.021500 + , 0.066955, 0.005558, -0.021500 + , 0.070993, 0.006870, -0.021500 + , 0.073114, -0.006534, -0.021500 + , 0.075030, -0.005558, -0.021500 + , 0.070993, -0.006870, -0.021500 + , 0.064459, -0.002121, -0.021500 + , 0.065353, -0.007764, -0.018000 + , 0.068030, -0.009127, -0.018000 + , 0.068030, -0.009127, -0.019500 + , 0.065353, -0.007764, -0.019500 + , 0.070993, -0.009596, -0.018000 + , 0.070993, -0.009596, -0.019500 + , 0.063229, -0.005640, -0.018000 + , 0.063229, -0.005640, -0.019500 + , 0.061397, 0.000000, -0.018000 + , 0.061866, -0.002963, -0.018000 + , 0.061866, -0.002963, -0.019500 + , 0.061397, 0.000000, -0.019500 + , 0.063229, 0.005640, -0.018000 + , 0.061866, 0.002963, -0.018000 + , 0.061866, 0.002963, -0.019500 + , 0.063229, 0.005640, -0.019500 + , 0.065353, 0.007764, -0.018000 + , 0.065353, 0.007764, -0.019500 + , 0.070993, 0.009596, -0.018000 + , 0.068030, 0.009127, -0.018000 + , 0.068030, 0.009127, -0.019500 + , 0.070993, 0.009596, -0.019500 + , 0.076633, 0.007764, -0.018000 + , 0.073956, 0.009127, -0.018000 + , 0.073956, 0.009127, -0.019500 + , 0.076633, 0.007764, -0.019500 + , 0.078757, 0.005640, -0.018000 + , 0.078757, 0.005640, -0.019500 + , 0.080589, 0.000000, -0.018000 + , 0.080120, 0.002963, -0.018000 + , 0.080120, 0.002963, -0.019500 + , 0.080589, 0.000000, -0.019500 + , 0.078757, -0.005640, -0.018000 + , 0.080120, -0.002963, -0.018000 + , 0.080120, -0.002963, -0.019500 + , 0.078757, -0.005640, -0.019500 + , 0.076633, -0.007764, -0.018000 + , 0.076633, -0.007764, -0.019500 + , 0.073956, -0.009127, -0.018000 + , 0.073956, -0.009127, -0.019500 + , 0.002356, -0.007764, -0.018000 + , 0.005033, -0.009127, -0.018000 + , 0.005033, -0.009127, -0.019500 + , 0.002356, -0.007764, -0.019500 + , 0.007996, -0.009596, -0.018000 + , 0.007996, -0.009596, -0.019500 + , 0.000232, -0.005640, -0.018000 + , 0.000232, -0.005640, -0.019500 + , -0.001600, 0.000000, -0.018000 + , -0.001131, -0.002963, -0.018000 + , -0.001131, -0.002963, -0.019500 + , -0.001600, 0.000000, -0.019500 + , 0.000232, 0.005640, -0.018000 + , -0.001131, 0.002963, -0.018000 + , -0.001131, 0.002963, -0.019500 + , 0.000232, 0.005640, -0.019500 + , 0.002356, 0.007764, -0.018000 + , 0.002356, 0.007764, -0.019500 + , 0.007996, 0.009596, -0.018000 + , 0.005033, 0.009127, -0.018000 + , 0.005033, 0.009127, -0.019500 + , 0.007996, 0.009596, -0.019500 + , 0.013636, 0.007764, -0.018000 + , 0.010959, 0.009127, -0.018000 + , 0.010959, 0.009127, -0.019500 + , 0.013636, 0.007764, -0.019500 + , 0.015760, 0.005640, -0.018000 + , 0.015760, 0.005640, -0.019500 + , 0.017592, 0.000000, -0.018000 + , 0.017123, 0.002963, -0.018000 + , 0.017123, 0.002963, -0.019500 + , 0.017592, 0.000000, -0.019500 + , 0.015760, -0.005640, -0.018000 + , 0.017123, -0.002963, -0.018000 + , 0.017123, -0.002963, -0.019500 + , 0.015760, -0.005640, -0.019500 + , 0.013636, -0.007764, -0.018000 + , 0.013636, -0.007764, -0.019500 + , 0.010959, -0.009127, -0.018000 + , 0.010959, -0.009127, -0.019500 + , 0.007996, -0.000000, -0.021500 + , 0.013554, 0.004038, -0.021500 + , 0.012033, 0.005558, -0.021500 + , 0.010117, 0.006534, -0.021500 + , 0.014866, 0.000000, -0.021500 + , 0.014530, 0.002121, -0.021500 + , 0.002438, -0.004038, -0.021500 + , 0.003958, -0.005558, -0.021500 + , 0.005875, -0.006534, -0.021500 + , 0.013554, -0.004038, -0.021500 + , 0.014530, -0.002121, -0.021500 + , 0.002438, 0.004038, -0.021500 + , 0.001462, 0.002121, -0.021500 + , 0.001126, 0.000000, -0.021500 + , 0.005875, 0.006534, -0.021500 + , 0.003958, 0.005558, -0.021500 + , 0.007996, 0.006870, -0.021500 + , 0.010117, -0.006534, -0.021500 + , 0.012033, -0.005558, -0.021500 + , 0.007996, -0.006870, -0.021500 + , 0.001462, -0.002121, -0.021500 + , 0.090529, -0.008928, 0.006500 + , 0.089905, -0.009249, 0.006500 + , 0.089209, -0.009448, 0.006500 + , 0.088477, -0.009506, 0.006500 + , -0.026234, -0.009497, 0.006500 + , -0.027703, -0.009430, 0.006500 + , -0.028399, -0.009231, 0.006500 + , -0.029024, -0.008910, 0.006500 + , 0.090529, -0.009792, 0.006500 + , 0.089905, -0.010144, 0.006500 + , 0.089209, -0.010362, 0.006500 + , 0.088477, -0.010427, 0.006500 + , -0.026219, -0.010417, 0.006500 + , -0.027703, -0.010344, 0.006500 + , -0.028399, -0.010125, 0.006500 + , -0.029024, -0.009773, 0.006500 + , 0.090529, 0.008867, 0.006500 + , 0.089905, 0.009187, 0.006500 + , 0.089209, 0.009385, 0.006500 + , 0.088477, 0.009453, 0.006500 + , -0.026549, 0.009454, 0.006500 + , -0.027703, 0.009387, 0.006500 + , -0.028399, 0.009189, 0.006500 + , -0.029024, 0.008869, 0.006500 + , 0.090529, 0.009705, 0.006500 + , 0.089905, 0.010055, 0.006500 + , 0.089209, 0.010272, 0.006500 + , 0.088477, 0.010346, 0.006500 + , -0.026564, 0.010347, 0.006500 + , -0.027703, 0.010273, 0.006500 + , -0.028399, 0.010056, 0.006500 + , -0.029024, 0.009707, 0.006500 + , 0.090529, -0.010555, 0.006500 + , 0.089905, -0.010935, 0.006500 + , 0.089209, -0.011170, 0.006500 + , 0.088477, -0.011240, 0.006500 + , -0.026205, -0.011231, 0.006500 + , -0.027703, -0.011151, 0.006500 + , -0.028399, -0.010915, 0.006500 + , -0.029024, -0.010536, 0.006500 + , 0.090529, 0.010411, 0.006500 + , 0.089905, 0.010786, 0.006500 + , 0.089209, 0.011019, 0.006500 + , 0.088477, 0.011098, 0.006500 + , -0.026577, 0.011099, 0.006500 + , -0.027703, 0.011020, 0.006500 + , -0.028399, 0.010787, 0.006500 + , -0.029024, 0.010412, 0.006500 +]) + +NB_AL_ZEDM_TRI = 125 +al_triangles_m = np.array([ + 2, 1, 8 + , 1, 2, 4 + , 1, 4, 5 + , 1, 5, 14 + , 1, 14, 15 + , 1, 6, 3 + , 1, 7, 6 + , 1, 15, 7 + , 1, 10, 8 + , 1, 11, 10 + , 1, 17, 11 + , 1, 16, 17 + , 1, 9, 12 + , 1, 12, 13 + , 1, 13, 16 + , 3, 9, 1 + , 3, 9, 1 + , 18, 21, 19 + , 18, 22, 21 + , 18, 32, 22 + , 18, 31, 32 + , 18, 31, 32 + , 18, 20, 23 + , 18, 23, 24 + , 18, 24, 31 + , 19, 25, 18 + , 20, 18, 26 + , 18, 25, 27 + , 18, 27, 28 + , 18, 28, 33 + , 18, 33, 34 + , 18, 33, 34 + , 18, 29, 26 + , 18, 30, 29 + , 18, 34, 30 + , 51, 35, 52 + , 52, 35, 36 + , 53, 37, 54 + , 54, 37, 38 + , 55, 39, 56 + , 56, 39, 40 + , 56, 40, 53 + , 53, 40, 37 + , 57, 41, 58 + , 58, 41, 42 + , 54, 38, 57 + , 57, 38, 41 + , 58, 42, 51 + , 51, 42, 35 + , 59, 43, 60 + , 60, 43, 44 + , 61, 46, 62 + , 62, 46, 45 + , 48, 47, 63 + , 63, 47, 64 + , 62, 45, 63 + , 63, 45, 48 + , 65, 50, 66 + , 66, 50, 49 + , 66, 49, 61 + , 61, 49, 46 + , 60, 44, 65 + , 65, 44, 50 + , 52, 36, 67 + , 67, 36, 68 + , 43, 59, 70 + , 70, 59, 69 + , 67, 68, 71 + , 71, 68, 72 + , 70, 69, 74 + , 74, 69, 73 + , 71, 72, 87 + , 74, 73, 87 + , 71, 87, 75 + , 87, 72, 76 + , 74, 87, 78 + , 87, 73, 77 + , 75, 87, 79 + , 87, 76, 80 + , 87, 77, 81 + , 78, 87, 82 + , 79, 87, 83 + , 87, 80, 84 + , 87, 81, 85 + , 82, 87, 86 + , 83, 87, 85 + , 87, 84, 86 + , 88, 17, 89 + , 89, 17, 16 + , 90, 91, 14 + , 14, 91, 15 + , 107, 108, 92 + , 92, 108, 93 + , 109, 110, 94 + , 94, 110, 95 + , 90, 111, 91 + , 91, 111, 96 + , 111, 109, 96 + , 96, 109, 94 + , 112, 113, 97 + , 97, 113, 98 + , 110, 112, 95 + , 95, 112, 97 + , 113, 107, 98 + , 98, 107, 92 + , 108, 114, 93 + , 93, 114, 99 + , 114, 115, 99 + , 99, 115, 100 + , 116, 117, 102 + , 102, 117, 101 + , 118, 119, 104 + , 104, 119, 103 + , 117, 118, 101 + , 101, 118, 104 + , 120, 121, 106 + , 106, 121, 105 + , 121, 116, 105 + , 105, 116, 102 + , 115, 120, 100 + , 100, 120, 106 + , 64, 47, 33 + , 33, 47, 34 + , 119, 32, 103 + , 103, 32, 31 +]) + +NB_DARK_ZEDM_TRI = 1268 +dark_triangles_m = np.array([ + 126, 144, 127 + , 127, 144, 143 + , 128, 136, 122 + , 122, 136, 135 + , 129, 132, 130 + , 130, 132, 131 + , 132, 125, 131 + , 131, 125, 124 + , 133, 129, 134 + , 134, 129, 130 + , 136, 133, 135 + , 135, 133, 134 + , 137, 140, 138 + , 138, 140, 139 + , 140, 128, 139 + , 139, 128, 122 + , 141, 137, 142 + , 142, 137, 138 + , 144, 141, 143 + , 143, 141, 142 + , 124, 125, 160 + , 160, 125, 161 + , 145, 153, 123 + , 123, 153, 152 + , 146, 149, 147 + , 147, 149, 148 + , 149, 126, 148 + , 148, 126, 127 + , 150, 146, 151 + , 151, 146, 147 + , 153, 150, 152 + , 152, 150, 151 + , 154, 157, 155 + , 155, 157, 156 + , 157, 145, 156 + , 156, 145, 123 + , 158, 154, 159 + , 159, 154, 155 + , 161, 158, 160 + , 160, 158, 159 + , 126, 163, 144 + , 144, 163, 162 + , 128, 165, 136 + , 136, 165, 164 + , 129, 167, 132 + , 132, 167, 166 + , 132, 166, 125 + , 125, 166, 168 + , 133, 169, 129 + , 129, 169, 167 + , 136, 164, 133 + , 133, 164, 169 + , 137, 171, 140 + , 140, 171, 170 + , 140, 170, 128 + , 128, 170, 165 + , 141, 172, 137 + , 137, 172, 171 + , 144, 162, 141 + , 141, 162, 172 + , 125, 168, 161 + , 161, 168, 173 + , 145, 175, 153 + , 153, 175, 174 + , 146, 177, 149 + , 149, 177, 176 + , 149, 176, 126 + , 126, 176, 163 + , 150, 178, 146 + , 146, 178, 177 + , 153, 174, 150 + , 150, 174, 178 + , 154, 180, 157 + , 157, 180, 179 + , 157, 179, 145 + , 145, 179, 175 + , 158, 181, 154 + , 154, 181, 180 + , 161, 173, 158 + , 158, 173, 181 + , 182, 183, 202 + , 202, 183, 203 + , 183, 184, 203 + , 203, 184, 204 + , 185, 182, 205 + , 205, 182, 202 + , 186, 187, 206 + , 206, 187, 207 + , 187, 185, 207 + , 207, 185, 205 + , 188, 189, 208 + , 208, 189, 209 + , 189, 186, 209 + , 209, 186, 206 + , 190, 188, 210 + , 210, 188, 208 + , 191, 192, 211 + , 211, 192, 212 + , 192, 190, 212 + , 212, 190, 210 + , 193, 194, 213 + , 213, 194, 214 + , 194, 191, 214 + , 214, 191, 211 + , 195, 193, 215 + , 215, 193, 213 + , 196, 197, 216 + , 216, 197, 217 + , 197, 195, 217 + , 217, 195, 215 + , 198, 199, 218 + , 218, 199, 219 + , 199, 196, 219 + , 219, 196, 216 + , 200, 198, 220 + , 220, 198, 218 + , 184, 201, 204 + , 204, 201, 221 + , 201, 200, 221 + , 221, 200, 220 + , 202, 203, 222 + , 222, 203, 223 + , 203, 204, 223 + , 223, 204, 224 + , 205, 202, 225 + , 225, 202, 222 + , 206, 207, 226 + , 226, 207, 227 + , 207, 205, 227 + , 227, 205, 225 + , 208, 209, 228 + , 228, 209, 229 + , 209, 206, 229 + , 229, 206, 226 + , 210, 208, 230 + , 230, 208, 228 + , 211, 212, 231 + , 231, 212, 232 + , 212, 210, 232 + , 232, 210, 230 + , 213, 214, 233 + , 233, 214, 234 + , 214, 211, 234 + , 234, 211, 231 + , 215, 213, 235 + , 235, 213, 233 + , 216, 217, 236 + , 236, 217, 237 + , 217, 215, 237 + , 237, 215, 235 + , 218, 219, 238 + , 238, 219, 239 + , 219, 216, 239 + , 239, 216, 236 + , 220, 218, 240 + , 240, 218, 238 + , 204, 221, 224 + , 224, 221, 241 + , 221, 220, 241 + , 241, 220, 240 + , 223, 243, 222 + , 222, 243, 242 + , 224, 244, 223 + , 223, 244, 243 + , 222, 242, 225 + , 225, 242, 245 + , 227, 247, 226 + , 226, 247, 246 + , 225, 245, 227 + , 227, 245, 247 + , 229, 249, 228 + , 228, 249, 248 + , 226, 246, 229 + , 229, 246, 249 + , 228, 248, 230 + , 230, 248, 250 + , 232, 252, 231 + , 231, 252, 251 + , 230, 250, 232 + , 232, 250, 252 + , 234, 254, 233 + , 233, 254, 253 + , 231, 251, 234 + , 234, 251, 254 + , 233, 253, 235 + , 235, 253, 255 + , 237, 257, 236 + , 236, 257, 256 + , 235, 255, 237 + , 237, 255, 257 + , 239, 259, 238 + , 238, 259, 258 + , 236, 256, 239 + , 239, 256, 259 + , 238, 258, 240 + , 240, 258, 260 + , 241, 261, 224 + , 224, 261, 244 + , 240, 260, 241 + , 241, 260, 261 + , 263, 262, 243 + , 243, 262, 242 + , 264, 263, 244 + , 244, 263, 243 + , 242, 262, 245 + , 245, 262, 265 + , 267, 266, 247 + , 247, 266, 246 + , 265, 267, 245 + , 245, 267, 247 + , 269, 268, 249 + , 249, 268, 248 + , 266, 269, 246 + , 246, 269, 249 + , 268, 270, 248 + , 248, 270, 250 + , 272, 271, 252 + , 252, 271, 251 + , 270, 272, 250 + , 250, 272, 252 + , 274, 273, 254 + , 254, 273, 253 + , 271, 274, 251 + , 251, 274, 254 + , 273, 275, 253 + , 253, 275, 255 + , 277, 276, 257 + , 257, 276, 256 + , 275, 277, 255 + , 255, 277, 257 + , 279, 278, 259 + , 259, 278, 258 + , 276, 279, 256 + , 256, 279, 259 + , 278, 280, 258 + , 258, 280, 260 + , 281, 264, 261 + , 261, 264, 244 + , 280, 281, 260 + , 260, 281, 261 + , 262, 263, 282 + , 282, 263, 283 + , 263, 264, 283 + , 283, 264, 284 + , 265, 262, 285 + , 285, 262, 282 + , 266, 267, 286 + , 286, 267, 287 + , 267, 265, 287 + , 287, 265, 285 + , 268, 269, 288 + , 288, 269, 289 + , 269, 266, 289 + , 289, 266, 286 + , 270, 268, 290 + , 290, 268, 288 + , 271, 272, 291 + , 291, 272, 292 + , 272, 270, 292 + , 292, 270, 290 + , 273, 274, 293 + , 293, 274, 294 + , 274, 271, 294 + , 294, 271, 291 + , 275, 273, 295 + , 295, 273, 293 + , 276, 277, 296 + , 296, 277, 297 + , 277, 275, 297 + , 297, 275, 295 + , 278, 279, 298 + , 298, 279, 299 + , 279, 276, 299 + , 299, 276, 296 + , 280, 278, 300 + , 300, 278, 298 + , 264, 281, 284 + , 284, 281, 301 + , 281, 280, 301 + , 301, 280, 300 + , 320, 461, 327 + , 461, 460, 327 + , 460, 477, 327 + , 477, 476, 327 + , 309, 303, 334 + , 334, 303, 335 + , 306, 304, 336 + , 336, 304, 337 + , 302, 305, 338 + , 338, 305, 339 + , 305, 306, 339 + , 339, 306, 336 + , 308, 307, 340 + , 340, 307, 341 + , 304, 308, 337 + , 337, 308, 340 + , 307, 309, 341 + , 341, 309, 334 + , 366, 302, 338 + , 303, 478, 335 + , 318, 312, 344 + , 344, 312, 345 + , 315, 313, 346 + , 346, 313, 347 + , 314, 348, 311 + , 311, 348, 343 + , 314, 315, 348 + , 348, 315, 346 + , 317, 316, 349 + , 349, 316, 350 + , 313, 317, 347 + , 347, 317, 349 + , 316, 318, 350 + , 350, 318, 344 + , 312, 367, 345 + , 326, 320, 352 + , 352, 320, 353 + , 323, 321, 354 + , 354, 321, 355 + , 319, 322, 351 + , 351, 322, 356 + , 322, 323, 356 + , 356, 323, 354 + , 325, 324, 357 + , 357, 324, 358 + , 321, 325, 355 + , 355, 325, 357 + , 324, 326, 358 + , 358, 326, 352 + , 320, 327, 353 + , 353, 327, 359 + , 327, 333, 359 + , 359, 333, 360 + , 328, 330, 362 + , 362, 330, 361 + , 329, 310, 363 + , 363, 310, 342 + , 330, 329, 361 + , 361, 329, 363 + , 331, 332, 365 + , 365, 332, 364 + , 332, 328, 364 + , 364, 328, 362 + , 333, 331, 360 + , 360, 331, 365 + , 368, 310, 366 + , 366, 310, 302 + , 367, 312, 407 + , 310, 368, 342 + , 369, 319, 351 + , 370, 482, 371 + , 336, 337, 372 + , 372, 337, 373 + , 338, 339, 374 + , 374, 339, 375 + , 339, 336, 375 + , 375, 336, 372 + , 340, 341, 376 + , 376, 341, 377 + , 337, 340, 373 + , 373, 340, 376 + , 341, 334, 377 + , 377, 334, 370 + , 366, 338, 413 + , 413, 338, 412 + , 412, 338, 378 + , 338, 374, 378 + , 344, 345, 380 + , 380, 345, 381 + , 346, 347, 382 + , 382, 347, 383 + , 481, 348, 480 + , 480, 348, 384 + , 348, 346, 384 + , 384, 346, 382 + , 349, 350, 385 + , 385, 350, 386 + , 347, 349, 383 + , 383, 349, 385 + , 350, 344, 386 + , 386, 344, 380 + , 409, 351, 388 + , 388, 351, 387 + , 352, 353, 389 + , 389, 353, 390 + , 354, 355, 391 + , 391, 355, 392 + , 351, 356, 387 + , 387, 356, 393 + , 356, 354, 393 + , 393, 354, 391 + , 357, 358, 394 + , 394, 358, 395 + , 355, 357, 392 + , 392, 357, 394 + , 358, 352, 395 + , 395, 352, 389 + , 353, 359, 390 + , 390, 359, 396 + , 359, 360, 396 + , 396, 360, 397 + , 362, 361, 399 + , 399, 361, 398 + , 363, 342, 401 + , 401, 342, 400 + , 361, 363, 398 + , 398, 363, 401 + , 365, 364, 403 + , 403, 364, 402 + , 364, 362, 402 + , 402, 362, 399 + , 360, 365, 397 + , 397, 365, 403 + , 367, 408, 345 + , 345, 408, 381 + , 342, 368, 411 + , 406, 319, 369 + , 312, 319, 407 + , 407, 319, 406 + , 369, 351, 409 + , 381, 408, 404 + , 400, 410, 405 + , 411, 410, 342 + , 342, 410, 400 + , 414, 415, 463 + , 463, 415, 462 + , 414, 417, 415 + , 415, 417, 416 + , 416, 417, 418 + , 418, 417, 419 + , 418, 419, 420 + , 420, 419, 421 + , 420, 421, 422 + , 422, 421, 423 + , 422, 423, 424 + , 424, 423, 425 + , 424, 425, 426 + , 426, 425, 427 + , 426, 427, 428 + , 428, 427, 429 + , 428, 429, 430 + , 430, 429, 431 + , 431, 433, 430 + , 430, 433, 432 + , 432, 433, 434 + , 434, 433, 435 + , 434, 435, 436 + , 436, 435, 437 + , 436, 437, 438 + , 438, 437, 439 + , 438, 439, 440 + , 440, 439, 441 + , 440, 441, 442 + , 442, 441, 443 + , 442, 443, 444 + , 444, 443, 445 + , 444, 445, 447 + , 447, 445, 446 + , 446, 449, 447 + , 447, 449, 448 + , 448, 449, 450 + , 450, 449, 451 + , 450, 451, 452 + , 452, 451, 453 + , 452, 453, 454 + , 454, 453, 455 + , 454, 455, 456 + , 456, 455, 457 + , 456, 457, 458 + , 458, 457, 459 + , 458, 459, 461 + , 461, 459, 460 + , 463, 462, 465 + , 465, 462, 464 + , 464, 466, 465 + , 465, 466, 467 + , 467, 466, 469 + , 469, 466, 468 + , 469, 468, 471 + , 471, 468, 470 + , 471, 470, 473 + , 473, 470, 472 + , 473, 472, 475 + , 475, 472, 474 + , 474, 476, 475 + , 475, 476, 477 + , 303, 309, 428 + , 428, 309, 426 + , 304, 306, 420 + , 420, 306, 418 + , 305, 302, 416 + , 416, 302, 415 + , 306, 305, 418 + , 418, 305, 416 + , 307, 308, 424 + , 424, 308, 422 + , 308, 304, 422 + , 422, 304, 420 + , 309, 307, 426 + , 426, 307, 424 + , 428, 430, 303 + , 303, 430, 311 + , 312, 318, 444 + , 444, 318, 442 + , 313, 315, 436 + , 436, 315, 434 + , 314, 311, 432 + , 432, 311, 430 + , 315, 314, 434 + , 434, 314, 432 + , 316, 317, 440 + , 440, 317, 438 + , 317, 313, 438 + , 438, 313, 436 + , 318, 316, 442 + , 442, 316, 440 + , 320, 326, 461 + , 461, 326, 458 + , 321, 323, 452 + , 452, 323, 450 + , 322, 319, 448 + , 448, 319, 447 + , 323, 322, 450 + , 450, 322, 448 + , 324, 325, 456 + , 456, 325, 454 + , 325, 321, 454 + , 454, 321, 452 + , 326, 324, 458 + , 458, 324, 456 + , 462, 310, 464 + , 464, 310, 329 + , 466, 464, 330 + , 330, 464, 329 + , 468, 466, 328 + , 328, 466, 330 + , 470, 468, 332 + , 332, 468, 328 + , 472, 470, 331 + , 331, 470, 332 + , 474, 472, 333 + , 333, 472, 331 + , 327, 476, 333 + , 333, 476, 474 + , 427, 425, 433 + , 433, 425, 435 + , 425, 423, 435 + , 435, 423, 437 + , 423, 421, 437 + , 437, 421, 439 + , 421, 419, 439 + , 439, 419, 441 + , 419, 417, 441 + , 441, 417, 443 + , 417, 414, 443 + , 443, 414, 445 + , 463, 465, 446 + , 446, 465, 449 + , 465, 467, 449 + , 449, 467, 451 + , 467, 469, 451 + , 451, 469, 453 + , 469, 471, 453 + , 453, 471, 455 + , 471, 473, 455 + , 455, 473, 457 + , 473, 475, 457 + , 457, 475, 459 + , 475, 477, 459 + , 459, 477, 460 + , 431, 429, 433 + , 433, 429, 427 + , 415, 302, 462 + , 462, 302, 310 + , 463, 446, 414 + , 414, 446, 445 + , 312, 444, 319 + , 319, 444, 447 + , 311, 479, 303 + , 303, 479, 478 + , 479, 311, 343 + , 480, 384, 379 + , 343, 348, 481 + , 483, 482, 334 + , 334, 482, 370 + , 334, 335, 483 + , 488, 506, 489 + , 489, 506, 505 + , 490, 498, 484 + , 484, 498, 497 + , 491, 494, 492 + , 492, 494, 493 + , 494, 487, 493 + , 493, 487, 486 + , 495, 491, 496 + , 496, 491, 492 + , 498, 495, 497 + , 497, 495, 496 + , 499, 502, 500 + , 500, 502, 501 + , 502, 490, 501 + , 501, 490, 484 + , 503, 499, 504 + , 504, 499, 500 + , 506, 503, 505 + , 505, 503, 504 + , 486, 487, 522 + , 522, 487, 523 + , 507, 515, 485 + , 485, 515, 514 + , 508, 511, 509 + , 509, 511, 510 + , 511, 488, 510 + , 510, 488, 489 + , 512, 508, 513 + , 513, 508, 509 + , 515, 512, 514 + , 514, 512, 513 + , 516, 519, 517 + , 517, 519, 518 + , 519, 507, 518 + , 518, 507, 485 + , 520, 516, 521 + , 521, 516, 517 + , 523, 520, 522 + , 522, 520, 521 + , 488, 525, 506 + , 506, 525, 524 + , 490, 527, 498 + , 498, 527, 526 + , 491, 529, 494 + , 494, 529, 528 + , 494, 528, 487 + , 487, 528, 530 + , 495, 531, 491 + , 491, 531, 529 + , 498, 526, 495 + , 495, 526, 531 + , 499, 533, 502 + , 502, 533, 532 + , 502, 532, 490 + , 490, 532, 527 + , 503, 534, 499 + , 499, 534, 533 + , 506, 524, 503 + , 503, 524, 534 + , 487, 530, 523 + , 523, 530, 535 + , 507, 537, 515 + , 515, 537, 536 + , 508, 539, 511 + , 511, 539, 538 + , 511, 538, 488 + , 488, 538, 525 + , 512, 540, 508 + , 508, 540, 539 + , 515, 536, 512 + , 512, 536, 540 + , 516, 542, 519 + , 519, 542, 541 + , 519, 541, 507 + , 507, 541, 537 + , 520, 543, 516 + , 516, 543, 542 + , 523, 535, 520 + , 520, 535, 543 + , 544, 545, 564 + , 564, 545, 565 + , 545, 546, 565 + , 565, 546, 566 + , 547, 544, 567 + , 567, 544, 564 + , 548, 549, 568 + , 568, 549, 569 + , 549, 547, 569 + , 569, 547, 567 + , 550, 551, 570 + , 570, 551, 571 + , 551, 548, 571 + , 571, 548, 568 + , 552, 550, 572 + , 572, 550, 570 + , 553, 554, 573 + , 573, 554, 574 + , 554, 552, 574 + , 574, 552, 572 + , 555, 556, 575 + , 575, 556, 576 + , 556, 553, 576 + , 576, 553, 573 + , 557, 555, 577 + , 577, 555, 575 + , 558, 559, 578 + , 578, 559, 579 + , 559, 557, 579 + , 579, 557, 577 + , 560, 561, 580 + , 580, 561, 581 + , 561, 558, 581 + , 581, 558, 578 + , 562, 560, 582 + , 582, 560, 580 + , 546, 563, 566 + , 566, 563, 583 + , 563, 562, 583 + , 583, 562, 582 + , 564, 565, 584 + , 584, 565, 585 + , 565, 566, 585 + , 585, 566, 586 + , 567, 564, 587 + , 587, 564, 584 + , 568, 569, 588 + , 588, 569, 589 + , 569, 567, 589 + , 589, 567, 587 + , 570, 571, 590 + , 590, 571, 591 + , 571, 568, 591 + , 591, 568, 588 + , 572, 570, 592 + , 592, 570, 590 + , 573, 574, 593 + , 593, 574, 594 + , 574, 572, 594 + , 594, 572, 592 + , 575, 576, 595 + , 595, 576, 596 + , 576, 573, 596 + , 596, 573, 593 + , 577, 575, 597 + , 597, 575, 595 + , 578, 579, 598 + , 598, 579, 599 + , 579, 577, 599 + , 599, 577, 597 + , 580, 581, 600 + , 600, 581, 601 + , 581, 578, 601 + , 601, 578, 598 + , 582, 580, 602 + , 602, 580, 600 + , 566, 583, 586 + , 586, 583, 603 + , 583, 582, 603 + , 603, 582, 602 + , 585, 605, 584 + , 584, 605, 604 + , 586, 606, 585 + , 585, 606, 605 + , 584, 604, 587 + , 587, 604, 607 + , 589, 609, 588 + , 588, 609, 608 + , 587, 607, 589 + , 589, 607, 609 + , 591, 611, 590 + , 590, 611, 610 + , 588, 608, 591 + , 591, 608, 611 + , 590, 610, 592 + , 592, 610, 612 + , 594, 614, 593 + , 593, 614, 613 + , 592, 612, 594 + , 594, 612, 614 + , 596, 616, 595 + , 595, 616, 615 + , 593, 613, 596 + , 596, 613, 616 + , 595, 615, 597 + , 597, 615, 617 + , 599, 619, 598 + , 598, 619, 618 + , 597, 617, 599 + , 599, 617, 619 + , 601, 621, 600 + , 600, 621, 620 + , 598, 618, 601 + , 601, 618, 621 + , 600, 620, 602 + , 602, 620, 622 + , 603, 623, 586 + , 586, 623, 606 + , 602, 622, 603 + , 603, 622, 623 + , 625, 624, 605 + , 605, 624, 604 + , 626, 625, 606 + , 606, 625, 605 + , 604, 624, 607 + , 607, 624, 627 + , 629, 628, 609 + , 609, 628, 608 + , 627, 629, 607 + , 607, 629, 609 + , 631, 630, 611 + , 611, 630, 610 + , 628, 631, 608 + , 608, 631, 611 + , 630, 632, 610 + , 610, 632, 612 + , 634, 633, 614 + , 614, 633, 613 + , 632, 634, 612 + , 612, 634, 614 + , 636, 635, 616 + , 616, 635, 615 + , 633, 636, 613 + , 613, 636, 616 + , 635, 637, 615 + , 615, 637, 617 + , 639, 638, 619 + , 619, 638, 618 + , 637, 639, 617 + , 617, 639, 619 + , 641, 640, 621 + , 621, 640, 620 + , 638, 641, 618 + , 618, 641, 621 + , 640, 642, 620 + , 620, 642, 622 + , 643, 626, 623 + , 623, 626, 606 + , 642, 643, 622 + , 622, 643, 623 + , 624, 625, 644 + , 644, 625, 645 + , 625, 626, 645 + , 645, 626, 646 + , 627, 624, 647 + , 647, 624, 644 + , 628, 629, 648 + , 648, 629, 649 + , 629, 627, 649 + , 649, 627, 647 + , 630, 631, 650 + , 650, 631, 651 + , 631, 628, 651 + , 651, 628, 648 + , 632, 630, 652 + , 652, 630, 650 + , 633, 634, 653 + , 653, 634, 654 + , 634, 632, 654 + , 654, 632, 652 + , 635, 636, 655 + , 655, 636, 656 + , 636, 633, 656 + , 656, 633, 653 + , 637, 635, 657 + , 657, 635, 655 + , 638, 639, 658 + , 658, 639, 659 + , 639, 637, 659 + , 659, 637, 657 + , 640, 641, 660 + , 660, 641, 661 + , 641, 638, 661 + , 661, 638, 658 + , 642, 640, 662 + , 662, 640, 660 + , 626, 643, 646 + , 646, 643, 663 + , 643, 642, 663 + , 663, 642, 662 + , 664, 665, 666 + , 666, 665, 723 + , 665, 664, 777 + , 777, 664, 776 + , 667, 668, 670 + , 670, 668, 669 + , 778, 779, 781 + , 781, 779, 780 + , 671, 666, 775 + , 667, 670, 778 + , 778, 670, 779 + , 666, 671, 664 + , 776, 664, 782 + , 782, 664, 673 + , 782, 673, 783 + , 783, 673, 674 + , 675, 676, 677 + , 783, 674, 784 + , 784, 674, 678 + , 679, 668, 667 + , 784, 678, 785 + , 785, 678, 680 + , 785, 680, 786 + , 786, 680, 681 + , 786, 681, 787 + , 787, 681, 682 + , 682, 683, 787 + , 787, 683, 788 + , 667, 684, 679 + , 778, 789, 667 + , 667, 789, 686 + , 791, 685, 790 + , 790, 685, 687 + , 789, 792, 686 + , 686, 792, 689 + , 687, 688, 790 + , 790, 688, 793 + , 792, 794, 689 + , 689, 794, 691 + , 688, 690, 793 + , 793, 690, 795 + , 794, 795, 691 + , 691, 795, 690 + , 671, 672, 693 + , 693, 672, 692 + , 693, 692, 695 + , 695, 692, 694 + , 695, 694, 697 + , 697, 694, 696 + , 664, 671, 673 + , 673, 671, 693 + , 673, 693, 674 + , 674, 693, 695 + , 697, 696, 699 + , 699, 696, 698 + , 782, 796, 776 + , 776, 796, 797 + , 674, 695, 678 + , 678, 695, 697 + , 699, 698, 701 + , 701, 698, 700 + , 798, 796, 783 + , 783, 796, 782 + , 678, 697, 680 + , 680, 697, 699 + , 701, 700, 703 + , 703, 700, 702 + , 799, 798, 784 + , 784, 798, 783 + , 703, 844, 705 + , 680, 699, 681 + , 681, 699, 701 + , 785, 800, 784 + , 784, 800, 799 + , 681, 701, 682 + , 682, 701, 703 + , 786, 801, 785 + , 785, 801, 800 + , 682, 703, 683 + , 683, 703, 705 + , 787, 802, 786 + , 786, 802, 801 + , 675, 677, 684 + , 684, 677, 679 + , 788, 803, 787 + , 787, 803, 802 + , 685, 841, 707 + , 803, 788, 804 + , 804, 788, 791 + , 683, 685, 788 + , 788, 685, 791 + , 708, 842, 706 + , 710, 711, 684 + , 684, 711, 675 + , 709, 708, 713 + , 713, 708, 712 + , 714, 715, 710 + , 710, 715, 711 + , 713, 712, 717 + , 717, 712, 716 + , 718, 719, 714 + , 714, 719, 715 + , 717, 716, 718 + , 718, 716, 719 + , 707, 709, 685 + , 685, 709, 687 + , 686, 710, 667 + , 667, 710, 684 + , 687, 709, 688 + , 688, 709, 713 + , 689, 714, 686 + , 686, 714, 710 + , 805, 804, 790 + , 790, 804, 791 + , 688, 713, 690 + , 690, 713, 717 + , 691, 718, 689 + , 689, 718, 714 + , 778, 781, 789 + , 789, 781, 806 + , 690, 717, 691 + , 691, 717, 718 + , 807, 805, 793 + , 793, 805, 790 + , 789, 806, 792 + , 792, 806, 808 + , 809, 807, 795 + , 795, 807, 793 + , 792, 808, 794 + , 794, 808, 810 + , 810, 809, 794 + , 794, 809, 795 + , 811, 777, 797 + , 797, 777, 776 + , 669, 720, 670 + , 720, 721, 722 + , 720, 722, 670 + , 779, 670, 812 + , 812, 670, 724 + , 812, 724, 813 + , 813, 724, 725 + , 813, 725, 814 + , 814, 725, 726 + , 814, 726, 815 + , 815, 726, 727 + , 815, 727, 816 + , 816, 727, 728 + , 816, 728, 817 + , 817, 728, 729 + , 729, 730, 817 + , 817, 730, 818 + , 731, 732, 723 + , 732, 731, 733 + , 733, 731, 736 + , 721, 734, 722 + , 722, 734, 735 + , 736, 737, 733 + , 665, 731, 723 + , 777, 819, 665 + , 665, 819, 739 + , 821, 738, 820 + , 820, 738, 740 + , 819, 822, 739 + , 739, 822, 742 + , 740, 741, 820 + , 820, 741, 823 + , 822, 824, 742 + , 742, 824, 744 + , 825, 823, 743 + , 743, 823, 741 + , 824, 825, 744 + , 744, 825, 743 + , 826, 780, 812 + , 812, 780, 779 + , 827, 826, 813 + , 813, 826, 812 + , 670, 722, 724 + , 724, 722, 745 + , 828, 827, 814 + , 814, 827, 813 + , 724, 745, 725 + , 725, 745, 746 + , 815, 829, 814 + , 814, 829, 828 + , 725, 746, 726 + , 726, 746, 747 + , 722, 735, 745 + , 745, 735, 748 + , 816, 830, 815 + , 815, 830, 829 + , 745, 748, 746 + , 746, 748, 749 + , 726, 747, 727 + , 727, 747, 750 + , 817, 831, 816 + , 816, 831, 830 + , 818, 832, 817 + , 817, 832, 831 + , 746, 749, 747 + , 747, 749, 751 + , 727, 750, 728 + , 728, 750, 752 + , 747, 751, 750 + , 750, 751, 753 + , 728, 752, 729 + , 729, 752, 754 + , 729, 754, 730 + , 730, 754, 755 + , 750, 753, 752 + , 752, 753, 756 + , 752, 756, 754 + , 754, 756, 757 + , 754, 757, 755 + , 755, 757, 758 + , 818, 821, 832 + , 832, 821, 833 + , 730, 738, 818 + , 818, 738, 821 + , 730, 755, 738 + , 738, 755, 759 + , 755, 758, 759 + , 759, 758, 760 + , 821, 820, 833 + , 833, 820, 834 + , 835, 819, 811 + , 811, 819, 777 + , 820, 823, 834 + , 834, 823, 836 + , 837, 822, 835 + , 835, 822, 819 + , 823, 825, 836 + , 836, 825, 838 + , 839, 824, 837 + , 837, 824, 822 + , 825, 824, 838 + , 838, 824, 839 + , 738, 759, 740 + , 740, 759, 761 + , 739, 762, 665 + , 665, 762, 731 + , 740, 761, 741 + , 741, 761, 763 + , 742, 764, 739 + , 739, 764, 762 + , 741, 763, 743 + , 743, 763, 765 + , 744, 766, 742 + , 742, 766, 764 + , 743, 765, 744 + , 744, 765, 766 + , 759, 760, 761 + , 761, 760, 767 + , 762, 768, 731 + , 731, 768, 736 + , 761, 767, 763 + , 763, 767, 769 + , 764, 770, 762 + , 762, 770, 768 + , 763, 769, 765 + , 765, 769, 771 + , 766, 772, 764 + , 764, 772, 770 + , 765, 771, 766 + , 766, 771, 772 + , 775, 774, 671 + , 671, 774, 672 + , 672, 774, 773 + , 683, 705, 840 + , 840, 841, 683 + , 683, 841, 685 + , 843, 842, 709 + , 709, 842, 708 + , 707, 843, 709 + , 702, 845, 703 + , 703, 845, 844 + , 845, 702, 704 + , 808, 1014, 810 + , 810, 1014, 1015 + , 806, 1013, 808 + , 808, 1013, 1014 + , 781, 1012, 806 + , 806, 1012, 1013 + , 781, 780, 1012 + , 1012, 780, 1011 + , 780, 826, 1011 + , 1011, 826, 1010 + , 826, 827, 1010 + , 1010, 827, 1009 + , 827, 828, 1009 + , 1009, 828, 1008 + , 968, 976, 969 + , 969, 976, 977 + , 969, 977, 970 + , 970, 977, 978 + , 970, 978, 971 + , 971, 978, 979 + , 972, 971, 980 + , 980, 971, 979 + , 973, 972, 981 + , 981, 972, 980 + , 974, 973, 982 + , 982, 973, 981 + , 975, 974, 983 + , 983, 974, 982 + , 976, 1000, 977 + , 977, 1000, 1001 + , 977, 1001, 978 + , 978, 1001, 1002 + , 978, 1002, 979 + , 979, 1002, 1003 + , 980, 979, 1004 + , 1004, 979, 1003 + , 981, 980, 1005 + , 1005, 980, 1004 + , 982, 981, 1006 + , 1006, 981, 1005 + , 983, 982, 1007 + , 1007, 982, 1006 + , 985, 984, 969 + , 969, 984, 968 + , 986, 985, 970 + , 970, 985, 969 + , 987, 986, 971 + , 971, 986, 970 + , 988, 987, 972 + , 972, 987, 971 + , 989, 988, 973 + , 973, 988, 972 + , 990, 989, 974 + , 974, 989, 973 + , 991, 990, 975 + , 975, 990, 974 + , 993, 992, 985 + , 985, 992, 984 + , 994, 993, 986 + , 986, 993, 985 + , 995, 994, 987 + , 987, 994, 986 + , 996, 995, 988 + , 988, 995, 987 + , 996, 988, 997 + , 997, 988, 989 + , 997, 989, 998 + , 998, 989, 990 + , 998, 990, 999 + , 999, 990, 991 + , 1000, 839, 1001 + , 1001, 839, 837 + , 1001, 837, 1002 + , 1002, 837, 835 + , 1002, 835, 1003 + , 1003, 835, 811 + , 1004, 1003, 797 + , 797, 1003, 811 + , 1005, 1004, 796 + , 796, 1004, 797 + , 1006, 1005, 798 + , 798, 1005, 796 + , 1007, 1006, 799 + , 799, 1006, 798 + , 1009, 1008, 993 + , 993, 1008, 992 + , 1010, 1009, 994 + , 994, 1009, 993 + , 1011, 1010, 995 + , 995, 1010, 994 + , 1012, 1011, 996 + , 996, 1011, 995 + , 1012, 996, 1013 + , 1013, 996, 997 + , 1013, 997, 1014 + , 1014, 997, 998 + , 1014, 998, 1015 + , 1015, 998, 999 + , 831, 992, 830 + , 830, 992, 1008 + , 832, 984, 831 + , 831, 984, 992 + , 832, 833, 984 + , 984, 833, 968 + , 833, 834, 968 + , 968, 834, 976 + , 834, 836, 976 + , 976, 836, 1000 + , 802, 983, 801 + , 801, 983, 1007 + , 803, 975, 802 + , 802, 975, 983 + , 804, 991, 803 + , 803, 991, 975 + , 804, 805, 991 + , 991, 805, 999 + , 805, 807, 999 + , 999, 807, 1015 + , 801, 1007, 800 + , 800, 1007, 799 + , 807, 809, 1015 + , 1015, 809, 810 + , 830, 1008, 829 + , 829, 1008, 828 + , 839, 1000, 838 + , 838, 1000, 836 +]) + +NB_GRAY_ZEDM_TRI = 40 +GRAY_COLOR = Color(0.22, 0.22, 0.22) +gray_triangles_m = np.array([ + 849, 846, 848 + , 846, 847, 848 + , 847, 846, 851 + , 846, 850, 851 + , 852, 853, 846 + , 846, 853, 854 + , 850, 846, 856 + , 846, 855, 856 + , 859, 846, 858 + , 846, 857, 858 + , 860, 861, 846 + , 846, 861, 857 + , 860, 846, 862 + , 862, 846, 849 + , 863, 864, 846 + , 846, 864, 855 + , 854, 865, 846 + , 846, 865, 863 + , 859, 866, 846 + , 846, 866, 852 + , 950, 947, 949 + , 947, 948, 949 + , 948, 947, 952 + , 947, 951, 952 + , 953, 954, 947 + , 947, 954, 955 + , 951, 947, 957 + , 947, 956, 957 + , 960, 947, 959 + , 947, 958, 959 + , 961, 962, 947 + , 947, 962, 958 + , 961, 947, 963 + , 963, 947, 950 + , 964, 965, 947 + , 947, 965, 956 + , 955, 966, 947 + , 947, 966, 964 + , 960, 967, 947 + , 947, 967, 953 +]) + +NB_YELLOW_ZEDM_TRI = 80 +YELLOW_COLOR = Color(1., 1., 0.) +yellow_triangles_m = np.array([ + 867, 868, 870 + , 870, 868, 869 + , 868, 871, 869 + , 869, 871, 872 + , 873, 867, 874 + , 874, 867, 870 + , 875, 876, 878 + , 878, 876, 877 + , 876, 873, 877 + , 877, 873, 874 + , 879, 880, 882 + , 882, 880, 881 + , 880, 875, 881 + , 881, 875, 878 + , 883, 879, 884 + , 884, 879, 882 + , 885, 886, 888 + , 888, 886, 887 + , 886, 883, 887 + , 887, 883, 884 + , 889, 890, 892 + , 892, 890, 891 + , 890, 885, 891 + , 891, 885, 888 + , 893, 889, 894 + , 894, 889, 892 + , 895, 896, 898 + , 898, 896, 897 + , 896, 893, 897 + , 897, 893, 894 + , 899, 900, 902 + , 902, 900, 901 + , 900, 895, 901 + , 901, 895, 898 + , 903, 899, 904 + , 904, 899, 902 + , 871, 905, 872 + , 872, 905, 906 + , 905, 903, 906 + , 906, 903, 904 + , 907, 908, 910 + , 910, 908, 909 + , 908, 911, 909 + , 909, 911, 912 + , 913, 907, 914 + , 914, 907, 910 + , 915, 916, 918 + , 918, 916, 917 + , 916, 913, 917 + , 917, 913, 914 + , 919, 920, 922 + , 922, 920, 921 + , 920, 915, 921 + , 921, 915, 918 + , 923, 919, 924 + , 924, 919, 922 + , 925, 926, 928 + , 928, 926, 927 + , 926, 923, 927 + , 927, 923, 924 + , 929, 930, 932 + , 932, 930, 931 + , 930, 925, 931 + , 931, 925, 928 + , 933, 929, 934 + , 934, 929, 932 + , 935, 936, 938 + , 938, 936, 937 + , 936, 933, 937 + , 937, 933, 934 + , 939, 940, 942 + , 942, 940, 941 + , 940, 935, 941 + , 941, 935, 938 + , 943, 939, 944 + , 944, 939, 942 + , 911, 945, 912 + , 912, 945, 946 + , 945, 943, 946 + , 946, 943, 944 +])