From 39a2bf4612502d8e91f72ac70846ad7d3934fb7f Mon Sep 17 00:00:00 2001 From: Drew Shark Date: Fri, 23 Aug 2024 11:32:54 -0400 Subject: [PATCH 01/86] Update Schema --- V3Schema | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/V3Schema b/V3Schema index 32731d7..23b5629 160000 --- a/V3Schema +++ b/V3Schema @@ -1 +1 @@ -Subproject commit 32731d7f8de74c087f4d935b68b23716026cdf6b +Subproject commit 23b5629ac5d9d4b4ddb25b9445cf29f0444820e1 diff --git a/pyproject.toml b/pyproject.toml index 0d915fc..30e8ada 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ dependencies = [ # URLs [project.urls] Homepage = "https://matterandform.net" -Documentation = "https://matterandform.net" +Documentation = "https://github.com/Matter-and-Form/three-python-library/wiki" # Package source [tool.setuptools.package-dir] From 9bf4ce85dab2b69e6397ae94ed3284844286afec Mon Sep 17 00:00:00 2001 From: Drew Shark Date: Fri, 23 Aug 2024 11:59:01 -0400 Subject: [PATCH 02/86] Update proto build script to delete previously generated files --- scripts/build-proto.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/build-proto.py b/scripts/build-proto.py index f3c6870..092afd0 100644 --- a/scripts/build-proto.py +++ b/scripts/build-proto.py @@ -2,6 +2,8 @@ import os import subprocess +import glob + # Paths scriptPath = os.path.dirname(os.path.realpath(__file__)) @@ -38,7 +40,14 @@ def BuildProtoFile(protoFile, inputDir, outputDir): # Find and build all the proto files fileError = 0 fileCount = 0 -import glob + +# Delete previously compiled directory +previousProtoOutputPath = protoOutputPath + "/MF" + +if os.path.exists(previousProtoOutputPath): + print("Deleting previously compiled directory: " + previousProtoOutputPath) + os.system("rm -rf " + previousProtoOutputPath) + files = glob.glob(protoInputPath+"/**/*.proto", recursive=True) for file in files: From 9867f4d58bedb0071307284081935927ab2424f5 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 30 Aug 2024 16:26:51 -0400 Subject: [PATCH 03/86] moving to new proto methods --- maf_three/buffer.py | 4 +- maf_three/examples/projector.py | 114 +++++++++++++++------------- maf_three/examples/simpleScanner.py | 10 +-- maf_three/scanner.py | 54 +++---------- pyproject.toml | 2 +- scripts/build-proto.py | 26 +++---- 6 files changed, 91 insertions(+), 119 deletions(-) diff --git a/maf_three/buffer.py b/maf_three/buffer.py index ab7c8b8..58069e6 100644 --- a/maf_three/buffer.py +++ b/maf_three/buffer.py @@ -1,7 +1,7 @@ # buffer.py -from maf_three.task import Task +from MF.V3 import Task class Buffer: @@ -17,7 +17,7 @@ class Buffer: """The related task.""" - def __init__(self, bufferIndex:int,totalBufferSize:int, task:Task, Input = None): + def __init__(self, bufferIndex:int, totalBufferSize:int, task:Task): self.Index = bufferIndex self.totalBufferSize = totalBufferSize self.Task = task diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index 8c46ad2..01a429d 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -1,14 +1,17 @@ # Projector +import sys +import os import time import numpy as np -from maf_three.scanner import Scanner -from maf_three.V3Task import V3Task +# from maf_three.scanner import Scanner +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) + +from MF.V3 import Three, Task +from MF.V3.Tasks import SetProjector -from MF.V3.Settings.Projector import Projector -from MF.V3.Settings.Rectangle import Rectangle -from MF.V3.Settings.Video import Video +from maf_three.scanner import Scanner def main(): @@ -17,54 +20,58 @@ def main(): scanner.Connect("ws://matterandform.local:8081") #### Turn ON - print('Turn ON') - scanner.SendTask(0, V3Task.SetProjector, Projector(on=True, brightness=1.0, color=[1,1,1])) - time.sleep(1) - - #### Project Red - print('Project Red') - scanner.SendTask(1, V3Task.SetProjector, Projector(color=[1,0,0])) - time.sleep(1) - - #### Project Green - print('Project Green') - scanner.SendTask(2, V3Task.SetProjector, Projector(color=[0,1,0])) - time.sleep(1) - - #### Project Blue - print('Project Blue') - scanner.SendTask(3, V3Task.SetProjector, Projector(color=[0,0,1])) - time.sleep(1) - - #### Project Vertical Pattern - print('Project Vertical Pattern (Identical image columns)') - scanner.SendTask(4, V3Task.SetProjector, Projector(pattern=Projector.Pattern(orientation=Projector.Orientation.Vertical,frequency=4,phase=1))) - time.sleep(1) - - #### Project Horizontal Pattern - print('Project Horizontal Pattern (Identical image rows)') - scanner.SendTask(5, V3Task.SetProjector, Projector(pattern=Projector.Pattern(orientation=Projector.Orientation.Horizontal,frequency=4,phase=1))) - time.sleep(1) - - ### Project an image - print('Project Image') - width = 640 - height = 480 - image = np.zeros([height, width, 3], np.uint8) - for y in range(height): - for x in range(0, width): - image[y,x] = ( - 255 * y / height , # Blue - 255 * x / width , # Green - 255 - 255 * y / height # Red - ) - source = Projector.Image.Source(format = Video.Format.BGR888, width=width, height=height, step=3*width, fixAspectRatio=True) - scanner.SendTaskWithBuffer(6, V3Task.SetProjector, image.tobytes(), Projector(image=Projector.Image(source=source, target=Rectangle(x=100,y=100,width=640, height=480))) ) - time.sleep(1) - - #### Turn OFF - print('Turn OFF') - scanner.SendTask(7, V3Task.SetProjector, Projector(on=False)) + task = Task() + task. + # task.Projector.CopyFrom(Projector(on=True, brightness=1.0, color=[1,1,1])) + # print("test2") + # print(task) + # scanner.SendTask(task) + # time.sleep(1) + + # #### Project Red + # print('Project Red') + # scanner.SendTask(1, V3Task.SetProjector, Projector(color=[1,0,0])) + # time.sleep(1) + + # #### Project Green + # print('Project Green') + # scanner.SendTask(2, V3Task.SetProjector, Projector(color=[0,1,0])) + # time.sleep(1) + + # #### Project Blue + # print('Project Blue') + # scanner.SendTask(3, V3Task.SetProjector, Projector(color=[0,0,1])) + # time.sleep(1) + + # #### Project Vertical Pattern + # print('Project Vertical Pattern (Identical image columns)') + # scanner.SendTask(4, V3Task.SetProjector, Projector(pattern=Projector.Pattern(orientation=Projector.Orientation.Vertical,frequency=4,phase=1))) + # time.sleep(1) + + # #### Project Horizontal Pattern + # print('Project Horizontal Pattern (Identical image rows)') + # scanner.SendTask(5, V3Task.SetProjector, Projector(pattern=Projector.Pattern(orientation=Projector.Orientation.Horizontal,frequency=4,phase=1))) + # time.sleep(1) + + # ### Project an image + # print('Project Image') + # width = 640 + # height = 480 + # image = np.zeros([height, width, 3], np.uint8) + # for y in range(height): + # for x in range(0, width): + # image[y,x] = ( + # 255 * y / height , # Blue + # 255 * x / width , # Green + # 255 - 255 * y / height # Red + # ) + # source = Projector.Image.Source(format = Video.Format.BGR888, width=width, height=height, step=3*width, fixAspectRatio=True) + # scanner.SendTaskWithBuffer(6, V3Task.SetProjector, image.tobytes(), Projector(image=Projector.Image(source=source, target=Rectangle(x=100,y=100,width=640, height=480))) ) + # time.sleep(1) + + # #### Turn OFF + # print('Turn OFF') + # scanner.SendTask(7, V3Task.SetProjector, Projector(on=False)) except Exception as error: print('Error: ', error) @@ -74,6 +81,7 @@ def main(): finally: if scanner.IsConnected(): scanner.Disconnect() + print('Finally') if __name__ == "__main__": main() diff --git a/maf_three/examples/simpleScanner.py b/maf_three/examples/simpleScanner.py index c84f3fa..da6671c 100644 --- a/maf_three/examples/simpleScanner.py +++ b/maf_three/examples/simpleScanner.py @@ -7,11 +7,11 @@ from maf_three.scanner import Scanner from maf_three.task import Task, TaskState -from MF.V3.Settings.Camera import Camera -from MF.V3.Settings.Capture import Capture -from MF.V3.Settings.Projector import Projector -from MF.V3.Settings.Turntable import Turntable -from MF.V3.Settings.Scan import Scan +from MF.V3.Settings.Camera_pb2 import Camera +from MF.V3.Settings.Capture_pb2 import Capture +from MF.V3.Settings.Projector_pb2 import Projector +from MF.V3.Settings.Turntable_pb2 import Turntable +from MF.V3.Settings.Scan_pb2 import Scan # Two frames for the video stream frame0 = np.zeros((0,0,3), np.uint8) diff --git a/maf_three/scanner.py b/maf_three/scanner.py index aac37b4..8e048f7 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -11,14 +11,12 @@ import threading import time +from MF.V3 import Task + from maf_three import __version__ -from maf_three.V3Task import V3Task from maf_three.serialization import TO_JSON -from maf_three.task import Task, TaskState from maf_three.buffer import Buffer -from MF.V3.Descriptors.Software import Software - class Scanner: """ @@ -53,14 +51,13 @@ def __init__(self, self.OnBuffer = OnBuffer - def Connect(self, URI:str, timeoutSec=5, checkVersionsCompatibility=True) -> bool: + def Connect(self, URI:str, timeoutSec=5) -> bool: """ Attempts to connect to the scanner using the specified URI and timeout. Args: * URI (str): The URI of the websocket server. * timeoutSec (int): Timeout in seconds, default is 5. - * checkVersionsCompatibility (bool): If True, right after the client connects to the server, check if the versions are compatible. Returns: bool: True if connection is successful, raises Exception otherwise. @@ -74,7 +71,6 @@ def Connect(self, URI:str, timeoutSec=5, checkVersionsCompatibility=True) -> boo self.__error = None self.__serverVersion__= None - self.__checkVersionsCompatibility__ = checkVersionsCompatibility self.websocket = websocket.WebSocketApp(self.__URI, on_open=self.__OnOpen, @@ -92,24 +88,7 @@ def Connect(self, URI:str, timeoutSec=5, checkVersionsCompatibility=True) -> boo while time.time() < start + timeoutSec: if self.__isConnected: # Not checking versions => return True - if not checkVersionsCompatibility: - return True - else: - # Request the server version - self.SendTask(0, V3Task.SoftwareVersionInstalled, 'three-server') - # Wait for the reply - while self.__serverVersion__ == None: - time.sleep(0.1) - # Compare the versions - if str(self.__serverVersion__.major) != __version__.split('.')[0]: - raise Exception( - 'Major versions of Python library and Server mismatch.\n'+ - '* Server: '+ str(self.__serverVersion__.major)+ '.'+str(self.__serverVersion__.minor)+'.'+str(self.__serverVersion__.patch)+'\n' - '* maf_three: '+ __version__+'\n'+ - 'Please update your python library: pip3 install --upgrade --no-cache-dir maf_three') - # Major versions match return True - elif self.__error: raise Exception(self.__error) time.sleep(0.1) @@ -210,13 +189,8 @@ def __OnMessage(self, ws, message) -> None: # Create the task from the message task = Task(**obj['Task']) - # Are we checking versions compatibility ? - if self.__checkVersionsCompatibility__ and task.Type == V3Task.SoftwareVersionInstalled and task.State == TaskState.Completed: - self.__serverVersion__ = Software.Version(**task.Output) - self.__checkVersionsCompatibility__ = False - # If assigned => Call the handler - elif self.OnTask: + if self.OnTask: self.OnTask(task) # Buffer @@ -228,7 +202,7 @@ def __OnMessage(self, ws, message) -> None: self.OnMessage(obj) # Send a task to the scanner - def SendTask(self, index:int, type:V3Task, input = None) -> Task: + def SendTask(self, task:Task) -> None: """ Sends a task to the scanner. Tasks are general control requests for the scanner. (eg. Camera exposure, or Get Image) @@ -236,21 +210,13 @@ def SendTask(self, index:int, type:V3Task, input = None) -> Task: Creates a task, serializes it, and sends it via the websocket. Args: - * index (int): The index of the task. - * type (V3Task): The type of the task. - * input: Additional input for the task, default is None. - - Returns: - Task: The task object that was sent. + * task (Task): The task to send. Raises: AssertionError: If the connection is not established. """ assert self.__isConnected - # Create the task - task = Task(index, type, input) - # Serialize the task message = TO_JSON(task) @@ -262,7 +228,7 @@ def SendTask(self, index:int, type:V3Task, input = None) -> Task: return task # Send a task with its buffer to the scanner - def SendTaskWithBuffer(self, index:int, type:V3Task, buffer:bytes, input = None) -> Task: + def SendTaskWithBuffer(self, task:Task, buffer:bytes) -> Task: """ Sends a task along with its associated buffer to the scanner. This call is used to send data to the scanner, like an image to be projected by the projector. @@ -271,10 +237,8 @@ def SendTaskWithBuffer(self, index:int, type:V3Task, buffer:bytes, input = None) The task is serialized, and sent to the scanner, followed by the buffer. Args: - * index (int): The index of the task. - * type (V3Task): The type of the task. + * task (Task): The task to send. * buffer (bytes): The buffer data to send. - * input: Additional input for the task, default is None. Returns: Task: The task object that was sent. @@ -285,7 +249,7 @@ def SendTaskWithBuffer(self, index:int, type:V3Task, buffer:bytes, input = None) assert self.__isConnected # Send the task - task = self.SendTask(index, type, input) + task = self.SendTask(task) # Build the buffer descriptor bufferSize = len(buffer) diff --git a/pyproject.toml b/pyproject.toml index 30e8ada..b2d281d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ classifiers = [ requires-python = ">=3.10" dependencies = [ 'importlib-metadata; python_version<"3.10"', - 'protobuf == 4.25.3', + 'protobuf >= 5.0.0', 'websocket-client >= 1.7.0', 'numpy >= 1.26.4' ] diff --git a/scripts/build-proto.py b/scripts/build-proto.py index 092afd0..dc37fc6 100644 --- a/scripts/build-proto.py +++ b/scripts/build-proto.py @@ -49,22 +49,21 @@ def BuildProtoFile(protoFile, inputDir, outputDir): os.system("rm -rf " + previousProtoOutputPath) files = glob.glob(protoInputPath+"/**/*.proto", recursive=True) -for file in files: - # Build - result = BuildProtoFile(file, protoInputPath, protoOutputPath) - - # Inspect result - fileCount += 1 - if result.returncode != 0: - fileError += 1 - print(RED + result.stderr.decode('utf-8') + ENDC) +status = subprocess.run([ + 'python3', + '-m', + 'grpc_tools.protoc', + *files, + f'-I={protoInputPath}', + f'--python_out={protoOutputPath}', + f'--pyi_out={protoOutputPath}', + '--experimental_allow_proto3_optional' + ], capture_output=True) # Print results print("*****************") -print(GREEN + 'Built: ' + str(fileCount - fileError) + " / " + str(fileCount) + " files." + ENDC) -if fileError > 0: - print(RED + 'Error: ' + str(fileError) + " / " + str(fileCount) + " files." + ENDC) +print(GREEN + 'Complete ' + str(status.returncode) + ENDC) print("*****************") # Let the caller know if everything was built @@ -83,7 +82,8 @@ def BuildProtoFile(protoFile, inputDir, outputDir): # Remove '_pb2' with open(file, "w") as f: for line in lines: - line = line.replace('_pb2', '') + if "MF.V3" in line: + line = line.replace('_pb2', '') f.write(line) # Rename the file From e8ec580e563231e6b96fb6a2420991f15c3a26d7 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 4 Sep 2024 19:25:30 -0400 Subject: [PATCH 04/86] Playing around with custom compilers for protoc --- scripts/interpretProto.py | 116 ++++++++++++++++++++++++++++++++++++++ scripts/transpileProto.py | 77 +++++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 scripts/interpretProto.py create mode 100644 scripts/transpileProto.py diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py new file mode 100644 index 0000000..b7a1d18 --- /dev/null +++ b/scripts/interpretProto.py @@ -0,0 +1,116 @@ +import re +import argparse + +from typing import List, Optional, Tuple + +class ProtoProperty: + def __init__(self, type_: str, name: str, optional: bool, comment: str) -> None: + self.type: str = type_ + self.name: str = name + self.optional: bool = optional + self.comment: str = comment + +class EnumType: + def __init__(self, name: str) -> None: + self.type: str = "enum" + self.name: str = name + self.properties: List[ProtoProperty] = [] + + def add_property(self, name: str, value: str) -> None: + self.properties.append(ProtoProperty("enum_value", name, False, f"Value: {value}")) + +class MessageType: + def __init__(self, name: str) -> None: + self.type: str = "message" + self.name: str = name + self.properties: List[ProtoProperty] = [] + + def add_property(self, type_: str, name: str, optional: bool, comment: str) -> None: + self.properties.append(ProtoProperty(type_, name, optional, comment)) + +def parse_proto(proto_file: str) -> Tuple[List[EnumType], List[MessageType]]: + with open(proto_file, 'r') as file: + lines: List[str] = file.readlines() + + enums: List[EnumType] = [] + messages: List[MessageType] = [] + current_message: Optional[MessageType] = None + current_enum: Optional[EnumType] = None + in_enum: bool = False + in_message: bool = False + + for line in lines: + line = line.strip() + + if line.startswith("enum"): + in_enum = True + enum_name: str = re.findall(r'enum (\w+)', line)[0] + current_enum = EnumType(enum_name) + enums.append(current_enum) + continue + + if line.startswith("message"): + in_message = True + message_name: str = re.findall(r'message (\w+)', line)[0] + current_message = MessageType(message_name) + messages.append(current_message) + continue + + if in_enum: + if line == "}": + in_enum = False + current_enum = None + else: + match = re.findall(r'(\w+) = (\d+);', line) + if match: + name, value = match[0] + current_enum.add_property(name, value) + + if in_message: + if line == "}": + in_message = False + current_message = None + else: + match = re.findall(r'(\w+) (\w+) = (\d+);', line) + if match: + type_, name, _ = match[0] + optional: bool = type_ != "required" + comment: str = "" # Add logic to extract comments if needed + current_message.add_property(type_, name, optional, comment) + + return enums, messages + +def print_object(obj: object, indent: int = 0) -> None: + indent_str = ' ' * indent + if isinstance(obj, list): + for item in obj: + print_object(item, indent) + elif isinstance(obj, ProtoProperty): + print(f"{indent_str}{obj.name} ({obj.type}) - Optional: {obj.optional}, Comment: {obj.comment}") + else: + print(f"{indent_str}{obj.__class__.__name__}: {obj.name}") + for key, value in obj.__dict__.items(): + if key != 'name' and key != 'type': + if isinstance(value, list): + print(f"{indent_str} {key}:") + print_object(value, indent + 4) + else: + print(f"{indent_str} {key}: {value}") + +def main() -> None: + parser = argparse.ArgumentParser(description="Parse a protobuf file and generate Python objects.") + parser.add_argument('proto_file', type=str, help='Path to the protobuf file') + args = parser.parse_args() + + enums, messages = parse_proto(args.proto_file) + + for enum in enums: + print_object(enum) + + + for message in messages: + print_object(message) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py new file mode 100644 index 0000000..2022c72 --- /dev/null +++ b/scripts/transpileProto.py @@ -0,0 +1,77 @@ +import re +import argparse + +def parse_proto_file(file_path): + with open(file_path, 'r') as file: + content = file.read() + return content + +def parse_imports(proto_content): + import_pattern = r'import\s+"([^"]+)"\s*;' + imports = re.findall(import_pattern, proto_content) + return imports + +def parse_messages(proto_content): + message_pattern = r'message\s+(\w+)\s*{([^}]*)}' + messages = re.findall(message_pattern, proto_content) + return messages + +def parse_enums(proto_content): + enum_pattern = r'enum\s+(\w+)\s*{([^}]*)}' + enums = re.findall(enum_pattern, proto_content) + return enums + +def generate_python_class(message_name, message_body): + class_def = f"class {message_name}:\n" + class_def += " def __init__(self" + + fields = [] + field_pattern = r'\s*(\w+)\s+(\w+)\s*=\s*\d+\s*;' + for field_type, field_name in re.findall(field_pattern, message_body): + fields.append((field_type, field_name)) + class_def += f", {field_name}=None" + + class_def += "):\n" + + for field_type, field_name in fields: + class_def += f" self.{field_name} = {field_name}\n" + + return class_def + +def generate_python_enum(enum_name, enum_body): + enum_def = f"class {enum_name}(Enum):\n" + value_pattern = r'\s*(\w+)\s*=\s*\d+\s*;' + for value_name in re.findall(value_pattern, enum_body): + enum_def += f" {value_name} = '{value_name}'\n" + return enum_def + +def transpile_proto_to_python(proto_file_path, output_file_path): + proto_content = parse_proto_file(proto_file_path) + + imports = parse_imports(proto_content) + messages = parse_messages(proto_content) + enums = parse_enums(proto_content) + + python_code = "# Generated Python classes from .proto file\n\n" + python_code += "from enum import Enum\n\n" + + for imp in imports: + python_code += f"# Import: {imp}\n" + + for enum_name, enum_body in enums: + python_code += "\n" + generate_python_enum(enum_name, enum_body) + "\n" + + for message_name, message_body in messages: + python_code += "\n" + generate_python_class(message_name, message_body) + "\n" + + with open(output_file_path, 'w') as output_file: + output_file.write(python_code) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Transpile a .proto file to a Python file.") + parser.add_argument("proto_file", help="Path to the input .proto file") + parser.add_argument("output_file", help="Path to the output .py file") + + args = parser.parse_args() + + transpile_proto_to_python(args.proto_file, args.output_file) \ No newline at end of file From 6ad583f235967b4199a8c9062a62c53e0bd90175 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 4 Sep 2024 19:48:34 -0400 Subject: [PATCH 05/86] improving the interpreter with comments and optionals --- scripts/interpretProto.py | 63 ++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index b7a1d18..c2f691d 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -11,18 +11,20 @@ def __init__(self, type_: str, name: str, optional: bool, comment: str) -> None: self.comment: str = comment class EnumType: - def __init__(self, name: str) -> None: + def __init__(self, name: str, comment: str) -> None: self.type: str = "enum" self.name: str = name + self.comment: str = comment self.properties: List[ProtoProperty] = [] - def add_property(self, name: str, value: str) -> None: - self.properties.append(ProtoProperty("enum_value", name, False, f"Value: {value}")) + def add_property(self, name: str, value: str, comment: str) -> None: + self.properties.append(ProtoProperty("enum_value", name, False, comment)) class MessageType: - def __init__(self, name: str) -> None: + def __init__(self, name: str, comment: str) -> None: self.type: str = "message" self.name: str = name + self.comment: str = comment self.properties: List[ProtoProperty] = [] def add_property(self, type_: str, name: str, optional: bool, comment: str) -> None: @@ -32,28 +34,48 @@ def parse_proto(proto_file: str) -> Tuple[List[EnumType], List[MessageType]]: with open(proto_file, 'r') as file: lines: List[str] = file.readlines() + imports: List[str] = [] enums: List[EnumType] = [] messages: List[MessageType] = [] current_message: Optional[MessageType] = None current_enum: Optional[EnumType] = None in_enum: bool = False in_message: bool = False + comments: List[str] = [] for line in lines: line = line.strip() + if line.startswith("import"): + match = re.findall(r'import\s+"([^"]+)";', line) + if match: + imports.append(match[0]) + continue + + if line.startswith("//") or line.startswith("/*") or line.startswith("*"): + comments.append(line) + continue + + if line == "": + continue + + if line.startswith("enum"): in_enum = True enum_name: str = re.findall(r'enum (\w+)', line)[0] - current_enum = EnumType(enum_name) + comment: str = "\n".join(comments) + current_enum = EnumType(enum_name, comment) enums.append(current_enum) + comments = [] continue if line.startswith("message"): in_message = True message_name: str = re.findall(r'message (\w+)', line)[0] - current_message = MessageType(message_name) + comment: str = "\n".join(comments) + current_message = MessageType(message_name, comment) messages.append(current_message) + comments = [] continue if in_enum: @@ -64,21 +86,24 @@ def parse_proto(proto_file: str) -> Tuple[List[EnumType], List[MessageType]]: match = re.findall(r'(\w+) = (\d+);', line) if match: name, value = match[0] - current_enum.add_property(name, value) + comment: str = "\n".join(comments) + current_enum.add_property(name, value, comment) + comments = [] if in_message: if line == "}": in_message = False current_message = None else: - match = re.findall(r'(\w+) (\w+) = (\d+);', line) + match = re.findall(r'(optional\s+)?([\w\.]+)\s+(\w+)\s*=\s*(\d+);', line) if match: - type_, name, _ = match[0] - optional: bool = type_ != "required" - comment: str = "" # Add logic to extract comments if needed + optional_str, type_, name, _ = match[0] + optional: bool = bool(optional_str) + comment: str = "\n".join(comments) current_message.add_property(type_, name, optional, comment) + comments = [] - return enums, messages + return imports, enums, messages def print_object(obj: object, indent: int = 0) -> None: indent_str = ' ' * indent @@ -98,19 +123,21 @@ def print_object(obj: object, indent: int = 0) -> None: print(f"{indent_str} {key}: {value}") def main() -> None: - parser = argparse.ArgumentParser(description="Parse a protobuf file and generate Python objects.") - parser.add_argument('proto_file', type=str, help='Path to the protobuf file') - args = parser.parse_args() + # parser = argparse.ArgumentParser(description="Parse a protobuf file and generate Python objects.") + # parser.add_argument('proto_file', type=str, help='Path to the protobuf file') + # args = parser.parse_args() - enums, messages = parse_proto(args.proto_file) + # enums, messages = parse_proto(args.proto_file) + imports, enums, messages = parse_proto("V3Schema/MF/V3/Task.proto") + for imp in imports: + print(f" {imp}") + for enum in enums: print_object(enum) - for message in messages: print_object(message) - if __name__ == "__main__": main() \ No newline at end of file From a42cd37540cede808ce11418fddd156e588eeb1f Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 4 Sep 2024 20:17:30 -0400 Subject: [PATCH 06/86] Add Namespace --- scripts/interpretProto.py | 48 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index c2f691d..4ba9201 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -1,6 +1,7 @@ import re import argparse - +import os +import glob from typing import List, Optional, Tuple class ProtoProperty: @@ -11,26 +12,28 @@ def __init__(self, type_: str, name: str, optional: bool, comment: str) -> None: self.comment: str = comment class EnumType: - def __init__(self, name: str, comment: str) -> None: + def __init__(self, name: str, comment: str, namespace: str) -> None: self.type: str = "enum" self.name: str = name self.comment: str = comment + self.namespace: str = namespace self.properties: List[ProtoProperty] = [] def add_property(self, name: str, value: str, comment: str) -> None: self.properties.append(ProtoProperty("enum_value", name, False, comment)) class MessageType: - def __init__(self, name: str, comment: str) -> None: + def __init__(self, name: str, comment: str, namespace: str) -> None: self.type: str = "message" self.name: str = name self.comment: str = comment + self.namespace: str = namespace self.properties: List[ProtoProperty] = [] def add_property(self, type_: str, name: str, optional: bool, comment: str) -> None: self.properties.append(ProtoProperty(type_, name, optional, comment)) -def parse_proto(proto_file: str) -> Tuple[List[EnumType], List[MessageType]]: +def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[EnumType], List[MessageType]]: with open(proto_file, 'r') as file: lines: List[str] = file.readlines() @@ -43,6 +46,10 @@ def parse_proto(proto_file: str) -> Tuple[List[EnumType], List[MessageType]]: in_message: bool = False comments: List[str] = [] + # Calculate namespace based on the relative path + relative_path = os.path.relpath(proto_file, base_dir) + namespace = os.path.dirname(relative_path).replace(os.sep, '.') + for line in lines: line = line.strip() @@ -59,12 +66,11 @@ def parse_proto(proto_file: str) -> Tuple[List[EnumType], List[MessageType]]: if line == "": continue - if line.startswith("enum"): in_enum = True enum_name: str = re.findall(r'enum (\w+)', line)[0] comment: str = "\n".join(comments) - current_enum = EnumType(enum_name, comment) + current_enum = EnumType(enum_name, comment, namespace) enums.append(current_enum) comments = [] continue @@ -73,7 +79,7 @@ def parse_proto(proto_file: str) -> Tuple[List[EnumType], List[MessageType]]: in_message = True message_name: str = re.findall(r'message (\w+)', line)[0] comment: str = "\n".join(comments) - current_message = MessageType(message_name, comment) + current_message = MessageType(message_name, comment, namespace) messages.append(current_message) comments = [] continue @@ -123,21 +129,25 @@ def print_object(obj: object, indent: int = 0) -> None: print(f"{indent_str} {key}: {value}") def main() -> None: - # parser = argparse.ArgumentParser(description="Parse a protobuf file and generate Python objects.") - # parser.add_argument('proto_file', type=str, help='Path to the protobuf file') - # args = parser.parse_args() + parser = argparse.ArgumentParser(description="Parse a directory of protobuf files and generate Python objects.") + parser.add_argument('directory', type=str, help='Path to the directory containing protobuf files') + args = parser.parse_args() + + proto_files = glob.glob(os.path.join(args.directory, '**', '*.proto'), recursive=True) + + for proto_file in proto_files: + print(f"Parsing file: {proto_file}") + imports, enums, messages = parse_proto(proto_file, args.directory) - # enums, messages = parse_proto(args.proto_file) - imports, enums, messages = parse_proto("V3Schema/MF/V3/Task.proto") + print("Imports:") + for imp in imports: + print(f" {imp}") - for imp in imports: - print(f" {imp}") - - for enum in enums: - print_object(enum) + for enum in enums: + print_object(enum) - for message in messages: - print_object(message) + for message in messages: + print_object(message) if __name__ == "__main__": main() \ No newline at end of file From 9f0b4b17a8b47ccba1c5b9b7795109a574f5ae8f Mon Sep 17 00:00:00 2001 From: Drew Shark Date: Thu, 5 Sep 2024 11:41:19 -0400 Subject: [PATCH 07/86] Transpiler additions. Still kinks to work out --- scripts/interpretProto.py | 85 ++++++++++++------- scripts/transpileProto.py | 171 ++++++++++++++++++++++---------------- 2 files changed, 153 insertions(+), 103 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index 4ba9201..cb879de 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -12,22 +12,20 @@ def __init__(self, type_: str, name: str, optional: bool, comment: str) -> None: self.comment: str = comment class EnumType: - def __init__(self, name: str, comment: str, namespace: str) -> None: + def __init__(self, name: str, comment: str) -> None: self.type: str = "enum" self.name: str = name self.comment: str = comment - self.namespace: str = namespace self.properties: List[ProtoProperty] = [] def add_property(self, name: str, value: str, comment: str) -> None: self.properties.append(ProtoProperty("enum_value", name, False, comment)) class MessageType: - def __init__(self, name: str, comment: str, namespace: str) -> None: + def __init__(self, name: str, comment: str) -> None: self.type: str = "message" self.name: str = name self.comment: str = comment - self.namespace: str = namespace self.properties: List[ProtoProperty] = [] def add_property(self, type_: str, name: str, optional: bool, comment: str) -> None: @@ -45,14 +43,19 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[EnumTyp in_enum: bool = False in_message: bool = False comments: List[str] = [] - - # Calculate namespace based on the relative path - relative_path = os.path.relpath(proto_file, base_dir) - namespace = os.path.dirname(relative_path).replace(os.sep, '.') + namespace: str = "" for line in lines: line = line.strip() + if line.startswith("package"): + match = re.findall(r'package\s+([\w\.]+);', line) + if match: + namespace = match[0] + else: + namespace = '' + continue + if line.startswith("import"): match = re.findall(r'import\s+"([^"]+)";', line) if match: @@ -70,7 +73,7 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[EnumTyp in_enum = True enum_name: str = re.findall(r'enum (\w+)', line)[0] comment: str = "\n".join(comments) - current_enum = EnumType(enum_name, comment, namespace) + current_enum = EnumType(enum_name, comment) enums.append(current_enum) comments = [] continue @@ -79,7 +82,7 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[EnumTyp in_message = True message_name: str = re.findall(r'message (\w+)', line)[0] comment: str = "\n".join(comments) - current_message = MessageType(message_name, comment, namespace) + current_message = MessageType(message_name, comment) messages.append(current_message) comments = [] continue @@ -109,7 +112,7 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[EnumTyp current_message.add_property(type_, name, optional, comment) comments = [] - return imports, enums, messages + return imports, enums, messages, namespace def print_object(obj: object, indent: int = 0) -> None: indent_str = ' ' * indent @@ -128,26 +131,46 @@ def print_object(obj: object, indent: int = 0) -> None: else: print(f"{indent_str} {key}: {value}") -def main() -> None: - parser = argparse.ArgumentParser(description="Parse a directory of protobuf files and generate Python objects.") - parser.add_argument('directory', type=str, help='Path to the directory containing protobuf files') - args = parser.parse_args() - - proto_files = glob.glob(os.path.join(args.directory, '**', '*.proto'), recursive=True) +def create_proto_objects(directory: str): + proto_files = glob.glob(os.path.join(directory, '**', '*.proto'), recursive=True) + all_objs = [] for proto_file in proto_files: print(f"Parsing file: {proto_file}") - imports, enums, messages = parse_proto(proto_file, args.directory) - - print("Imports:") - for imp in imports: - print(f" {imp}") - - for enum in enums: - print_object(enum) - - for message in messages: - print_object(message) - -if __name__ == "__main__": - main() \ No newline at end of file + imports, enums, messages, namespace = parse_proto(proto_file, directory) + # Get relative path of the file + proto_file = os.path.relpath(proto_file, directory) + + # create object that has imports, enums, and messages, and namespace to keep them together + all_objs.append({ + "imports": imports, + "enums": enums, + "messages": messages, + "namespace": namespace, + "filename": proto_file + }) + return all_objs + +# def main() -> None: +# parser = argparse.ArgumentParser(description="Parse a directory of protobuf files and generate Python objects.") +# parser.add_argument('directory', type=str, help='Path to the directory containing protobuf files') +# args = parser.parse_args() +# +# proto_files = glob.glob(os.path.join(args.directory, '**', '*.proto'), recursive=True) +# +# for proto_file in proto_files: +# print(f"Parsing file: {proto_file}") +# imports, enums, messages = parse_proto(proto_file, args.directory) +# +# print("Imports:") +# for imp in imports: +# print(f" {imp}") +# +# for enum in enums: +# print_object(enum) +# +# for message in messages: +# print_object(message) +# +# if __name__ == "__main__": +# main() \ No newline at end of file diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 2022c72..1050a4a 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -1,77 +1,104 @@ -import re +import os import argparse +from interpretProto import create_proto_objects, EnumType, MessageType +from typing import List, Dict -def parse_proto_file(file_path): - with open(file_path, 'r') as file: - content = file.read() - return content - -def parse_imports(proto_content): - import_pattern = r'import\s+"([^"]+)"\s*;' - imports = re.findall(import_pattern, proto_content) - return imports - -def parse_messages(proto_content): - message_pattern = r'message\s+(\w+)\s*{([^}]*)}' - messages = re.findall(message_pattern, proto_content) - return messages - -def parse_enums(proto_content): - enum_pattern = r'enum\s+(\w+)\s*{([^}]*)}' - enums = re.findall(enum_pattern, proto_content) - return enums - -def generate_python_class(message_name, message_body): - class_def = f"class {message_name}:\n" - class_def += " def __init__(self" - - fields = [] - field_pattern = r'\s*(\w+)\s+(\w+)\s*=\s*\d+\s*;' - for field_type, field_name in re.findall(field_pattern, message_body): - fields.append((field_type, field_name)) - class_def += f", {field_name}=None" - - class_def += "):\n" - - for field_type, field_name in fields: - class_def += f" self.{field_name} = {field_name}\n" - - return class_def - -def generate_python_enum(enum_name, enum_body): - enum_def = f"class {enum_name}(Enum):\n" - value_pattern = r'\s*(\w+)\s*=\s*\d+\s*;' - for value_name in re.findall(value_pattern, enum_body): - enum_def += f" {value_name} = '{value_name}'\n" - return enum_def - -def transpile_proto_to_python(proto_file_path, output_file_path): - proto_content = parse_proto_file(proto_file_path) - - imports = parse_imports(proto_content) - messages = parse_messages(proto_content) - enums = parse_enums(proto_content) - - python_code = "# Generated Python classes from .proto file\n\n" - python_code += "from enum import Enum\n\n" - + +def load_proto_objects(input_dir: str): + # Call the function from interpretProto.py to create the proto objects + proto_objects = create_proto_objects(input_dir) + return proto_objects + +def generate_import_lines(imports: List[str]) -> str: + import_lines = [] for imp in imports: - python_code += f"# Import: {imp}\n" - - for enum_name, enum_body in enums: - python_code += "\n" + generate_python_enum(enum_name, enum_body) + "\n" - - for message_name, message_body in messages: - python_code += "\n" + generate_python_class(message_name, message_body) + "\n" - - with open(output_file_path, 'w') as output_file: - output_file.write(python_code) + # Split the import path into parts + module_path = os.path.splitext(imp.replace('/', '.'))[0] + module_parts = module_path.split('.') + module_name = module_parts[-1] + # Special consideration for google imports + if "google" in module_parts: + import_line = f"from {'.'.join(module_parts[:-1])} import {module_name}_pb2 as _{module_name}_pb2" + else: + import_line = f"import {module_path}" + import_lines.append(import_line) + return "\n".join(import_lines) -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Transpile a .proto file to a Python file.") - parser.add_argument("proto_file", help="Path to the input .proto file") - parser.add_argument("output_file", help="Path to the output .py file") - +def generate_python_code(proto_objects: List, output_dir: str): + for obj in proto_objects: + print(obj) + # Access namespace, imports, messages, enums from the dictionary obj + #namespace = obj['namespace'] + imports = obj['imports'] + messages = obj['messages'] + enums = obj['enums'] + file_path = obj['filename'] + + # Get the base path of the file + path = os.path.join(output_dir, os.path.dirname(file_path)) + # Get the filename without the extension + filename = os.path.basename(file_path).replace('.proto', '') + # Create the directory if it doesn't exist + os.makedirs(path, exist_ok=True) + + # Generate imports + import_lines = generate_import_lines(imports) + + # Generate code for messages + message_code = "" + for message in messages: + message_code += generate_message_code(message) + "\n\n" + + # Generate code for enums + enum_code = "" + for enum in enums: + enum_code += generate_enum_code(enum) + "\n\n" + + # Combine imports, message code, and enum code + combined_code = import_lines + "\n\n" + message_code + enum_code + + # Write the combined code to a file with the name from the file_path + filename = os.path.join(path, f"{filename}.py") + with open(filename, 'w') as f: + f.write(combined_code) + +def generate_message_code(message: Dict) -> str: + comment = message.comment + name = message.name + properties = message.properties + + class_code = f'"""{comment}"""\n' + class_code += f"class {name}:\n" + class_code += " def __init__(self" + for prop in properties: + class_code += f", {prop.name}: {prop.type}" + if prop.optional: + class_code += " = None" + class_code += "):\n" + for prop in properties: + class_code += f" self.{prop.name} = {prop.name} # {prop.comment}\n" + return class_code + +def generate_enum_code(enum) -> str: + comment = enum.comment + name = enum.name + values = enum.properties + + enum_code = f'"""{comment}"""\n' + enum_code += f"from enum import Enum\n\n" + enum_code += f"class {name}(Enum):\n" + for value in values: + enum_code += f" {value.name} = \"{value.name}\" # {value.comment}\n" + return enum_code + +def main(): + parser = argparse.ArgumentParser(description="Generate Python classes and enums from protobuf schema objects.") + parser.add_argument('input_dir', type=str, nargs='?', default='./V3Schema', help='The input directory containing the protobuf schema objects.') + parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() - - transpile_proto_to_python(args.proto_file, args.output_file) \ No newline at end of file + + proto_objects = load_proto_objects(args.input_dir) + generate_python_code(proto_objects, args.output_dir) + +if __name__ == "__main__": + main() \ No newline at end of file From cedf7e0b72edff6eb8f7ffcdbbd2027712b8773a Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 5 Sep 2024 19:58:10 -0400 Subject: [PATCH 08/86] Added proper type mapping. Removed Enums as special case --- scripts/interpretProto.py | 141 +++++++++++++++++--------------------- scripts/transpileProto.py | 93 +++++++++++++++++++------ 2 files changed, 135 insertions(+), 99 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index cb879de..a0ad4d7 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -11,39 +11,31 @@ def __init__(self, type_: str, name: str, optional: bool, comment: str) -> None: self.optional: bool = optional self.comment: str = comment -class EnumType: - def __init__(self, name: str, comment: str) -> None: - self.type: str = "enum" - self.name: str = name - self.comment: str = comment - self.properties: List[ProtoProperty] = [] - - def add_property(self, name: str, value: str, comment: str) -> None: - self.properties.append(ProtoProperty("enum_value", name, False, comment)) - class MessageType: - def __init__(self, name: str, comment: str) -> None: - self.type: str = "message" + def __init__(self, type_: str, name: str, comment: str) -> None: + self.type: str = type_ self.name: str = name self.comment: str = comment self.properties: List[ProtoProperty] = [] + self.nested_messages = [] def add_property(self, type_: str, name: str, optional: bool, comment: str) -> None: self.properties.append(ProtoProperty(type_, name, optional, comment)) + + def add_nested_message(self, message): + self.nested_messages.append(message) -def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[EnumType], List[MessageType]]: + +def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[MessageType]]: with open(proto_file, 'r') as file: lines: List[str] = file.readlines() imports: List[str] = [] - enums: List[EnumType] = [] messages: List[MessageType] = [] - current_message: Optional[MessageType] = None - current_enum: Optional[EnumType] = None - in_enum: bool = False - in_message: bool = False + in_message: int = 0 comments: List[str] = [] namespace: str = "" + current_message_stack = [] for line in lines: line = line.strip() @@ -56,80 +48,72 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[EnumTyp namespace = '' continue - if line.startswith("import"): + elif line.startswith("import"): match = re.findall(r'import\s+"([^"]+)";', line) if match: imports.append(match[0]) continue - if line.startswith("//") or line.startswith("/*") or line.startswith("*"): - comments.append(line) + elif line.startswith("//") or line.startswith("/*") or line.startswith("*"): + cleaned_line = line.lstrip("/*") + comments.append(cleaned_line) continue - if line == "": + elif line == "": continue - if line.startswith("enum"): - in_enum = True - enum_name: str = re.findall(r'enum (\w+)', line)[0] - comment: str = "\n".join(comments) - current_enum = EnumType(enum_name, comment) - enums.append(current_enum) - comments = [] - continue + elif line.startswith("message") or line.startswith("enum"): + + comment = "\n".join(comments) + + if line.startswith("enum"): + message_name = re.findall(r'enum (\w+)', line)[0] + message_type = "enum" + else: + message_name: str = re.findall(r'message (\w+)', line)[0] + message_type = "message" + + new_message = MessageType(message_type, message_name, comment) + + if current_message_stack: + current_message_stack[-1].add_nested_message(new_message) + else: + messages.append(new_message) - if line.startswith("message"): - in_message = True - message_name: str = re.findall(r'message (\w+)', line)[0] - comment: str = "\n".join(comments) - current_message = MessageType(message_name, comment) - messages.append(current_message) + current_message_stack.append(new_message) + comments = [] continue + elif line == "{": + in_message += 1 + continue - if in_enum: - if line == "}": - in_enum = False - current_enum = None - else: - match = re.findall(r'(\w+) = (\d+);', line) - if match: - name, value = match[0] - comment: str = "\n".join(comments) - current_enum.add_property(name, value, comment) - comments = [] - - if in_message: + elif in_message > 0: if line == "}": - in_message = False - current_message = None + in_message -= 1 + current_message_stack.pop() else: - match = re.findall(r'(optional\s+)?([\w\.]+)\s+(\w+)\s*=\s*(\d+);', line) - if match: - optional_str, type_, name, _ = match[0] - optional: bool = bool(optional_str) - comment: str = "\n".join(comments) - current_message.add_property(type_, name, optional, comment) - comments = [] - - return imports, enums, messages, namespace - -def print_object(obj: object, indent: int = 0) -> None: - indent_str = ' ' * indent - if isinstance(obj, list): - for item in obj: - print_object(item, indent) - elif isinstance(obj, ProtoProperty): - print(f"{indent_str}{obj.name} ({obj.type}) - Optional: {obj.optional}, Comment: {obj.comment}") - else: - print(f"{indent_str}{obj.__class__.__name__}: {obj.name}") - for key, value in obj.__dict__.items(): - if key != 'name' and key != 'type': - if isinstance(value, list): - print(f"{indent_str} {key}:") - print_object(value, indent + 4) + if current_message_stack[-1].type == "enum": + match = re.findall(r'(\w+)\s*=\s*(\d+);', line) + if match: + name, value = match[0] + comment = "\n".join(comments) + current_message_stack[-1].add_property("string", name, False, comment) + comments = [] + else: + print(f"Error parsing enum: {line}") else: - print(f"{indent_str} {key}: {value}") + match = re.findall(r'(optional\s+)?([\w\.]+)\s+(\w+)\s*=\s*(\d+);', line) + if match: + optional_str, type_, name, _ = match[0] + optional: bool = bool(optional_str) + comment: str = "\n".join(comments) + current_message_stack[-1].add_property(type_, name, optional, comment) + comments = [] + else : + print(f"Error parsing message: {line}") + + return imports, messages, namespace def create_proto_objects(directory: str): proto_files = glob.glob(os.path.join(directory, '**', '*.proto'), recursive=True) @@ -137,14 +121,13 @@ def create_proto_objects(directory: str): for proto_file in proto_files: print(f"Parsing file: {proto_file}") - imports, enums, messages, namespace = parse_proto(proto_file, directory) + imports, messages, namespace = parse_proto(proto_file, directory) # Get relative path of the file proto_file = os.path.relpath(proto_file, directory) - # create object that has imports, enums, and messages, and namespace to keep them together + # create object that has imports, and messages, and namespace to keep them together all_objs.append({ "imports": imports, - "enums": enums, "messages": messages, "namespace": namespace, "filename": proto_file diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 1050a4a..4276a23 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -1,6 +1,6 @@ import os import argparse -from interpretProto import create_proto_objects, EnumType, MessageType +from interpretProto import create_proto_objects, MessageType, parse_proto from typing import List, Dict @@ -31,7 +31,6 @@ def generate_python_code(proto_objects: List, output_dir: str): #namespace = obj['namespace'] imports = obj['imports'] messages = obj['messages'] - enums = obj['enums'] file_path = obj['filename'] # Get the base path of the file @@ -47,36 +46,70 @@ def generate_python_code(proto_objects: List, output_dir: str): # Generate code for messages message_code = "" for message in messages: - message_code += generate_message_code(message) + "\n\n" - - # Generate code for enums - enum_code = "" - for enum in enums: - enum_code += generate_enum_code(enum) + "\n\n" + if message.type == "message": + message_code += generate_message_code(message) + "\n\n" + elif message.type == "enum": + message_code += generate_enum_code(message) + "\n\n" # Combine imports, message code, and enum code - combined_code = import_lines + "\n\n" + message_code + enum_code + combined_code = import_lines + "\n\n" + message_code # Write the combined code to a file with the name from the file_path filename = os.path.join(path, f"{filename}.py") with open(filename, 'w') as f: f.write(combined_code) +# Mapping of special types to Python types +type_mapping = { + "int32": "int", + "Int32": "int", + "int64": "int", + "Int64": "int", + "float": "float", + "Float": "float", + "double": "float", + "Double": "float", + "string": "str", + "String": "str", + # Add more mappings as needed +} + def generate_message_code(message: Dict) -> str: comment = message.comment name = message.name properties = message.properties - - class_code = f'"""{comment}"""\n' + nested_messages = message.nested_messages + + if comment != "": + if len(comment.split('\n')) > 1: + class_code = f'"""{comment}"""\n' + else: + class_code = f'# {comment}\n' + else: + class_code = '' + class_code += f"class {name}:\n" - class_code += " def __init__(self" - for prop in properties: - class_code += f", {prop.name}: {prop.type}" - if prop.optional: - class_code += " = None" - class_code += "):\n" - for prop in properties: - class_code += f" self.{prop.name} = {prop.name} # {prop.comment}\n" + + if properties: + class_code += " def __init__(self" + for prop in properties: + prop_type = type_mapping.get(prop.type, prop.type) + class_code += f", {prop.name}: {prop_type}" + if prop.optional: + class_code += " = None" + class_code += "):\n" + for prop in properties: + class_code += f" self.{prop.name} = {prop.name} # {prop.comment}\n" + else: + class_code += " def __init__(self):\n" + class_code += " pass\n" + + # Generate code for nested messages + for nested_message in nested_messages: + nested_class_code = generate_message_code(nested_message) + nested_class_code = "\n".join([f" {line}" for line in nested_class_code.split("\n")]) + class_code += f"\n{nested_class_code}\n" + return class_code def generate_enum_code(enum) -> str: @@ -97,8 +130,28 @@ def main(): parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() - proto_objects = load_proto_objects(args.input_dir) + # proto_objects = load_proto_objects(args.input_dir) + # generate_python_code(proto_objects, args.output_dir) + + imports, messages, namespace = parse_proto("./V3Schema/MF/V3/Task.proto", args.input_dir) + + # Add imports enum and messages to an object + proto_objects = [{ + "imports": imports, + "messages": messages, + "namespace": namespace, + "filename": "AddMergeToProject.proto" + }] generate_python_code(proto_objects, args.output_dir) + # print("Imports:") + # print(imports) + # print("Enums:") + # print(enums) + # print("Messages:") + # print(messages) + # print("Namespace:") + # print(namespace) + if __name__ == "__main__": main() \ No newline at end of file From 7a578674bfaaadf797e21ae855581f0c80d31e42 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 5 Sep 2024 20:11:17 -0400 Subject: [PATCH 09/86] Handles enum imports and google any in init defs --- scripts/interpretProto.py | 1 + scripts/transpileProto.py | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index a0ad4d7..8238e12 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -69,6 +69,7 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message if line.startswith("enum"): message_name = re.findall(r'enum (\w+)', line)[0] message_type = "enum" + imports.append("enum/Enum.py") else: message_name: str = re.findall(r'message (\w+)', line)[0] message_type = "message" diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 4276a23..bcd18ce 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -20,7 +20,11 @@ def generate_import_lines(imports: List[str]) -> str: if "google" in module_parts: import_line = f"from {'.'.join(module_parts[:-1])} import {module_name}_pb2 as _{module_name}_pb2" else: - import_line = f"import {module_path}" + # Check if the import has a namespace + if len(module_parts) > 1: + import_line = f"from {'.'.join(module_parts[:-1])} import {module_name}" + else: + import_line = f"import {module_path}" import_lines.append(import_line) return "\n".join(import_lines) @@ -71,15 +75,10 @@ def generate_python_code(proto_objects: List, output_dir: str): "Double": "float", "string": "str", "String": "str", - # Add more mappings as needed + "google.protobuf.Any": "_any_pb2" } -def generate_message_code(message: Dict) -> str: - comment = message.comment - name = message.name - properties = message.properties - nested_messages = message.nested_messages - +def parseComment(comment: str) -> str: if comment != "": if len(comment.split('\n')) > 1: class_code = f'"""{comment}"""\n' @@ -87,6 +86,15 @@ def generate_message_code(message: Dict) -> str: class_code = f'# {comment}\n' else: class_code = '' + return class_code + +def generate_message_code(message: Dict) -> str: + comment = message.comment + name = message.name + properties = message.properties + nested_messages = message.nested_messages + + class_code = parseComment(comment) class_code += f"class {name}:\n" @@ -117,8 +125,7 @@ def generate_enum_code(enum) -> str: name = enum.name values = enum.properties - enum_code = f'"""{comment}"""\n' - enum_code += f"from enum import Enum\n\n" + enum_code = parseComment(comment) enum_code += f"class {name}(Enum):\n" for value in values: enum_code += f" {value.name} = \"{value.name}\" # {value.comment}\n" @@ -140,7 +147,7 @@ def main(): "imports": imports, "messages": messages, "namespace": namespace, - "filename": "AddMergeToProject.proto" + "filename": "MF/V3/Task.proto" }] generate_python_code(proto_objects, args.output_dir) # print("Imports:") From 4819008072a34b94163214d0a8b0f3bb92ffe721 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 5 Sep 2024 20:38:41 -0400 Subject: [PATCH 10/86] fix uint and inmessage counter --- scripts/interpretProto.py | 3 +-- scripts/transpileProto.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index 8238e12..ca4765a 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -63,7 +63,7 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message continue elif line.startswith("message") or line.startswith("enum"): - + in_message += 1 comment = "\n".join(comments) if line.startswith("enum"): @@ -86,7 +86,6 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message comments = [] continue elif line == "{": - in_message += 1 continue elif in_message > 0: diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index bcd18ce..dd7bc8b 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -69,6 +69,12 @@ def generate_python_code(proto_objects: List, output_dir: str): "Int32": "int", "int64": "int", "Int64": "int", + "uint64": "int", + "UInt64": "int", + "uint32": "int", + "UInt32": "int", + "bool": "bool", + "Bool": "bool", "float": "float", "Float": "float", "double": "float", @@ -140,14 +146,14 @@ def main(): # proto_objects = load_proto_objects(args.input_dir) # generate_python_code(proto_objects, args.output_dir) - imports, messages, namespace = parse_proto("./V3Schema/MF/V3/Task.proto", args.input_dir) + imports, messages, namespace = parse_proto("./V3Schema/MF/V3/Buffer.proto", args.input_dir) # Add imports enum and messages to an object proto_objects = [{ "imports": imports, "messages": messages, "namespace": namespace, - "filename": "MF/V3/Task.proto" + "filename": "MF/V3/Buffer.proto" }] generate_python_code(proto_objects, args.output_dir) # print("Imports:") From ac56933ecd40e3f01422dceb637cc54576416d84 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 5 Sep 2024 21:15:08 -0400 Subject: [PATCH 11/86] Fix imports with wildcard for now --- scripts/transpileProto.py | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index dd7bc8b..e5f7a0d 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -22,7 +22,7 @@ def generate_import_lines(imports: List[str]) -> str: else: # Check if the import has a namespace if len(module_parts) > 1: - import_line = f"from {'.'.join(module_parts[:-1])} import {module_name}" + import_line = f"from {'.'.join(module_parts[:])} import *" else: import_line = f"import {module_path}" import_lines.append(import_line) @@ -143,28 +143,19 @@ def main(): parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() - # proto_objects = load_proto_objects(args.input_dir) - # generate_python_code(proto_objects, args.output_dir) + proto_objects = load_proto_objects(args.input_dir) + generate_python_code(proto_objects, args.output_dir) - imports, messages, namespace = parse_proto("./V3Schema/MF/V3/Buffer.proto", args.input_dir) + # imports, messages, namespace = parse_proto("./V3Schema/MF/V3/Tasks/AddMergeToProject.proto", args.input_dir) # Add imports enum and messages to an object - proto_objects = [{ - "imports": imports, - "messages": messages, - "namespace": namespace, - "filename": "MF/V3/Buffer.proto" - }] - generate_python_code(proto_objects, args.output_dir) - # print("Imports:") - # print(imports) - # print("Enums:") - # print(enums) - # print("Messages:") - # print(messages) - # print("Namespace:") - # print(namespace) - + # proto_objects = [{ + # "imports": imports, + # "messages": messages, + # "namespace": namespace, + # "filename": "MF/V3/Tasks/AddMergeToProject.proto" + # }] + # generate_python_code(proto_objects, args.output_dir) if __name__ == "__main__": main() \ No newline at end of file From 6ae9348345e99d7e96e8db90aee47528ad1a200c Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 5 Sep 2024 21:20:06 -0400 Subject: [PATCH 12/86] Fix nested classes first --- scripts/transpileProto.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index e5f7a0d..83c4d83 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -104,6 +104,12 @@ def generate_message_code(message: Dict) -> str: class_code += f"class {name}:\n" + # Generate code for nested messages + for nested_message in nested_messages: + nested_class_code = generate_message_code(nested_message) + nested_class_code = "\n".join([f" {line}" for line in nested_class_code.split("\n")]) + class_code += f"\n{nested_class_code}\n" + if properties: class_code += " def __init__(self" for prop in properties: @@ -118,11 +124,7 @@ def generate_message_code(message: Dict) -> str: class_code += " def __init__(self):\n" class_code += " pass\n" - # Generate code for nested messages - for nested_message in nested_messages: - nested_class_code = generate_message_code(nested_message) - nested_class_code = "\n".join([f" {line}" for line in nested_class_code.split("\n")]) - class_code += f"\n{nested_class_code}\n" + return class_code @@ -143,19 +145,19 @@ def main(): parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() - proto_objects = load_proto_objects(args.input_dir) - generate_python_code(proto_objects, args.output_dir) + # proto_objects = load_proto_objects(args.input_dir) + # generate_python_code(proto_objects, args.output_dir) - # imports, messages, namespace = parse_proto("./V3Schema/MF/V3/Tasks/AddMergeToProject.proto", args.input_dir) + imports, messages, namespace = parse_proto("./V3Schema/MF/V3/Descriptors/Settings/Camera.proto", args.input_dir) # Add imports enum and messages to an object - # proto_objects = [{ - # "imports": imports, - # "messages": messages, - # "namespace": namespace, - # "filename": "MF/V3/Tasks/AddMergeToProject.proto" - # }] - # generate_python_code(proto_objects, args.output_dir) + proto_objects = [{ + "imports": imports, + "messages": messages, + "namespace": namespace, + "filename": "MF/V3/Descriptors/Settings/Camera.proto" + }] + generate_python_code(proto_objects, args.output_dir) if __name__ == "__main__": main() \ No newline at end of file From 4a5a2baf0599880b6d45944c7bf4a423a923b6d6 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 6 Sep 2024 11:34:44 -0400 Subject: [PATCH 13/86] fixed indenting of comments. Adding __init__ --- scripts/interpretProto.py | 5 ++++- scripts/transpileProto.py | 41 ++++++++++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index ca4765a..d8b57cf 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -55,7 +55,10 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message continue elif line.startswith("//") or line.startswith("/*") or line.startswith("*"): - cleaned_line = line.lstrip("/*") + cleaned_line = line.lstrip() + #clean out /* * and // from the comments + cleaned_line = re.sub(r'^/\*|\*/|^\*|//', '', cleaned_line) + comments.append(cleaned_line) continue diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 83c4d83..9843a1e 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -28,7 +28,10 @@ def generate_import_lines(imports: List[str]) -> str: import_lines.append(import_line) return "\n".join(import_lines) -def generate_python_code(proto_objects: List, output_dir: str): +def generate_python_code(proto_objects: List, output_dir: str) -> set: + # create a unique set of paths + paths = set() + for obj in proto_objects: print(obj) # Access namespace, imports, messages, enums from the dictionary obj @@ -41,8 +44,12 @@ def generate_python_code(proto_objects: List, output_dir: str): path = os.path.join(output_dir, os.path.dirname(file_path)) # Get the filename without the extension filename = os.path.basename(file_path).replace('.proto', '') + # Create the directory if it doesn't exist os.makedirs(path, exist_ok=True) + # Add the path to a unique set + paths.add(path) + # Generate imports import_lines = generate_import_lines(imports) @@ -62,6 +69,8 @@ def generate_python_code(proto_objects: List, output_dir: str): filename = os.path.join(path, f"{filename}.py") with open(filename, 'w') as f: f.write(combined_code) + + return paths # Mapping of special types to Python types type_mapping = { @@ -94,6 +103,9 @@ def parseComment(comment: str) -> str: class_code = '' return class_code +def add_indents(code: str, indent: int) -> str: + return "\n".join([f"{' ' * indent}{line}" for line in code.split("\n")]) + def generate_message_code(message: Dict) -> str: comment = message.comment name = message.name @@ -107,25 +119,28 @@ def generate_message_code(message: Dict) -> str: # Generate code for nested messages for nested_message in nested_messages: nested_class_code = generate_message_code(nested_message) - nested_class_code = "\n".join([f" {line}" for line in nested_class_code.split("\n")]) + nested_class_code = add_indents(nested_class_code,1) class_code += f"\n{nested_class_code}\n" - + if properties: class_code += " def __init__(self" for prop in properties: prop_type = type_mapping.get(prop.type, prop.type) + # Extract the last value of the type if it contains dots + if '.' in prop_type: + prop_type = prop_type.split('.')[-1] class_code += f", {prop.name}: {prop_type}" if prop.optional: class_code += " = None" class_code += "):\n" for prop in properties: - class_code += f" self.{prop.name} = {prop.name} # {prop.comment}\n" + # Add comments with parseComment function with spaces + class_code += f"{add_indents(parseComment(prop.comment),2)}\n" + class_code += f" self.{prop.name} = {prop.name}\n" else: class_code += " def __init__(self):\n" class_code += " pass\n" - - return class_code def generate_enum_code(enum) -> str: @@ -139,6 +154,12 @@ def generate_enum_code(enum) -> str: enum_code += f" {value.name} = \"{value.name}\" # {value.comment}\n" return enum_code +def generate_init_files(paths: set): + for path in paths: + init_file = os.path.join(path, "__init__.py") + with open(init_file, 'w') as f: + f.write("") + def main(): parser = argparse.ArgumentParser(description="Generate Python classes and enums from protobuf schema objects.") parser.add_argument('input_dir', type=str, nargs='?', default='./V3Schema', help='The input directory containing the protobuf schema objects.') @@ -146,16 +167,18 @@ def main(): args = parser.parse_args() # proto_objects = load_proto_objects(args.input_dir) - # generate_python_code(proto_objects, args.output_dir) + # paths = generate_python_code(proto_objects, args.output_dir) + # generate_init_files(paths) - imports, messages, namespace = parse_proto("./V3Schema/MF/V3/Descriptors/Settings/Camera.proto", args.input_dir) + name = "Settings/Advanced.proto" + imports, messages, namespace = parse_proto(f"./V3Schema/MF/V3/{name}" , args.input_dir) # Add imports enum and messages to an object proto_objects = [{ "imports": imports, "messages": messages, "namespace": namespace, - "filename": "MF/V3/Descriptors/Settings/Camera.proto" + "filename": f"MF/V3/{name}" }] generate_python_code(proto_objects, args.output_dir) From 12b37d05ae5577350649d5d3c9fca5bd5d9fe6f3 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 6 Sep 2024 11:50:30 -0400 Subject: [PATCH 14/86] Fix Comment spacing --- scripts/transpileProto.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 9843a1e..ce061cb 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -100,7 +100,7 @@ def parseComment(comment: str) -> str: else: class_code = f'# {comment}\n' else: - class_code = '' + class_code = '\n' return class_code def add_indents(code: str, indent: int) -> str: @@ -135,8 +135,8 @@ def generate_message_code(message: Dict) -> str: class_code += "):\n" for prop in properties: # Add comments with parseComment function with spaces - class_code += f"{add_indents(parseComment(prop.comment),2)}\n" - class_code += f" self.{prop.name} = {prop.name}\n" + class_code += f"\n{add_indents(parseComment(prop.comment),2)}" + class_code += f"self.{prop.name} = {prop.name}\n" else: class_code += " def __init__(self):\n" class_code += " pass\n" From 232989095224805bf031202b3db5e1761cf752c2 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 6 Sep 2024 12:26:06 -0400 Subject: [PATCH 15/86] Sort properties by optional. Make imports a set instead of a list --- scripts/interpretProto.py | 13 +++++++----- scripts/transpileProto.py | 42 ++++++++++++++++++++++----------------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index d8b57cf..a21db33 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -2,7 +2,9 @@ import argparse import os import glob -from typing import List, Optional, Tuple +from typing import List, Optional, Tuple, Set + + class ProtoProperty: def __init__(self, type_: str, name: str, optional: bool, comment: str) -> None: @@ -27,10 +29,11 @@ def add_nested_message(self, message): def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[MessageType]]: + with open(proto_file, 'r') as file: lines: List[str] = file.readlines() - - imports: List[str] = [] + + imports: Set[str] = set() messages: List[MessageType] = [] in_message: int = 0 comments: List[str] = [] @@ -51,7 +54,7 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message elif line.startswith("import"): match = re.findall(r'import\s+"([^"]+)";', line) if match: - imports.append(match[0]) + imports.add(match[0]) continue elif line.startswith("//") or line.startswith("/*") or line.startswith("*"): @@ -72,7 +75,7 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message if line.startswith("enum"): message_name = re.findall(r'enum (\w+)', line)[0] message_type = "enum" - imports.append("enum/Enum.py") + imports.add("enum/Enum.py") else: message_name: str = re.findall(r'message (\w+)', line)[0] message_type = "message" diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index ce061cb..7982486 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -121,14 +121,17 @@ def generate_message_code(message: Dict) -> str: nested_class_code = generate_message_code(nested_message) nested_class_code = add_indents(nested_class_code,1) class_code += f"\n{nested_class_code}\n" - + if properties: + # sort properties so optionals are last + properties = sorted(properties, key=lambda x: x.optional) + class_code += " def __init__(self" for prop in properties: prop_type = type_mapping.get(prop.type, prop.type) # Extract the last value of the type if it contains dots - if '.' in prop_type: - prop_type = prop_type.split('.')[-1] + # if '.' in prop_type: + # prop_type = prop_type.split('.')[-1] class_code += f", {prop.name}: {prop_type}" if prop.optional: class_code += " = None" @@ -166,21 +169,24 @@ def main(): parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() - # proto_objects = load_proto_objects(args.input_dir) - # paths = generate_python_code(proto_objects, args.output_dir) - # generate_init_files(paths) - - name = "Settings/Advanced.proto" - imports, messages, namespace = parse_proto(f"./V3Schema/MF/V3/{name}" , args.input_dir) - - # Add imports enum and messages to an object - proto_objects = [{ - "imports": imports, - "messages": messages, - "namespace": namespace, - "filename": f"MF/V3/{name}" - }] - generate_python_code(proto_objects, args.output_dir) + if 1: + proto_objects = load_proto_objects(args.input_dir) + paths = generate_python_code(proto_objects, args.output_dir) + generate_init_files(paths) + + else: + name = "Settings/Advanced.proto" + imports, messages, namespace = parse_proto(f"./V3Schema/MF/V3/{name}" , args.input_dir) + + # Add imports enum and messages to an object + proto_objects = [{ + "imports": imports, + "messages": messages, + "namespace": namespace, + "filename": f"MF/V3/{name}" + }] + generate_python_code(proto_objects, args.output_dir) + if __name__ == "__main__": main() \ No newline at end of file From a419489ecd56f5b6f795495c8ab2e0599404ed3f Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 6 Sep 2024 12:39:03 -0400 Subject: [PATCH 16/86] Importing enum secial case --- scripts/interpretProto.py | 2 +- scripts/transpileProto.py | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index a21db33..6fc4db6 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -75,7 +75,7 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message if line.startswith("enum"): message_name = re.findall(r'enum (\w+)', line)[0] message_type = "enum" - imports.add("enum/Enum.py") + imports.add("enum") else: message_name: str = re.findall(r'message (\w+)', line)[0] message_type = "message" diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 7982486..ceb492d 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -19,6 +19,8 @@ def generate_import_lines(imports: List[str]) -> str: # Special consideration for google imports if "google" in module_parts: import_line = f"from {'.'.join(module_parts[:-1])} import {module_name}_pb2 as _{module_name}_pb2" + elif module_path == "enum": + import_line = f"from enum import Enum" else: # Check if the import has a namespace if len(module_parts) > 1: @@ -104,7 +106,8 @@ def parseComment(comment: str) -> str: return class_code def add_indents(code: str, indent: int) -> str: - return "\n".join([f"{' ' * indent}{line}" for line in code.split("\n")]) + # Indent the code by adding spaces if the line is not empty + return "\n".join([f"{' ' * indent}{line}" if line.strip() else line for line in code.split("\n")]) def generate_message_code(message: Dict) -> str: comment = message.comment @@ -125,7 +128,7 @@ def generate_message_code(message: Dict) -> str: if properties: # sort properties so optionals are last properties = sorted(properties, key=lambda x: x.optional) - + class_code += " def __init__(self" for prop in properties: prop_type = type_mapping.get(prop.type, prop.type) @@ -138,8 +141,9 @@ def generate_message_code(message: Dict) -> str: class_code += "):\n" for prop in properties: # Add comments with parseComment function with spaces - class_code += f"\n{add_indents(parseComment(prop.comment),2)}" - class_code += f"self.{prop.name} = {prop.name}\n" + if prop.comment: + class_code += f"\n{add_indents(parseComment(prop.comment),2)}" + class_code += add_indents(f"self.{prop.name} = {prop.name}\n",2) else: class_code += " def __init__(self):\n" class_code += " pass\n" @@ -169,13 +173,13 @@ def main(): parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() - if 1: + if 0: proto_objects = load_proto_objects(args.input_dir) paths = generate_python_code(proto_objects, args.output_dir) generate_init_files(paths) else: - name = "Settings/Advanced.proto" + name = "Task.proto" imports, messages, namespace = parse_proto(f"./V3Schema/MF/V3/{name}" , args.input_dir) # Add imports enum and messages to an object From 3221c810207c716bf1ba95a2543e4852bae3e70c Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 6 Sep 2024 12:44:47 -0400 Subject: [PATCH 17/86] Outputting unhandled lines --- scripts/interpretProto.py | 4 +++- scripts/transpileProto.py | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index 6fc4db6..a098704 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -91,7 +91,7 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message comments = [] continue - elif line == "{": + elif "proto3" in line or "{" in line: continue elif in_message > 0: @@ -118,6 +118,8 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message comments = [] else : print(f"Error parsing message: {line}") + else: + print(f"Error parsing line: {line}") return imports, messages, namespace diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index ceb492d..4836bab 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -16,7 +16,7 @@ def generate_import_lines(imports: List[str]) -> str: module_path = os.path.splitext(imp.replace('/', '.'))[0] module_parts = module_path.split('.') module_name = module_parts[-1] - # Special consideration for google imports + # Special consideration for google imports and enum if "google" in module_parts: import_line = f"from {'.'.join(module_parts[:-1])} import {module_name}_pb2 as _{module_name}_pb2" elif module_path == "enum": @@ -35,7 +35,6 @@ def generate_python_code(proto_objects: List, output_dir: str) -> set: paths = set() for obj in proto_objects: - print(obj) # Access namespace, imports, messages, enums from the dictionary obj #namespace = obj['namespace'] imports = obj['imports'] @@ -173,7 +172,7 @@ def main(): parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() - if 0: + if 1: proto_objects = load_proto_objects(args.input_dir) paths = generate_python_code(proto_objects, args.output_dir) generate_init_files(paths) From b5b3c4862291840a524856723094062d5569dcf1 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 6 Sep 2024 13:54:04 -0400 Subject: [PATCH 18/86] Handling self reference class names --- scripts/interpretProto.py | 19 +++++++++++++------ scripts/transpileProto.py | 32 +++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index a098704..087c907 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -14,12 +14,13 @@ def __init__(self, type_: str, name: str, optional: bool, comment: str) -> None: self.comment: str = comment class MessageType: - def __init__(self, type_: str, name: str, comment: str) -> None: + def __init__(self, type_: str, name: str, comment: str, parent: str) -> None: self.type: str = type_ self.name: str = name self.comment: str = comment self.properties: List[ProtoProperty] = [] self.nested_messages = [] + self.parent = parent def add_property(self, type_: str, name: str, optional: bool, comment: str) -> None: self.properties.append(ProtoProperty(type_, name, optional, comment)) @@ -27,6 +28,12 @@ def add_property(self, type_: str, name: str, optional: bool, comment: str) -> N def add_nested_message(self, message): self.nested_messages.append(message) +def get_parent_name_from_stack(stack: List[MessageType]) -> str: + if len(stack) == 0: + return "" + # Concatinate all the names in the stack with a . + return ".".join([message.name for message in stack]) + def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[MessageType]]: @@ -35,7 +42,6 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message imports: Set[str] = set() messages: List[MessageType] = [] - in_message: int = 0 comments: List[str] = [] namespace: str = "" current_message_stack = [] @@ -69,7 +75,6 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message continue elif line.startswith("message") or line.startswith("enum"): - in_message += 1 comment = "\n".join(comments) if line.startswith("enum"): @@ -80,7 +85,9 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message message_name: str = re.findall(r'message (\w+)', line)[0] message_type = "message" - new_message = MessageType(message_type, message_name, comment) + + parent = get_parent_name_from_stack(current_message_stack) + new_message = MessageType(message_type, message_name, comment, parent) if current_message_stack: current_message_stack[-1].add_nested_message(new_message) @@ -94,9 +101,9 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message elif "proto3" in line or "{" in line: continue - elif in_message > 0: + # elif current_message_stack is not empty, then we are in a message + elif len(current_message_stack) > 0: if line == "}": - in_message -= 1 current_message_stack.pop() else: if current_message_stack[-1].type == "enum": diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 4836bab..02829a3 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -3,7 +3,6 @@ from interpretProto import create_proto_objects, MessageType, parse_proto from typing import List, Dict - def load_proto_objects(input_dir: str): # Call the function from interpretProto.py to create the proto objects proto_objects = create_proto_objects(input_dir) @@ -34,6 +33,18 @@ def generate_python_code(proto_objects: List, output_dir: str) -> set: # create a unique set of paths paths = set() + # create a LUT to track the namespaces of each object + proto_objects_dict = {} + for obj in proto_objects: + for msg in obj['messages']: + + def get_nested_messages(message): + proto_objects_dict[message.name] = message.parent + for nested in message.nested_messages: + proto_objects_dict[nested.name] = nested.parent + get_nested_messages(nested) + get_nested_messages(msg) + for obj in proto_objects: # Access namespace, imports, messages, enums from the dictionary obj #namespace = obj['namespace'] @@ -59,7 +70,7 @@ def generate_python_code(proto_objects: List, output_dir: str) -> set: message_code = "" for message in messages: if message.type == "message": - message_code += generate_message_code(message) + "\n\n" + message_code += generate_message_code(message, proto_objects_dict) + "\n\n" elif message.type == "enum": message_code += generate_enum_code(message) + "\n\n" @@ -108,7 +119,7 @@ def add_indents(code: str, indent: int) -> str: # Indent the code by adding spaces if the line is not empty return "\n".join([f"{' ' * indent}{line}" if line.strip() else line for line in code.split("\n")]) -def generate_message_code(message: Dict) -> str: +def generate_message_code(message: Dict, proto_objects_dict: Dict) -> str: comment = message.comment name = message.name properties = message.properties @@ -120,7 +131,7 @@ def generate_message_code(message: Dict) -> str: # Generate code for nested messages for nested_message in nested_messages: - nested_class_code = generate_message_code(nested_message) + nested_class_code = generate_message_code(nested_message, proto_objects_dict) nested_class_code = add_indents(nested_class_code,1) class_code += f"\n{nested_class_code}\n" @@ -130,7 +141,14 @@ def generate_message_code(message: Dict) -> str: class_code += " def __init__(self" for prop in properties: - prop_type = type_mapping.get(prop.type, prop.type) + #Check to see if the type is in the proto_objects_dict + if prop.type in proto_objects_dict: + # Join proto_objects_dict[prop.type] + prop_type + prop_type = f"'{proto_objects_dict[prop.type]}.{prop.type}'" + else: + prop_type = type_mapping.get(prop.type, prop.type) + + # Extract the last value of the type if it contains dots # if '.' in prop_type: # prop_type = prop_type.split('.')[-1] @@ -172,13 +190,13 @@ def main(): parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() - if 1: + if 0: proto_objects = load_proto_objects(args.input_dir) paths = generate_python_code(proto_objects, args.output_dir) generate_init_files(paths) else: - name = "Task.proto" + name = "Descriptors/Settings/Advanced.proto" imports, messages, namespace = parse_proto(f"./V3Schema/MF/V3/{name}" , args.input_dir) # Add imports enum and messages to an object From 9a2ce39cac8f5ae905edb7227afd42e2b9729364 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 6 Sep 2024 14:32:48 -0400 Subject: [PATCH 19/86] Update Schema to fix namespaces without MF --- V3Schema | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/V3Schema b/V3Schema index 23b5629..0c76977 160000 --- a/V3Schema +++ b/V3Schema @@ -1 +1 @@ -Subproject commit 23b5629ac5d9d4b4ddb25b9445cf29f0444820e1 +Subproject commit 0c769772ff7cc55d5e9df43b6dd3243da0544733 From 912e0ad57f8fbe1d186590fc224939f4bd48ce59 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 6 Sep 2024 20:46:20 -0400 Subject: [PATCH 20/86] implementing reverse tree --- scripts/interpretProto.py | 2 +- scripts/transpileProto.py | 146 +++++++++++++++++++++++++++++++------- 2 files changed, 123 insertions(+), 25 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index 087c907..544cdda 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -21,6 +21,7 @@ def __init__(self, type_: str, name: str, comment: str, parent: str) -> None: self.properties: List[ProtoProperty] = [] self.nested_messages = [] self.parent = parent + self.path = "" def add_property(self, type_: str, name: str, optional: bool, comment: str) -> None: self.properties.append(ProtoProperty(type_, name, optional, comment)) @@ -135,7 +136,6 @@ def create_proto_objects(directory: str): all_objs = [] for proto_file in proto_files: - print(f"Parsing file: {proto_file}") imports, messages, namespace = parse_proto(proto_file, directory) # Get relative path of the file proto_file = os.path.relpath(proto_file, directory) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 02829a3..688386b 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -1,20 +1,96 @@ import os import argparse from interpretProto import create_proto_objects, MessageType, parse_proto -from typing import List, Dict +from typing import List, Dict,Tuple, Set + + +class TreeNode: + def __init__(self, name: str, parent = None, object = None): + self.name = name + self.parent = parent + self.children = {} + self.object = object + + def add_child(self, child_node): + self.children[child_node.name] = child_node + + def get_child(self, name: str): + parts = name.split('.') + return self.children.get(parts[-1], None) + + def has_child(self, name: str): + parts = name.split('.') + return parts[-1] in self.children + + def get_path(self): + path = [] + current_node = self + while current_node: + path.append(current_node.name) + current_node = current_node.parent + return '.'.join(reversed(path)) + + def get_relative_path(self, node): + path = [] + current_node = self + while current_node != node: + path.append(current_node.name) + current_node = current_node.parent + return '.'.join(reversed(path)) + + def get_first_parent_with_child(self, name: str): + # Break the name into parts + parts = name.split('.') + lastIndex = len(parts) - 1 + + current_node = self + while current_node: + if parts[-1] in current_node.children: + return current_node + current_node = current_node.parent + return None + +class Tree: + def __init__(self): + self.root = TreeNode("root") + + def add_path(self, path: str, object): + parts = path.split('.') + current_node = self.root + for part in parts: + if part not in current_node.children: + new_node = TreeNode(part, parent=current_node, object=object) + current_node.add_child(new_node) + current_node = current_node.get_child(part) + + def search(self, path: str) -> TreeNode: + parts = path.split('.') + current_node = self.root + for part in parts: + current_node = current_node.get_child(part) + if current_node is None: + return None + return current_node + def load_proto_objects(input_dir: str): # Call the function from interpretProto.py to create the proto objects proto_objects = create_proto_objects(input_dir) return proto_objects -def generate_import_lines(imports: List[str]) -> str: +def generate_import_lines(imports: List[str]) -> Tuple[str, Set[str]]: import_lines = [] + module_parts_set = set() + for imp in imports: # Split the import path into parts module_path = os.path.splitext(imp.replace('/', '.'))[0] module_parts = module_path.split('.') module_name = module_parts[-1] + + # Add module parts to the set + module_parts_set.add(module_path) + # Special consideration for google imports and enum if "google" in module_parts: import_line = f"from {'.'.join(module_parts[:-1])} import {module_name}_pb2 as _{module_name}_pb2" @@ -27,25 +103,31 @@ def generate_import_lines(imports: List[str]) -> str: else: import_line = f"import {module_path}" import_lines.append(import_line) - return "\n".join(import_lines) + return "\n".join(import_lines), module_parts_set def generate_python_code(proto_objects: List, output_dir: str) -> set: # create a unique set of paths paths = set() - - # create a LUT to track the namespaces of each object - proto_objects_dict = {} + + tree = Tree() for obj in proto_objects: + namespace = obj['namespace'] for msg in obj['messages']: def get_nested_messages(message): - proto_objects_dict[message.name] = message.parent + # concat message.name with message.parent + tree_path = f"{namespace}.{message.parent + '.' if message.parent else ''}{message.name}" + message.path = tree_path + tree.add_path(tree_path, message) for nested in message.nested_messages: - proto_objects_dict[nested.name] = nested.parent get_nested_messages(nested) get_nested_messages(msg) for obj in proto_objects: + print(f"Parsing file: {obj['filename']}") + + file_node = tree.search(obj['namespace']) + # Access namespace, imports, messages, enums from the dictionary obj #namespace = obj['namespace'] imports = obj['imports'] @@ -54,6 +136,7 @@ def get_nested_messages(message): # Get the base path of the file path = os.path.join(output_dir, os.path.dirname(file_path)) + # Get the filename without the extension filename = os.path.basename(file_path).replace('.proto', '') @@ -62,15 +145,15 @@ def get_nested_messages(message): # Add the path to a unique set paths.add(path) - # Generate imports - import_lines = generate_import_lines(imports) + import_lines, import_paths = generate_import_lines(imports) # Generate code for messages message_code = "" for message in messages: + current_node = file_node.get_child(message.name) if message.type == "message": - message_code += generate_message_code(message, proto_objects_dict) + "\n\n" + message_code += generate_message_code(message, tree, current_node, import_paths) + "\n\n" elif message.type == "enum": message_code += generate_enum_code(message) + "\n\n" @@ -119,7 +202,28 @@ def add_indents(code: str, indent: int) -> str: # Indent the code by adding spaces if the line is not empty return "\n".join([f"{' ' * indent}{line}" if line.strip() else line for line in code.split("\n")]) -def generate_message_code(message: Dict, proto_objects_dict: Dict) -> str: +def get_property_type(property, tree: Tree, node:TreeNode, import_paths: Set) -> str: + + if property.type in type_mapping: + prop_type = type_mapping.get(property.type, property.type) + elif any(import_path in property.type for import_path in import_paths): + matched_import_path = next(import_path for import_path in import_paths if import_path in property.type) + # Remove the matched import path from the property type, except for its last word + last_word = matched_import_path.split('.')[-1] + prop_type = property.type.replace(matched_import_path, last_word) + elif node.parent.has_child(property.type): + parts = property.type.split('.') + prop_type = f"'{parts[-1]}'" + elif node.has_child(property.type): + prop_type = f"'{property.type}'" + else: + parentWithChild = node.get_first_parent_with_child(property.type) + # if (parentWithChild) + # prop_type = f"'{parentWithChild.object.path}'" + print("Warning: Property Type could not be resolved", property.type) + + return prop_type +def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, import_paths: Set) -> str: comment = message.comment name = message.name properties = message.properties @@ -131,7 +235,7 @@ def generate_message_code(message: Dict, proto_objects_dict: Dict) -> str: # Generate code for nested messages for nested_message in nested_messages: - nested_class_code = generate_message_code(nested_message, proto_objects_dict) + nested_class_code = generate_message_code(nested_message, tree, current_node.get_child(nested_message.name), import_paths) nested_class_code = add_indents(nested_class_code,1) class_code += f"\n{nested_class_code}\n" @@ -141,18 +245,12 @@ def generate_message_code(message: Dict, proto_objects_dict: Dict) -> str: class_code += " def __init__(self" for prop in properties: - #Check to see if the type is in the proto_objects_dict - if prop.type in proto_objects_dict: - # Join proto_objects_dict[prop.type] + prop_type - prop_type = f"'{proto_objects_dict[prop.type]}.{prop.type}'" - else: - prop_type = type_mapping.get(prop.type, prop.type) - - # Extract the last value of the type if it contains dots - # if '.' in prop_type: - # prop_type = prop_type.split('.')[-1] + prop_type = get_property_type(prop, tree, current_node, import_paths) + + # write class init parameter class_code += f", {prop.name}: {prop_type}" + # handle optionals if prop.optional: class_code += " = None" class_code += "):\n" @@ -196,7 +294,7 @@ def main(): generate_init_files(paths) else: - name = "Descriptors/Settings/Advanced.proto" + name = "Descriptors/Calibration.proto" imports, messages, namespace = parse_proto(f"./V3Schema/MF/V3/{name}" , args.input_dir) # Add imports enum and messages to an object From 761d30c8cc3dfa29b19e92f2616f64d4f8ed4a96 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sat, 7 Sep 2024 11:56:31 -0400 Subject: [PATCH 21/86] partial search partial implementation --- scripts/transpileProto.py | 159 ++++++++++++++++++++++++++++++++++---- 1 file changed, 143 insertions(+), 16 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 688386b..47d9be4 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -26,6 +26,8 @@ def get_path(self): path = [] current_node = self while current_node: + if current_node.name == "root": + break path.append(current_node.name) current_node = current_node.parent return '.'.join(reversed(path)) @@ -34,8 +36,12 @@ def get_relative_path(self, node): path = [] current_node = self while current_node != node: + if current_node.name == "root": + break path.append(current_node.name) current_node = current_node.parent + if current_node: + path.append(current_node.name) return '.'.join(reversed(path)) def get_first_parent_with_child(self, name: str): @@ -72,6 +78,73 @@ def search(self, path: str) -> TreeNode: return None return current_node + def partial_search(self, path: str, reference_node: TreeNode) -> TreeNode: + if path == "": + raise Exception("Path cannot be empty") + + parts = path.split('.') + current_node = reference_node + + if (current_node.name == parts[0]): + current_node = current_node.parent + + # Check children + for part in parts: + current_node = current_node.get_child(part) + if current_node is None: + break + if current_node: + return current_node + + # Check parents + current_node = reference_node + while current_node: + if current_node.name == "root": + current_node = None + break + + loop_node = current_node + if current_node.has_child(parts[-1]): + loop_node = current_node.get_child(parts[-1]) + + if loop_node.name == parts[-1]: + index = len(parts) - 1 + temp_node = loop_node + while index >= 0 and temp_node: + if temp_node.name != parts[index]: + break + index -= 1 + temp_node = temp_node.parent + + if index < 0: + return loop_node + + current_node = current_node.parent + + return None + + def get_shared_parent(self, node1: TreeNode, node2: TreeNode) -> TreeNode: + path1 = [] + current_node = node1 + while current_node: + path1.append(current_node) + current_node = current_node.parent + + path2 = [] + current_node = node2 + while current_node: + path2.append(current_node) + current_node = current_node.parent + + shared_parent = None + while path1 and path2: + if path1[-1] == path2[-1]: + shared_parent = path1.pop() + path2.pop() + else: + break + return shared_parent + def load_proto_objects(input_dir: str): # Call the function from interpretProto.py to create the proto objects @@ -204,23 +277,77 @@ def add_indents(code: str, indent: int) -> str: def get_property_type(property, tree: Tree, node:TreeNode, import_paths: Set) -> str: + # Check to see if the property type can be mapped to a Python type if property.type in type_mapping: - prop_type = type_mapping.get(property.type, property.type) - elif any(import_path in property.type for import_path in import_paths): - matched_import_path = next(import_path for import_path in import_paths if import_path in property.type) - # Remove the matched import path from the property type, except for its last word - last_word = matched_import_path.split('.')[-1] - prop_type = property.type.replace(matched_import_path, last_word) - elif node.parent.has_child(property.type): + return type_mapping.get(property.type, property.type) + if property.type == "MF.V3.Settings.Scan.Processing.AdaptiveSampling.Type": + print("stop") + + matching_node = tree.partial_search(property.type, node) + if matching_node: + pt = f"'{matching_node.get_path()}'" + return pt + + for import_path in import_paths: + import_node = tree.search(import_path) + if import_node: + matching_node = tree.partial_search(property.type, import_node) + if matching_node: + pt = f"'{matching_node.get_path()}'" + return pt + + + # Check to see if the node has a child with the property type + if node.has_child(property.type): + return f"'{property.type}'" + + # Check to see if the property type can be mapped to the tree using imports + # split the property type into parts + property_type_parts = property.type.split('.') + # iterrate through the import paths + for import_path in import_paths: + # see if there is a node in the tree that matches the import path + import_node = tree.search(import_path) + last_index = len(property_type_parts) - 1 + if import_node: + if import_node.has_child(property_type_parts[last_index]): + return f"'{property.type}'" + # make sure to check the full path + while import_node and last_index >= 0: + if import_node.name != property_type_parts[last_index]: + break + last_index -= 1 + import_node = import_node.parent + if last_index == -1: + return f"'{property.type}'" + + if node.parent.has_child(property.type): parts = property.type.split('.') - prop_type = f"'{parts[-1]}'" - elif node.has_child(property.type): - prop_type = f"'{property.type}'" - else: - parentWithChild = node.get_first_parent_with_child(property.type) - # if (parentWithChild) - # prop_type = f"'{parentWithChild.object.path}'" - print("Warning: Property Type could not be resolved", property.type) + return f"'{parts[-1]}'"\ + + raise Exception("Property Type could not be resolved", property.type) + + # # Check to see if the property type is a direct match to anything the import list + # elif any(import_path in property.type for import_path in import_paths): + # matched_import_path = next(import_path for import_path in import_paths if import_path in property.type) + # # Remove the matched import path from the property type, except for its last word + # last_word = matched_import_path.split('.')[-1] + # prop_type = property.type.replace(matched_import_path, last_word) + # # Check to see if the property type part of this class + # elif node.has_child(property.type): + # prop_type = f"'{property.type}'" + # # Check to see if the property type is part of the parent class + # elif node.parent.has_child(property.type): + # parts = property.type.split('.') + # prop_type = f"'{parts[-1]}'"\ + # # Otherwise check up the tree. + # else: + # parentWithChild = node.get_first_parent_with_child(property.type) + # if parentWithChild: + # prop_type = f"'{parentWithChild.get_path()}.{property.type}'" + # else: + # raise Exception("Property Type could not be resolved", property.type) + return prop_type def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, import_paths: Set) -> str: @@ -288,7 +415,7 @@ def main(): parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() - if 0: + if 1: proto_objects = load_proto_objects(args.input_dir) paths = generate_python_code(proto_objects, args.output_dir) generate_init_files(paths) From 8ee3b141cc0d6d6e505fcc13b408f9c847ae2d99 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sat, 7 Sep 2024 15:18:56 -0400 Subject: [PATCH 22/86] working tree. Overlaps not handled --- scripts/transpileProto.py | 219 +++++++++++++------------------------- 1 file changed, 72 insertions(+), 147 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 47d9be4..02aea94 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -5,22 +5,31 @@ class TreeNode: - def __init__(self, name: str, parent = None, object = None): + def __init__(self, name: str, parent = None, filespace = None): self.name = name self.parent = parent self.children = {} - self.object = object + self.filespace = filespace def add_child(self, child_node): self.children[child_node.name] = child_node def get_child(self, name: str): parts = name.split('.') - return self.children.get(parts[-1], None) + # Check each part of the name to see if it is a child + temp = self + while temp and len(parts) > 0: + temp = temp.children.get(parts[0], None) + parts = parts[1:] + if temp: + return temp + return None def has_child(self, name: str): - parts = name.split('.') - return parts[-1] in self.children + temp = self.get_child(name) + if temp: + return True + return False def get_path(self): path = [] @@ -44,15 +53,18 @@ def get_relative_path(self, node): path.append(current_node.name) return '.'.join(reversed(path)) - def get_first_parent_with_child(self, name: str): + def get_first_parent_with_name(self, name: str): # Break the name into parts parts = name.split('.') - lastIndex = len(parts) - 1 current_node = self while current_node: - if parts[-1] in current_node.children: + if current_node.name == "root": + break + if current_node.name == parts[-1]: return current_node + if current_node.has_child(parts[-1]): + return current_node.get_child(parts[-1]) current_node = current_node.parent return None @@ -60,14 +72,15 @@ class Tree: def __init__(self): self.root = TreeNode("root") - def add_path(self, path: str, object): + def add_path(self, path: str, filespace): parts = path.split('.') current_node = self.root for part in parts: if part not in current_node.children: - new_node = TreeNode(part, parent=current_node, object=object) + new_node = TreeNode(part, parent=current_node) current_node.add_child(new_node) current_node = current_node.get_child(part) + current_node.filespace = filespace def search(self, path: str) -> TreeNode: parts = path.split('.') @@ -77,74 +90,38 @@ def search(self, path: str) -> TreeNode: if current_node is None: return None return current_node + + def get_nodes_with_filespace(self, filespace: str) -> TreeNode: + nodes = [] + def get_nodes(node): + if node.filespace == filespace: + nodes.append(node) + for child in node.children.values(): + get_nodes(child) + get_nodes(self.root) + return nodes - def partial_search(self, path: str, reference_node: TreeNode) -> TreeNode: + def get_node_with_shared_parent(self, reference_node: TreeNode, path: str) -> TreeNode: if path == "": raise Exception("Path cannot be empty") parts = path.split('.') - current_node = reference_node - if (current_node.name == parts[0]): - current_node = current_node.parent - - # Check children - for part in parts: - current_node = current_node.get_child(part) - if current_node is None: - break - if current_node: - return current_node - - # Check parents + # Go up the tree until we find the node with parts[0] current_node = reference_node while current_node: - if current_node.name == "root": - current_node = None + if current_node.name == parts[0]: break - - loop_node = current_node - if current_node.has_child(parts[-1]): - loop_node = current_node.get_child(parts[-1]) - - if loop_node.name == parts[-1]: - index = len(parts) - 1 - temp_node = loop_node - while index >= 0 and temp_node: - if temp_node.name != parts[index]: - break - index -= 1 - temp_node = temp_node.parent - - if index < 0: - return loop_node - current_node = current_node.parent + if current_node == None: + return None - return None - - def get_shared_parent(self, node1: TreeNode, node2: TreeNode) -> TreeNode: - path1 = [] - current_node = node1 - while current_node: - path1.append(current_node) - current_node = current_node.parent - - path2 = [] - current_node = node2 - while current_node: - path2.append(current_node) - current_node = current_node.parent - - shared_parent = None - while path1 and path2: - if path1[-1] == path2[-1]: - shared_parent = path1.pop() - path2.pop() - else: - break - return shared_parent - + # Now go down the tree to find the rest of the path + for part in parts[1:]: + current_node = current_node.get_child(part) + if current_node == None: + return None + return current_node def load_proto_objects(input_dir: str): # Call the function from interpretProto.py to create the proto objects @@ -191,7 +168,9 @@ def get_nested_messages(message): # concat message.name with message.parent tree_path = f"{namespace}.{message.parent + '.' if message.parent else ''}{message.name}" message.path = tree_path - tree.add_path(tree_path, message) + #convert filename to namespace + filespace = obj['filename'].replace('/', '.').replace('.proto', '') + tree.add_path(tree_path, filespace) for nested in message.nested_messages: get_nested_messages(nested) get_nested_messages(msg) @@ -280,76 +259,37 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_paths: Set) -> # Check to see if the property type can be mapped to a Python type if property.type in type_mapping: return type_mapping.get(property.type, property.type) - if property.type == "MF.V3.Settings.Scan.Processing.AdaptiveSampling.Type": - print("stop") - - matching_node = tree.partial_search(property.type, node) - if matching_node: - pt = f"'{matching_node.get_path()}'" - return pt + + # Node search down for the property type + childNode = node.get_child(property.type) + if childNode: + return f"'{property.type}'" + # Or Search for siblings + sibling_node = node.parent.get_child(property.type) + if sibling_node: + return f"'{property.type}'" + # Check imports + tree_nodes = [] for import_path in import_paths: - import_node = tree.search(import_path) - if import_node: - matching_node = tree.partial_search(property.type, import_node) - if matching_node: - pt = f"'{matching_node.get_path()}'" - return pt + tree_nodes.extend(tree.get_nodes_with_filespace(import_path)) + for tree_node in tree_nodes: + if tree_node.name == property.type: + return f"'{property.type}'" + if tree_node.has_child(property.type): + return f"'{property.type}'" + if (tree_node.parent.has_child(property.type)): + return f"'{property.type}'" - # Check to see if the node has a child with the property type - if node.has_child(property.type): + # Finally Search up the tree for the property type if all else fails + parent_node = tree.get_node_with_shared_parent(node, property.type) + if parent_node: return f"'{property.type}'" - # Check to see if the property type can be mapped to the tree using imports - # split the property type into parts - property_type_parts = property.type.split('.') - # iterrate through the import paths - for import_path in import_paths: - # see if there is a node in the tree that matches the import path - import_node = tree.search(import_path) - last_index = len(property_type_parts) - 1 - if import_node: - if import_node.has_child(property_type_parts[last_index]): - return f"'{property.type}'" - # make sure to check the full path - while import_node and last_index >= 0: - if import_node.name != property_type_parts[last_index]: - break - last_index -= 1 - import_node = import_node.parent - if last_index == -1: - return f"'{property.type}'" - - if node.parent.has_child(property.type): - parts = property.type.split('.') - return f"'{parts[-1]}'"\ - raise Exception("Property Type could not be resolved", property.type) - # # Check to see if the property type is a direct match to anything the import list - # elif any(import_path in property.type for import_path in import_paths): - # matched_import_path = next(import_path for import_path in import_paths if import_path in property.type) - # # Remove the matched import path from the property type, except for its last word - # last_word = matched_import_path.split('.')[-1] - # prop_type = property.type.replace(matched_import_path, last_word) - # # Check to see if the property type part of this class - # elif node.has_child(property.type): - # prop_type = f"'{property.type}'" - # # Check to see if the property type is part of the parent class - # elif node.parent.has_child(property.type): - # parts = property.type.split('.') - # prop_type = f"'{parts[-1]}'"\ - # # Otherwise check up the tree. - # else: - # parentWithChild = node.get_first_parent_with_child(property.type) - # if parentWithChild: - # prop_type = f"'{parentWithChild.get_path()}.{property.type}'" - # else: - # raise Exception("Property Type could not be resolved", property.type) - - return prop_type def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, import_paths: Set) -> str: comment = message.comment name = message.name @@ -415,24 +355,9 @@ def main(): parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() - if 1: - proto_objects = load_proto_objects(args.input_dir) - paths = generate_python_code(proto_objects, args.output_dir) - generate_init_files(paths) - - else: - name = "Descriptors/Calibration.proto" - imports, messages, namespace = parse_proto(f"./V3Schema/MF/V3/{name}" , args.input_dir) - - # Add imports enum and messages to an object - proto_objects = [{ - "imports": imports, - "messages": messages, - "namespace": namespace, - "filename": f"MF/V3/{name}" - }] - generate_python_code(proto_objects, args.output_dir) - + proto_objects = load_proto_objects(args.input_dir) + paths = generate_python_code(proto_objects, args.output_dir) + generate_init_files(paths) if __name__ == "__main__": main() \ No newline at end of file From 4ac4a2b28cffb505de37f1fd0ff38e9da6ccfa5a Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sat, 7 Sep 2024 22:50:52 -0400 Subject: [PATCH 23/86] Commit before cleanup --- V3Schema | 2 +- scripts/interpretProto.py | 6 +- scripts/transpileProto.py | 272 ++++++++++++++++++++++++++++++++------ 3 files changed, 235 insertions(+), 45 deletions(-) diff --git a/V3Schema b/V3Schema index 0c76977..82177f5 160000 --- a/V3Schema +++ b/V3Schema @@ -1 +1 @@ -Subproject commit 0c769772ff7cc55d5e9df43b6dd3243da0544733 +Subproject commit 82177f599ea080edf81be69b4a20b6f4daa01525 diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index 544cdda..c7faa2f 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -14,14 +14,16 @@ def __init__(self, type_: str, name: str, optional: bool, comment: str) -> None: self.comment: str = comment class MessageType: - def __init__(self, type_: str, name: str, comment: str, parent: str) -> None: + def __init__(self, type_: str, name: str, comment: str, parent: str, namespace: str) -> None: self.type: str = type_ self.name: str = name self.comment: str = comment + self.namespace = namespace self.properties: List[ProtoProperty] = [] self.nested_messages = [] self.parent = parent self.path = "" + def add_property(self, type_: str, name: str, optional: bool, comment: str) -> None: self.properties.append(ProtoProperty(type_, name, optional, comment)) @@ -88,7 +90,7 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message parent = get_parent_name_from_stack(current_message_stack) - new_message = MessageType(message_type, message_name, comment, parent) + new_message = MessageType(message_type, message_name, comment, parent, namespace) if current_message_stack: current_message_stack[-1].add_nested_message(new_message) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 02aea94..1e68d68 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -55,16 +55,14 @@ def get_relative_path(self, node): def get_first_parent_with_name(self, name: str): # Break the name into parts - parts = name.split('.') + top_name = name.split('.')[0] current_node = self while current_node: if current_node.name == "root": break - if current_node.name == parts[-1]: + if current_node.name == top_name: return current_node - if current_node.has_child(parts[-1]): - return current_node.get_child(parts[-1]) current_node = current_node.parent return None @@ -90,7 +88,7 @@ def search(self, path: str) -> TreeNode: if current_node is None: return None return current_node - + def get_nodes_with_filespace(self, filespace: str) -> TreeNode: nodes = [] def get_nodes(node): @@ -123,37 +121,67 @@ def get_node_with_shared_parent(self, reference_node: TreeNode, path: str) -> Tr return None return current_node +class ImportDescriptor: + def __init__(self, file:str): + self.file = file + self.types: List[dict[str,str]] = [] + def add_type(self, type:str, replacement:str): + # Check to see if the type is already in the list + for t in self.types: + if t["type"] == type: + return + self.types.append({"type":type, "replacement":replacement}) + def load_proto_objects(input_dir: str): # Call the function from interpretProto.py to create the proto objects proto_objects = create_proto_objects(input_dir) return proto_objects -def generate_import_lines(imports: List[str]) -> Tuple[str, Set[str]]: - import_lines = [] - module_parts_set = set() +def get_descriptor_by_name(name: str, descriptors: List[dict]) -> ImportDescriptor: + for descriptor in descriptors: + if descriptor.file == name: + return descriptor + return None + +def get_imports(imports: List[str]) -> List[ImportDescriptor]: + module_parts_list:List[ImportDescriptor] = [] for imp in imports: # Split the import path into parts module_path = os.path.splitext(imp.replace('/', '.'))[0] + # Check module_parts_list for existing module by filename + foundModule = None + for module in module_parts_list: + if module.file == module_path: + foundModule = module + break + if foundModule == None: + module_parts_list.append(ImportDescriptor(module_path)) + return module_parts_list + +def generate_import_lines(descriptors:List[ImportDescriptor]) -> str: + import_lines = [] + + for descriptor in descriptors: + # Split the import path into parts + module_path = descriptor.file module_parts = module_path.split('.') module_name = module_parts[-1] - # Add module parts to the set - module_parts_set.add(module_path) - # Special consideration for google imports and enum if "google" in module_parts: - import_line = f"from {'.'.join(module_parts[:-1])} import {module_name}_pb2 as _{module_name}_pb2" + import_lines.append(f"from {'.'.join(module_parts[:-1])} import {module_name}_pb2 as _{module_name}_pb2") elif module_path == "enum": - import_line = f"from enum import Enum" + import_lines.append(f"from enum import Enum") else: - # Check if the import has a namespace - if len(module_parts) > 1: - import_line = f"from {'.'.join(module_parts[:])} import *" - else: - import_line = f"import {module_path}" - import_lines.append(import_line) - return "\n".join(import_lines), module_parts_set + # Go through all the types in the descriptor and add them to the import line + for type in descriptor.types: + import_line = f"from {'.'.join(module_parts[:])} import {type['type']}" + if type['replacement'] != "": + import_line += f" as {type['replacement']}" + import_lines.append(import_line) + + return "\n".join(import_lines) def generate_python_code(proto_objects: List, output_dir: str) -> set: # create a unique set of paths @@ -185,7 +213,10 @@ def get_nested_messages(message): imports = obj['imports'] messages = obj['messages'] file_path = obj['filename'] + namespace = obj['namespace'] + if file_path == "MF/V3/Tasks/UpdateSettings.proto": + print("Debug") # Get the base path of the file path = os.path.join(output_dir, os.path.dirname(file_path)) @@ -197,18 +228,22 @@ def get_nested_messages(message): # Add the path to a unique set paths.add(path) - # Generate imports - import_lines, import_paths = generate_import_lines(imports) + # Generate imports paths for parsing + importDescs = get_imports(imports) # Generate code for messages message_code = "" for message in messages: current_node = file_node.get_child(message.name) if message.type == "message": - message_code += generate_message_code(message, tree, current_node, import_paths) + "\n\n" + code = generate_message_code(message, tree, current_node, importDescs) + message_code += code + "\n\n" elif message.type == "enum": message_code += generate_enum_code(message) + "\n\n" + # Generate imports another time to get the final output of imports + import_lines = generate_import_lines(importDescs) + # Combine imports, message code, and enum code combined_code = import_lines + "\n\n" + message_code @@ -254,33 +289,184 @@ def add_indents(code: str, indent: int) -> str: # Indent the code by adding spaces if the line is not empty return "\n".join([f"{' ' * indent}{line}" if line.strip() else line for line in code.split("\n")]) -def get_property_type(property, tree: Tree, node:TreeNode, import_paths: Set) -> str: +def find_remaining_elements_of_b(a_elements, b_elements): + len_a = len(a_elements) + len_b = len(b_elements) + + for i in range(len_a): + if a_elements[i:i+len_b] == b_elements[:len_a-i]: + return b_elements[len_a-i:] + return None + +def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: List[ImportDescriptor], message_namespace:str) -> str: # Check to see if the property type can be mapped to a Python type if property.type in type_mapping: return type_mapping.get(property.type, property.type) + + property_type_parts = property.type.split('.') + if property.type == "Camera" and node.filespace == "MF.V3.Settings.Scanner": + print("Debug") + + if len(property_type_parts) > 1: + # Combine message_namespace with property type + property_type_with_namespace = f"{message_namespace}.{property.type}" + + # Try getting the node directly + property_node = tree.search(property.type) + + # If the property node is not found, try getting the node with the namespace + if property_node == None: + property_node = tree.search(property_type_with_namespace) + + if property_node == None: + property_type_with_namespace = f"{message_namespace}.{property.type.split('.')[-1]}" + property_node = tree.search(property_type_with_namespace) + + if property_node == None: + property_node = node.get_first_parent_with_name(property.type) + property_node = property_node.parent.get_child(property.type) + + if (property_node.filespace == node.filespace): + return f"'{property.type}'" + + temp = property_node + while temp.parent.filespace == property_node.filespace: + temp = temp.parent + relativePath = property_node.get_relative_path(temp) + + descriptor = get_descriptor_by_name(property_node.filespace, import_descriptors) + descriptor.add_type(temp.name, "") + return f"'{relativePath}'" + else: + + sibling_nodes = tree.get_nodes_with_filespace(node.filespace) + for sibling_node in sibling_nodes: + if sibling_node.has_child(property.type): + return f"'{property.type}'" + elif sibling_node.name == property.type: + return f"'{property.type}'" + for descriptor in import_descriptors: + # Search for direct imports first + descriptor_file_node = tree.search(descriptor.file) + if descriptor_file_node: + if descriptor_file_node.name == property.type: + descriptor.add_type(property.type, "") + return f"'{property.type}'" + for descriptor in import_descriptors: + # Search for imports with the same filespace + descriptor_file_nodes = tree.get_nodes_with_filespace(descriptor.file) + for descriptor_node in descriptor_file_nodes: + if descriptor_node == None: + continue + elif descriptor_node.name == property.type: + descriptor.add_type(property.type, "") + return f"'{property.type}'" + elif descriptor_node.has_child(property.type): + descriptor.add_type(property.type, "") + return f"'{property.type}'" + + + print("Debug") + # Check imports + tree_nodes = [] + for descriptor in import_descriptors: + tree_nodes.extend(tree.get_nodes_with_filespace(descriptor.file)) + + tree_nodes.extend(tree.get_nodes_with_filespace(node.filespace)) + + if node.filespace == "MF.V3.Tasks.UpdateSettings" and property.type == "Descriptors.Settings.Scanner": + print("Debug") + + for tree_node in tree_nodes: + tree_parts = tree_node.get_path().split('.') + remaining_parts = find_remaining_elements_of_b(tree_parts, property_type_parts) + if remaining_parts == None: + continue + elif len(remaining_parts) == 0: + if (node.filespace == tree_node.filespace): + return f"'{property.type}'" + descriptor = get_descriptor_by_name(tree_node.filespace, import_descriptors) + descriptor.add_type(tree_node.name, "") + return f"'{property.type}'" + else: + child_node = tree_node.get_child(remaining_parts[0]) + if child_node: + if (node.filespace == child_node.filespace): + propName = child_node.get_relative_path(tree_node) + return propName + descriptor = get_descriptor_by_name(tree_node.filespace, import_descriptors) + descriptor.add_type(tree_node.name, "") + return f"'{tree_node.name}.{'.'.join(remaining_parts)}'" + + + print("debug") + print("debug") + + # Node search down for the property type childNode = node.get_child(property.type) if childNode: return f"'{property.type}'" - # Or Search for siblings - sibling_node = node.parent.get_child(property.type) - if sibling_node: - return f"'{property.type}'" - - # Check imports - tree_nodes = [] - for import_path in import_paths: - tree_nodes.extend(tree.get_nodes_with_filespace(import_path)) + + + #run once on imports to see if therre is a direct import for tree_node in tree_nodes: if tree_node.name == property.type: + # direct import eg. Rectangle -> MF.V3.Rectangle + replacementName = tree_node.get_path().replace('.','_') + # Get descriptor for the import by tree_node filename + descriptor = get_descriptor_by_name(tree_node.filespace, import_descriptors) + if descriptor: + descriptor.add_type(property.type, replacementName) + return f"'{replacementName}'" + + for tree_node in tree_nodes: + tree_parts = tree_node.filespace.split('.') + remaining_parts = find_remaining_elements_of_b(tree_parts, property_type_parts) + if remaining_parts == None: + continue + + descriptor = get_descriptor_by_name(tree_node.filespace, import_descriptors) + + if len(remaining_parts) == 0: + remaining_parts_name = property_type_parts[-1] + replacementName = tree_node.filespace.replace('.','_') + if descriptor: + descriptor.add_type(remaining_parts_name, replacementName) + else: + print(f"Descriptor not found for {tree_node.filespace}") + return f"'{replacementName}'" + else: + remaining_parts_name = remaining_parts[0] #'.'.join(property_type_parts[:-len(remaining_parts)]) + replacementName = "" + if descriptor: + descriptor.add_type(tree_node.name, replacementName) + else: + print(f"Descriptor not found for {tree_node.filespace}") + if (tree_node.has_child(remaining_parts[0])): + return f"'{tree_node.name}.{'.'.join(remaining_parts)}'" + else: + return f"'{'.'.join(remaining_parts)}'" + + # Or Search for siblings + sibling_node = node.parent.get_child(property.type) + if sibling_node: + # while parents share the same filespace, then keep appending the parent name + parent_node = node + path = [] + path.append(property.type) + while parent_node.parent.filespace == sibling_node.filespace: + parent_node = parent_node.parent + path.append(parent_node.name) + + if node == parent_node: return f"'{property.type}'" - if tree_node.has_child(property.type): - return f"'{property.type}'" - if (tree_node.parent.has_child(property.type)): - return f"'{property.type}'" + else: + return f"'{'.'.join(reversed(path))}'" + # Finally Search up the tree for the property type if all else fails parent_node = tree.get_node_with_shared_parent(node, property.type) @@ -290,19 +476,20 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_paths: Set) -> raise Exception("Property Type could not be resolved", property.type) -def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, import_paths: Set) -> str: +def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, import_descriptors: List[ImportDescriptor]) -> str: comment = message.comment name = message.name properties = message.properties nested_messages = message.nested_messages + message_namespace = message.namespace class_code = parseComment(comment) class_code += f"class {name}:\n" - + # Generate code for nested messages for nested_message in nested_messages: - nested_class_code = generate_message_code(nested_message, tree, current_node.get_child(nested_message.name), import_paths) + nested_class_code = generate_message_code(nested_message, tree, current_node.get_child(nested_message.name), import_descriptors) nested_class_code = add_indents(nested_class_code,1) class_code += f"\n{nested_class_code}\n" @@ -313,8 +500,8 @@ def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, impo class_code += " def __init__(self" for prop in properties: - prop_type = get_property_type(prop, tree, current_node, import_paths) - + prop_type = get_property_type(prop, tree, current_node, import_descriptors, message_namespace) + # write class init parameter class_code += f", {prop.name}: {prop_type}" # handle optionals @@ -350,6 +537,7 @@ def generate_init_files(paths: set): f.write("") def main(): + parser = argparse.ArgumentParser(description="Generate Python classes and enums from protobuf schema objects.") parser.add_argument('input_dir', type=str, nargs='?', default='./V3Schema', help='The input directory containing the protobuf schema objects.') parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') From b054b41af3dcee889efc399a8c9099cb1dff6c8d Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sat, 7 Sep 2024 23:04:32 -0400 Subject: [PATCH 24/86] Property cleanup. Needs repeating --- scripts/transpileProto.py | 129 +++++--------------------------------- 1 file changed, 16 insertions(+), 113 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 1e68d68..d6293e5 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -235,11 +235,8 @@ def get_nested_messages(message): message_code = "" for message in messages: current_node = file_node.get_child(message.name) - if message.type == "message": - code = generate_message_code(message, tree, current_node, importDescs) - message_code += code + "\n\n" - elif message.type == "enum": - message_code += generate_enum_code(message) + "\n\n" + code = generate_message_code(message, tree, current_node, importDescs) + message_code += code + "\n\n" # Generate imports another time to get the final output of imports import_lines = generate_import_lines(importDescs) @@ -306,7 +303,7 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L property_type_parts = property.type.split('.') - if property.type == "Camera" and node.filespace == "MF.V3.Settings.Scanner": + if property.type == "Orientation" and node.filespace == "MF.V3.Settings.Projector": print("Debug") if len(property_type_parts) > 1: @@ -344,7 +341,11 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L sibling_nodes = tree.get_nodes_with_filespace(node.filespace) for sibling_node in sibling_nodes: if sibling_node.has_child(property.type): - return f"'{property.type}'" + if sibling_node.parent.name == node.parent.name: + #true siblings + return f"'{property.type}'" + else: + return f"'{sibling_node.name}.{property.type}'" elif sibling_node.name == property.type: return f"'{property.type}'" for descriptor in import_descriptors: @@ -368,115 +369,14 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L return f"'{property.type}'" - print("Debug") - # Check imports - tree_nodes = [] - for descriptor in import_descriptors: - tree_nodes.extend(tree.get_nodes_with_filespace(descriptor.file)) - - tree_nodes.extend(tree.get_nodes_with_filespace(node.filespace)) - - if node.filespace == "MF.V3.Tasks.UpdateSettings" and property.type == "Descriptors.Settings.Scanner": - print("Debug") - - for tree_node in tree_nodes: - tree_parts = tree_node.get_path().split('.') - remaining_parts = find_remaining_elements_of_b(tree_parts, property_type_parts) - if remaining_parts == None: - continue - elif len(remaining_parts) == 0: - if (node.filespace == tree_node.filespace): - return f"'{property.type}'" - descriptor = get_descriptor_by_name(tree_node.filespace, import_descriptors) - descriptor.add_type(tree_node.name, "") - return f"'{property.type}'" - else: - child_node = tree_node.get_child(remaining_parts[0]) - if child_node: - if (node.filespace == child_node.filespace): - propName = child_node.get_relative_path(tree_node) - return propName - descriptor = get_descriptor_by_name(tree_node.filespace, import_descriptors) - descriptor.add_type(tree_node.name, "") - return f"'{tree_node.name}.{'.'.join(remaining_parts)}'" - - - print("debug") - print("debug") - - - # Node search down for the property type - childNode = node.get_child(property.type) - if childNode: - return f"'{property.type}'" - - - - #run once on imports to see if therre is a direct import - for tree_node in tree_nodes: - if tree_node.name == property.type: - # direct import eg. Rectangle -> MF.V3.Rectangle - replacementName = tree_node.get_path().replace('.','_') - # Get descriptor for the import by tree_node filename - descriptor = get_descriptor_by_name(tree_node.filespace, import_descriptors) - if descriptor: - descriptor.add_type(property.type, replacementName) - return f"'{replacementName}'" - - for tree_node in tree_nodes: - tree_parts = tree_node.filespace.split('.') - remaining_parts = find_remaining_elements_of_b(tree_parts, property_type_parts) - if remaining_parts == None: - continue - - descriptor = get_descriptor_by_name(tree_node.filespace, import_descriptors) - - if len(remaining_parts) == 0: - remaining_parts_name = property_type_parts[-1] - replacementName = tree_node.filespace.replace('.','_') - if descriptor: - descriptor.add_type(remaining_parts_name, replacementName) - else: - print(f"Descriptor not found for {tree_node.filespace}") - return f"'{replacementName}'" - else: - remaining_parts_name = remaining_parts[0] #'.'.join(property_type_parts[:-len(remaining_parts)]) - replacementName = "" - if descriptor: - descriptor.add_type(tree_node.name, replacementName) - else: - print(f"Descriptor not found for {tree_node.filespace}") - if (tree_node.has_child(remaining_parts[0])): - return f"'{tree_node.name}.{'.'.join(remaining_parts)}'" - else: - return f"'{'.'.join(remaining_parts)}'" - - # Or Search for siblings - sibling_node = node.parent.get_child(property.type) - if sibling_node: - # while parents share the same filespace, then keep appending the parent name - parent_node = node - path = [] - path.append(property.type) - while parent_node.parent.filespace == sibling_node.filespace: - parent_node = parent_node.parent - path.append(parent_node.name) - - if node == parent_node: - return f"'{property.type}'" - else: - return f"'{'.'.join(reversed(path))}'" - - - # Finally Search up the tree for the property type if all else fails - parent_node = tree.get_node_with_shared_parent(node, property.type) - if parent_node: - return f"'{property.type}'" - raise Exception("Property Type could not be resolved", property.type) def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, import_descriptors: List[ImportDescriptor]) -> str: + + if message.type == "enum": + return generate_enum_code(message) + "\n\n" + comment = message.comment name = message.name properties = message.properties @@ -489,7 +389,10 @@ def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, impo # Generate code for nested messages for nested_message in nested_messages: - nested_class_code = generate_message_code(nested_message, tree, current_node.get_child(nested_message.name), import_descriptors) + if nested_message.type == "enum": + nested_class_code = generate_enum_code(nested_message) + "\n\n" + else : + nested_class_code = generate_message_code(nested_message, tree, current_node.get_child(nested_message.name), import_descriptors) nested_class_code = add_indents(nested_class_code,1) class_code += f"\n{nested_class_code}\n" From 67aa45331c8bb63ea871782746fed871a5299f42 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sat, 7 Sep 2024 23:15:49 -0400 Subject: [PATCH 25/86] Catching Repeated. --- scripts/interpretProto.py | 18 ++++++++++-------- scripts/transpileProto.py | 9 ++++----- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index c7faa2f..6c42f75 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -7,10 +7,11 @@ class ProtoProperty: - def __init__(self, type_: str, name: str, optional: bool, comment: str) -> None: + def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated) -> None: self.type: str = type_ self.name: str = name self.optional: bool = optional + self.repeated: bool = repeated self.comment: str = comment class MessageType: @@ -25,8 +26,8 @@ def __init__(self, type_: str, name: str, comment: str, parent: str, namespace: self.path = "" - def add_property(self, type_: str, name: str, optional: bool, comment: str) -> None: - self.properties.append(ProtoProperty(type_, name, optional, comment)) + def add_property(self, type_: str, name: str, optional: bool, comment: str, repeated: bool) -> None: + self.properties.append(ProtoProperty(type_, name, optional, comment, repeated)) def add_nested_message(self, message): self.nested_messages.append(message) @@ -114,17 +115,18 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message if match: name, value = match[0] comment = "\n".join(comments) - current_message_stack[-1].add_property("string", name, False, comment) + current_message_stack[-1].add_property("string", name, False, comment, False) comments = [] else: print(f"Error parsing enum: {line}") else: - match = re.findall(r'(optional\s+)?([\w\.]+)\s+(\w+)\s*=\s*(\d+);', line) + match = re.findall(r'(optional\s+|repeated\s+)?([\w\.]+)\s+(\w+)\s*=\s*(\d+);', line) if match: - optional_str, type_, name, _ = match[0] - optional: bool = bool(optional_str) + keyword_str, type_, name, _ = match[0] + optional: bool = keyword_str.strip() == 'optional' + repeated: bool = keyword_str.strip() == 'repeated' comment: str = "\n".join(comments) - current_message_stack[-1].add_property(type_, name, optional, comment) + current_message_stack[-1].add_property(type_, name, optional, comment, repeated) comments = [] else : print(f"Error parsing message: {line}") diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index d6293e5..ad5606c 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -301,10 +301,9 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L if property.type in type_mapping: return type_mapping.get(property.type, property.type) - property_type_parts = property.type.split('.') - if property.type == "Orientation" and node.filespace == "MF.V3.Settings.Projector": - print("Debug") + # if property.type == "Orientation" and node.filespace == "MF.V3.Settings.Projector": + # print("Debug") if len(property_type_parts) > 1: # Combine message_namespace with property type @@ -316,11 +315,11 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L # If the property node is not found, try getting the node with the namespace if property_node == None: property_node = tree.search(property_type_with_namespace) - + # Nope? Try getting the node with the namespace and just the last part of the property type if property_node == None: property_type_with_namespace = f"{message_namespace}.{property.type.split('.')[-1]}" property_node = tree.search(property_type_with_namespace) - + # Still Nope? Try getting the node with a shared parent if property_node == None: property_node = node.get_first_parent_with_name(property.type) property_node = property_node.parent.get_child(property.type) From 50c5b7ac655ed9080a92a8609c19977a8ffb2fef Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sat, 7 Sep 2024 23:17:43 -0400 Subject: [PATCH 26/86] Writing out repeated --- scripts/transpileProto.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index ad5606c..9019b6c 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -409,6 +409,9 @@ def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, impo # handle optionals if prop.optional: class_code += " = None" + # handle repeated + if prop.repeated: + class_code += " = []" class_code += "):\n" for prop in properties: # Add comments with parseComment function with spaces From 998d2f65b6148a2db07c5537063ae4ffd7c0df16 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sun, 8 Sep 2024 14:06:19 -0400 Subject: [PATCH 27/86] Cleanup --- scripts/transpileProto.py | 38 +------------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 9019b6c..3691879 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -98,28 +98,6 @@ def get_nodes(node): get_nodes(child) get_nodes(self.root) return nodes - - def get_node_with_shared_parent(self, reference_node: TreeNode, path: str) -> TreeNode: - if path == "": - raise Exception("Path cannot be empty") - - parts = path.split('.') - - # Go up the tree until we find the node with parts[0] - current_node = reference_node - while current_node: - if current_node.name == parts[0]: - break - current_node = current_node.parent - if current_node == None: - return None - - # Now go down the tree to find the rest of the path - for part in parts[1:]: - current_node = current_node.get_child(part) - if current_node == None: - return None - return current_node class ImportDescriptor: def __init__(self, file:str): @@ -132,11 +110,6 @@ def add_type(self, type:str, replacement:str): return self.types.append({"type":type, "replacement":replacement}) -def load_proto_objects(input_dir: str): - # Call the function from interpretProto.py to create the proto objects - proto_objects = create_proto_objects(input_dir) - return proto_objects - def get_descriptor_by_name(name: str, descriptors: List[dict]) -> ImportDescriptor: for descriptor in descriptors: if descriptor.file == name: @@ -286,15 +259,6 @@ def add_indents(code: str, indent: int) -> str: # Indent the code by adding spaces if the line is not empty return "\n".join([f"{' ' * indent}{line}" if line.strip() else line for line in code.split("\n")]) -def find_remaining_elements_of_b(a_elements, b_elements): - len_a = len(a_elements) - len_b = len(b_elements) - - for i in range(len_a): - if a_elements[i:i+len_b] == b_elements[:len_a-i]: - return b_elements[len_a-i:] - return None - def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: List[ImportDescriptor], message_namespace:str) -> str: # Check to see if the property type can be mapped to a Python type @@ -448,7 +412,7 @@ def main(): parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() - proto_objects = load_proto_objects(args.input_dir) + proto_objects = create_proto_objects(args.input_dir) paths = generate_python_code(proto_objects, args.output_dir) generate_init_files(paths) From 2fe9eefba295cafccdd835963100e27cf95b04f2 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sun, 8 Sep 2024 15:51:33 -0400 Subject: [PATCH 28/86] Cleanup and working on init --- V3Schema | 2 +- maf_three/examples/projector.py | 23 ++++++---- scripts/transpileProto.py | 78 +++++++++++++++++++++++---------- 3 files changed, 71 insertions(+), 32 deletions(-) diff --git a/V3Schema b/V3Schema index 82177f5..edc6230 160000 --- a/V3Schema +++ b/V3Schema @@ -1 +1 @@ -Subproject commit 82177f599ea080edf81be69b4a20b6f4daa01525 +Subproject commit edc62306ba5ce8a18317fdc6eeabffa5f361c3f0 diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index 01a429d..8f0527d 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -8,20 +8,27 @@ # from maf_three.scanner import Scanner sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) -from MF.V3 import Three, Task -from MF.V3.Tasks import SetProjector +from maf_three.MF.V3.Tasks import SetProjector from maf_three.scanner import Scanner def main(): try: - scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) - scanner.Connect("ws://matterandform.local:8081") + # scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) + # scanner.Connect("ws://matterandform.local:8081") #### Turn ON - task = Task() - task. + set_projector_request = SetProjector.Request( + Index=1, + Type="SetProjector", + Input=SetProjector.Projector(on=True, brightness=1.0, color=[1, 1, 1]) + ) + # Index=1, + # Type="SetProjector", + # Input=SetProjector.Projector(on=True, brightness=1.0, color=[1, 1, 1]) + # ) # scanner.SendTask(Task) + # task.Projector.CopyFrom(Projector(on=True, brightness=1.0, color=[1,1,1])) # print("test2") # print(task) @@ -79,8 +86,8 @@ def main(): print('Error') finally: - if scanner.IsConnected(): - scanner.Disconnect() + # if scanner.IsConnected(): + # scanner.Disconnect() print('Finally') if __name__ == "__main__": diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 3691879..508374a 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -65,7 +65,20 @@ def get_first_parent_with_name(self, name: str): return current_node current_node = current_node.parent return None - + + def climbing_search(self, name: str): + current_node = self + #find the top level node and return it's child + while current_node: + if current_node.name == "root": + break + if current_node.name == name: + return current_node + elif current_node.has_child(name): + return current_node.get_child(name) + current_node = current_node.parent + return None + class Tree: def __init__(self): self.root = TreeNode("root") @@ -156,10 +169,7 @@ def generate_import_lines(descriptors:List[ImportDescriptor]) -> str: return "\n".join(import_lines) -def generate_python_code(proto_objects: List, output_dir: str) -> set: - # create a unique set of paths - paths = set() - +def get_tree(proto_objects: List)-> Tree: tree = Tree() for obj in proto_objects: namespace = obj['namespace'] @@ -175,6 +185,11 @@ def get_nested_messages(message): for nested in message.nested_messages: get_nested_messages(nested) get_nested_messages(msg) + return tree + +def generate_python_code(proto_objects: List, output_dir: str, tree:Tree) -> set: + # create a unique set of paths + paths = set() for obj in proto_objects: print(f"Parsing file: {obj['filename']}") @@ -188,8 +203,6 @@ def get_nested_messages(message): file_path = obj['filename'] namespace = obj['namespace'] - if file_path == "MF/V3/Tasks/UpdateSettings.proto": - print("Debug") # Get the base path of the file path = os.path.join(output_dir, os.path.dirname(file_path)) @@ -266,9 +279,9 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L return type_mapping.get(property.type, property.type) property_type_parts = property.type.split('.') - # if property.type == "Orientation" and node.filespace == "MF.V3.Settings.Projector": - # print("Debug") - + if property.type == "Settings.Export" and node.filespace == "MF.V3.Tasks.ExportMerge": + print("Debug") + if len(property_type_parts) > 1: # Combine message_namespace with property type property_type_with_namespace = f"{message_namespace}.{property.type}" @@ -279,15 +292,12 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L # If the property node is not found, try getting the node with the namespace if property_node == None: property_node = tree.search(property_type_with_namespace) - # Nope? Try getting the node with the namespace and just the last part of the property type if property_node == None: - property_type_with_namespace = f"{message_namespace}.{property.type.split('.')[-1]}" - property_node = tree.search(property_type_with_namespace) - # Still Nope? Try getting the node with a shared parent + property_node = node.climbing_search(property.type) + if property_node == None: - property_node = node.get_first_parent_with_name(property.type) - property_node = property_node.parent.get_child(property.type) - + raise Exception("Property Type could not be resolved", property.type) + if (property_node.filespace == node.filespace): return f"'{property.type}'" @@ -388,6 +398,10 @@ def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, impo return class_code +name_mapping = { + "None": "Empty", +} + def generate_enum_code(enum) -> str: comment = enum.comment name = enum.name @@ -396,25 +410,43 @@ def generate_enum_code(enum) -> str: enum_code = parseComment(comment) enum_code += f"class {name}(Enum):\n" for value in values: - enum_code += f" {value.name} = \"{value.name}\" # {value.comment}\n" + name = name_mapping.get(value.name, value.name) + enum_code += f" {name} = \"{value.name}\" # {value.comment}\n" return enum_code -def generate_init_files(paths: set): +def generate_init_files(paths: set, tree: Tree, output_dir: str): for path in paths: init_file = os.path.join(path, "__init__.py") + + # Remove output_dir from the path + relative_path = path.replace(output_dir+"/", "") + relative_path = relative_path.replace("/", ".") + node = tree.search(relative_path) + with open(init_file, 'w') as f: - f.write("") + f.write("") #guarantee a file + for child in node.children.values(): + # imports.append((child.filespace, [child.name for child in child.children.values()])) + if child.filespace: + f.write(f"from {child.filespace} import * \n") def main(): parser = argparse.ArgumentParser(description="Generate Python classes and enums from protobuf schema objects.") parser.add_argument('input_dir', type=str, nargs='?', default='./V3Schema', help='The input directory containing the protobuf schema objects.') - parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three', help='The output directory to write the generated Python classes and enums.') + parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three/', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() + # Check to see if args.input_dir and args.output_dir contain a trailing slash + if args.input_dir[-1] == '/': + args.input_dir = args.input_dir[:-1] + if args.output_dir[-1] == '/': + args.output_dir = args.output_dir[:-1] + proto_objects = create_proto_objects(args.input_dir) - paths = generate_python_code(proto_objects, args.output_dir) - generate_init_files(paths) + tree= get_tree(proto_objects) + paths = generate_python_code(proto_objects, args.output_dir, tree) + generate_init_files(paths, tree, args.output_dir) if __name__ == "__main__": main() \ No newline at end of file From 00f956b829c0dbbcb9f83c065cbe8e5df27ea810 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sun, 8 Sep 2024 20:34:49 -0400 Subject: [PATCH 29/86] Fixes imports for __init__ and repeated as Lists --- maf_three/examples/projector.py | 10 +++++----- scripts/transpileProto.py | 28 +++++++++++++++++++--------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index 8f0527d..4a7dbd9 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -19,11 +19,11 @@ def main(): # scanner.Connect("ws://matterandform.local:8081") #### Turn ON - set_projector_request = SetProjector.Request( - Index=1, - Type="SetProjector", - Input=SetProjector.Projector(on=True, brightness=1.0, color=[1, 1, 1]) - ) + # set_projector_request = SetProjector. + # Index=1, + # Type="SetProjector", + # Input=SetProjector.Projector(on=True, brightness=1.0, color=[1, 1, 1]) + # ) # Index=1, # Type="SetProjector", # Input=SetProjector.Projector(on=True, brightness=1.0, color=[1, 1, 1]) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 508374a..46124f3 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -378,14 +378,20 @@ def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, impo prop_type = get_property_type(prop, tree, current_node, import_descriptors, message_namespace) - # write class init parameter - class_code += f", {prop.name}: {prop_type}" + # handle repeated + if prop.repeated: + # Get importDescriptor for List "typing" + descriptor = get_descriptor_by_name("typing", import_descriptors) + if descriptor == None: + descriptor = ImportDescriptor("typing") + import_descriptors.append(descriptor) + descriptor.add_type("List", "") + class_code += f", {prop.name}:List[{prop_type}]" + else: + class_code += f", {prop.name}:{prop_type}" # handle optionals if prop.optional: class_code += " = None" - # handle repeated - if prop.repeated: - class_code += " = []" class_code += "):\n" for prop in properties: # Add comments with parseComment function with spaces @@ -423,12 +429,16 @@ def generate_init_files(paths: set, tree: Tree, output_dir: str): relative_path = relative_path.replace("/", ".") node = tree.search(relative_path) + imports:Set[str] = set() + + for child in node.children.values(): + if child.filespace: + imports.add(child.filespace) + with open(init_file, 'w') as f: f.write("") #guarantee a file - for child in node.children.values(): - # imports.append((child.filespace, [child.name for child in child.children.values()])) - if child.filespace: - f.write(f"from {child.filespace} import * \n") + for import_path in imports: + f.write(f"from {import_path} import * \n") def main(): From 7bff75524599c26e72c5c2960d6faf734ebbe3b1 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sun, 8 Sep 2024 20:44:57 -0400 Subject: [PATCH 30/86] Fixes conflict names --- scripts/transpileProto.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 46124f3..8bb47fa 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -307,8 +307,12 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L relativePath = property_node.get_relative_path(temp) descriptor = get_descriptor_by_name(property_node.filespace, import_descriptors) - descriptor.add_type(temp.name, "") - return f"'{relativePath}'" + # Make a unique name for the type based on the filespace and the property type + unique_name = f"{property.type}" + unique_name = unique_name.replace(".", "_") + + descriptor.add_type(temp.name, unique_name) + return f"'{unique_name}'" else: sibling_nodes = tree.get_nodes_with_filespace(node.filespace) From d8c712685b1b9b6377bcd7f69172d0f49a02aee2 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sun, 8 Sep 2024 20:44:57 -0400 Subject: [PATCH 31/86] Projector testing --- maf_three/examples/projector.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index 4a7dbd9..3926f5c 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -8,7 +8,7 @@ # from maf_three.scanner import Scanner sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) -from maf_three.MF.V3.Tasks import SetProjector +from maf_three.MF.V3.Tasks import SetProjector, Settings_Projector as Projector from maf_three.scanner import Scanner @@ -19,15 +19,11 @@ def main(): # scanner.Connect("ws://matterandform.local:8081") #### Turn ON - # set_projector_request = SetProjector. - # Index=1, - # Type="SetProjector", - # Input=SetProjector.Projector(on=True, brightness=1.0, color=[1, 1, 1]) - # ) - # Index=1, - # Type="SetProjector", - # Input=SetProjector.Projector(on=True, brightness=1.0, color=[1, 1, 1]) - # ) # scanner.SendTask(Task) + set_projector_request = SetProjector.Request( + Index=1, + Type="SetProjector", + Input=Projector(on=True, brightness=1.0, color=[1, 1, 1]) + ) # task.Projector.CopyFrom(Projector(on=True, brightness=1.0, color=[1,1,1])) # print("test2") From 4199d97192d96fc3180c1dd622d11fdb930320bd Mon Sep 17 00:00:00 2001 From: drewsipher Date: Sun, 8 Sep 2024 21:00:23 -0400 Subject: [PATCH 32/86] Requests Work. Updated Build-proto.py --- maf_three/examples/projector.py | 11 +++++++---- maf_three/scanner.py | 2 +- scripts/build-proto.py | 32 +++++++++++++++----------------- scripts/transpileProto.py | 6 ++++-- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index 3926f5c..9c66daa 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -15,8 +15,8 @@ def main(): try: - # scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) - # scanner.Connect("ws://matterandform.local:8081") + scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) + scanner.Connect("ws://matterandform.local:8081") #### Turn ON set_projector_request = SetProjector.Request( @@ -25,6 +25,9 @@ def main(): Input=Projector(on=True, brightness=1.0, color=[1, 1, 1]) ) + scanner.SendTask(set_projector_request) + # Sleep for 5 seconds + time.sleep(5) # task.Projector.CopyFrom(Projector(on=True, brightness=1.0, color=[1,1,1])) # print("test2") # print(task) @@ -82,8 +85,8 @@ def main(): print('Error') finally: - # if scanner.IsConnected(): - # scanner.Disconnect() + if scanner.IsConnected(): + scanner.Disconnect() print('Finally') if __name__ == "__main__": diff --git a/maf_three/scanner.py b/maf_three/scanner.py index 8e048f7..5837700 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -202,7 +202,7 @@ def __OnMessage(self, ws, message) -> None: self.OnMessage(obj) # Send a task to the scanner - def SendTask(self, task:Task) -> None: + def SendTask(self, task) -> None: """ Sends a task to the scanner. Tasks are general control requests for the scanner. (eg. Camera exposure, or Get Image) diff --git a/scripts/build-proto.py b/scripts/build-proto.py index dc37fc6..22aa154 100644 --- a/scripts/build-proto.py +++ b/scripts/build-proto.py @@ -21,13 +21,9 @@ def BuildProtoFile(protoFile, inputDir, outputDir): # Build the proto file status = subprocess.run([ 'python3', - '-m', - 'grpc_tools.protoc', - protoFile, - f'-I={inputDir}', - f'--python_out={outputDir}', - f'--pyi_out={outputDir}', - '--experimental_allow_proto3_optional' + 'transpileProto.py', + f'{inputDir}', + f'{outputDir}' ], capture_output=True) return status @@ -52,19 +48,21 @@ def BuildProtoFile(protoFile, inputDir, outputDir): status = subprocess.run([ 'python3', - '-m', - 'grpc_tools.protoc', - *files, - f'-I={protoInputPath}', - f'--python_out={protoOutputPath}', - f'--pyi_out={protoOutputPath}', - '--experimental_allow_proto3_optional' + f'{scriptPath}/transpileProto.py', + f'{protoInputPath}', + f'{protoOutputPath}' ], capture_output=True) # Print results -print("*****************") -print(GREEN + 'Complete ' + str(status.returncode) + ENDC) -print("*****************") +if (status.returncode != 0): + print("*****************") + print(RED + 'Error ' + str(status.returncode) + ENDC) + print(status.stderr) + print("*****************") +else: + print("*****************") + print(GREEN + 'Complete ' + str(status.returncode) + ENDC) + print("*****************") # Let the caller know if everything was built if fileError > 0: diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 8bb47fa..1ab477c 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -279,8 +279,8 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L return type_mapping.get(property.type, property.type) property_type_parts = property.type.split('.') - if property.type == "Settings.Export" and node.filespace == "MF.V3.Tasks.ExportMerge": - print("Debug") + # if property.type == "Settings.Export" and node.filespace == "MF.V3.Tasks.ExportMerge": + # print("Debug") if len(property_type_parts) > 1: # Combine message_namespace with property type @@ -462,5 +462,7 @@ def main(): paths = generate_python_code(proto_objects, args.output_dir, tree) generate_init_files(paths, tree, args.output_dir) + exit(0) + if __name__ == "__main__": main() \ No newline at end of file From facc8fe4371df2261867476c571b975bf0345bb9 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Mon, 9 Sep 2024 19:56:59 -0400 Subject: [PATCH 33/86] Handling Task messages with indicies --- maf_three/examples/projector.py | 14 ++-- maf_three/scanner.py | 142 ++++++++++++++++++++++++++------ 2 files changed, 122 insertions(+), 34 deletions(-) diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index 9c66daa..308ec34 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -8,24 +8,20 @@ # from maf_three.scanner import Scanner sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) -from maf_three.MF.V3.Tasks import SetProjector, Settings_Projector as Projector +from MF.V3.Tasks import SetProjector, Settings_Projector as Projector +from MF.V3.Task import Task from maf_three.scanner import Scanner + def main(): try: scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) scanner.Connect("ws://matterandform.local:8081") - #### Turn ON - set_projector_request = SetProjector.Request( - Index=1, - Type="SetProjector", - Input=Projector(on=True, brightness=1.0, color=[1, 1, 1]) - ) - - scanner.SendTask(set_projector_request) + + scanner.SetProjector(on=True, brightness=1.0, color=[1,1,1]) # Sleep for 5 seconds time.sleep(5) # task.Projector.CopyFrom(Projector(on=True, brightness=1.0, color=[1,1,1])) diff --git a/maf_three/scanner.py b/maf_three/scanner.py index 5837700..d43f217 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -4,14 +4,15 @@ # @date 2024-04-22 # @copyright © 2024 Matter and Form. All rights reserved. -from typing import Any, Callable, Optional +from typing import Any, Callable, Optional, List import websocket import json import threading import time -from MF.V3 import Task +from MF.V3 import Task, TaskState +from MF.V3.Tasks.SetProjector import SetProjector, Settings_Projector from maf_three import __version__ from maf_three.serialization import TO_JSON @@ -30,6 +31,9 @@ class Scanner: __bufferDescriptor = None __error = None + __taskIndex:int = 0 + __tasks:List[Task] = [] + def __init__(self, OnTask: Optional[Callable[[Task], None]], @@ -49,7 +53,8 @@ def __init__(self, self.OnTask = OnTask self.OnMessage = OnMessage self.OnBuffer = OnBuffer - + + self.__task_return_event = threading.Event() def Connect(self, URI:str, timeoutSec=5) -> bool: """ @@ -189,9 +194,22 @@ def __OnMessage(self, ws, message) -> None: # Create the task from the message task = Task(**obj['Task']) + # Find the original task for reference + inputTask = self.__FindTaskWithIndex(task.Index) + assert inputTask + # If assigned => Call the handler if self.OnTask: self.OnTask(task) + + # If waiting for a response, set the response and notify + if (task.State == TaskState.Completed.value): + if task.Output: + inputTask.Output = task.Output + self.__task_return_event.set() + elif (task.State == TaskState.Failed.value): + inputTask.Error = task.Error + self.__task_return_event # Buffer elif 'Buffer' in obj: @@ -201,8 +219,7 @@ def __OnMessage(self, ws, message) -> None: if self.OnMessage: self.OnMessage(obj) - # Send a task to the scanner - def SendTask(self, task) -> None: + def SendTask(self, task, buffer:bytes = None) -> Any: """ Sends a task to the scanner. Tasks are general control requests for the scanner. (eg. Camera exposure, or Get Image) @@ -211,14 +228,42 @@ def SendTask(self, task) -> None: Args: * task (Task): The task to send. + * buffer (bytes): The buffer data to send, default is None. + + Returns: + Any: The task object that was sent. Raises: AssertionError: If the connection is not established. """ assert self.__isConnected + + # Send the task + + self.__task_return_event.clear() + + # Append the task + self.__tasks.append(task) + + if buffer == None: + task = self.__SendTask(task) + else: + task = self.__SendTaskWithBuffer(task, buffer) + + if task.Output: + # Wait for response + self.__task_return_event.wait() + + self.__tasks.remove(task) + + return task + + # Send a task to the scanner + def __SendTask(self, task) -> Any: + assert self.__isConnected # Serialize the task - message = TO_JSON(task) + message = TO_JSON(task.Input) # Build and send the message message = '{"Task":' + message + '}' @@ -228,28 +273,11 @@ def SendTask(self, task) -> None: return task # Send a task with its buffer to the scanner - def SendTaskWithBuffer(self, task:Task, buffer:bytes) -> Task: - """ - Sends a task along with its associated buffer to the scanner. - This call is used to send data to the scanner, like an image to be projected by the projector. - An appropriate task must be sent with the buffer, or the buffer will be ignored. - - The task is serialized, and sent to the scanner, followed by the buffer. - - Args: - * task (Task): The task to send. - * buffer (bytes): The buffer data to send. - - Returns: - Task: The task object that was sent. - - Raises: - AssertionError: If the connection is not established. - """ + def __SendTaskWithBuffer(self, task:Task, buffer:bytes) -> Any: assert self.__isConnected # Send the task - task = self.SendTask(task) + task = self.__SendTask(task.Input) # Build the buffer descriptor bufferSize = len(buffer) @@ -276,4 +304,68 @@ def SendTaskWithBuffer(self, task:Task, buffer:bytes) -> Task: self.websocket.send(buffer[sentSize:bufferSize], websocket.ABNF.OPCODE_BINARY) return task + + def __FindTaskWithIndex(self, index:int) -> Task: + # Find the task in the list + for i, t in enumerate(self.__tasks): + if t.Index == index: + return t + break + return None + + def SetProjector(self, on:bool, brightness:float, color:List[float]) -> Task: + + """ + Sets the projector settings. + + Args: + * on (bool): True to turn the projector on, False to turn it off. + * brightness (float): The brightness of the projector, between 0.0 and 1.0. + * color ([float]): The RGB color of the projector, as a list of three floats between 0.0 and 1.0. + + Returns: + Task: The task object that was sent. + """ + set_projector_request = SetProjector.Request( + Index=self.__taskIndex, + Type="SetProjector", + Input=Settings_Projector(on=on, brightness=brightness, color=color) + ) + set_projector_response = SetProjector.Response( + Index=self.__taskIndex, + Type="SetProjector" + ) + + task = Task(Index=self.__taskIndex, Type="SetProjector", Input=set_projector_request, Output=set_projector_response) + + self.__taskIndex += 1 + + print(self.SendTask(task)) + + return + +# Main function to run the code +if __name__ == "__main__": + def on_task(task): + print(f"Task received: {task}") + + def on_message(message): + print(f"Message received: {message}") + + def on_buffer(buffer, data): + print(f"Buffer received: {data}") + + scanner = Scanner(OnTask=on_task, OnMessage=on_message, OnBuffer=on_buffer) + scanner.Connect("ws://matterandform.local:8081") + + # Set the projector settings for debugging + scanner.SetProjector(on=True, brightness=1.0, color=[1, 1, 1]) + time.sleep(1) + scanner.SetProjector(on=False, brightness=1.0, color=[1, 1, 1]) + time.sleep(1) + scanner.SetProjector(on=True, brightness=0.0, color=[1, 1, 1]) + time.sleep(1) + scanner.SetProjector(on=True, brightness=1.0, color=[1, 0, 0]) + time.sleep(1) + scanner.Disconnect() \ No newline at end of file From 124c61e9cac67b53ab83528ba7117baf518cde05 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 11 Sep 2024 10:13:46 -0400 Subject: [PATCH 34/86] Working on scanner helper automated class --- maf_three/scanner.py | 96 +++++++++++++--------------------- maf_three/scanner_functions.py | 31 +++++++++++ scripts/interpretProto.py | 20 +++++++ scripts/transpileProto.py | 46 +++++++++++++++- 4 files changed, 132 insertions(+), 61 deletions(-) create mode 100644 maf_three/scanner_functions.py diff --git a/maf_three/scanner.py b/maf_three/scanner.py index d43f217..ec00290 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -12,12 +12,12 @@ import time from MF.V3 import Task, TaskState -from MF.V3.Tasks.SetProjector import SetProjector, Settings_Projector from maf_three import __version__ from maf_three.serialization import TO_JSON from maf_three.buffer import Buffer +from scanner_functions import set_projector class Scanner: """ @@ -36,9 +36,9 @@ class Scanner: def __init__(self, - OnTask: Optional[Callable[[Task], None]], - OnMessage: Optional[Callable[[str], None]], - OnBuffer: Optional[Callable[[Any, bytes], None]], + OnTask: Optional[Callable[[Task], None]] = None, + OnMessage: Optional[Callable[[str], None]] = None, + OnBuffer: Optional[Callable[[Any, bytes], None]] = None, ): """ Initializes the Scanner object. @@ -56,6 +56,13 @@ def __init__(self, self.__task_return_event = threading.Event() + # Bind functions + self.bind_functions() + + def bind_functions(self): + # SetProjector + self.set_projector = lambda on, brightness, color: set_projector(self, on, brightness, color) + def Connect(self, URI:str, timeoutSec=5) -> bool: """ Attempts to connect to the scanner using the specified URI and timeout. @@ -196,12 +203,14 @@ def __OnMessage(self, ws, message) -> None: # Find the original task for reference inputTask = self.__FindTaskWithIndex(task.Index) - assert inputTask + if inputTask == None: + raise Exception('Task not found') # If assigned => Call the handler if self.OnTask: self.OnTask(task) + # If waiting for a response, set the response and notify if (task.State == TaskState.Completed.value): if task.Output: @@ -238,17 +247,21 @@ def SendTask(self, task, buffer:bytes = None) -> Any: """ assert self.__isConnected + # Update the index + task.Index = self.__taskIndex + task.Input.Index = self.__taskIndex + self.__taskIndex += 1 + # Send the task - self.__task_return_event.clear() # Append the task self.__tasks.append(task) if buffer == None: - task = self.__SendTask(task) + self.__SendTask(task) else: - task = self.__SendTaskWithBuffer(task, buffer) + self.__SendTaskWithBuffer(task, buffer) if task.Output: # Wait for response @@ -259,25 +272,24 @@ def SendTask(self, task, buffer:bytes = None) -> Any: return task # Send a task to the scanner - def __SendTask(self, task) -> Any: + def __SendTask(self, task): assert self.__isConnected - + # Serialize the task message = TO_JSON(task.Input) # Build and send the message message = '{"Task":' + message + '}' + print('Message: ', message) #print('Message: ', message) self.websocket.send(message) - return task - # Send a task with its buffer to the scanner - def __SendTaskWithBuffer(self, task:Task, buffer:bytes) -> Any: + def __SendTaskWithBuffer(self, task:Task, buffer:bytes): assert self.__isConnected # Send the task - task = self.__SendTask(task.Input) + self.__SendTask(task.Input) # Build the buffer descriptor bufferSize = len(buffer) @@ -302,8 +314,6 @@ def __SendTaskWithBuffer(self, task:Task, buffer:bytes) -> Any: # Send the remaining data. if sentSize < bufferSize: self.websocket.send(buffer[sentSize:bufferSize], websocket.ABNF.OPCODE_BINARY) - - return task def __FindTaskWithIndex(self, index:int) -> Task: # Find the task in the list @@ -312,60 +322,26 @@ def __FindTaskWithIndex(self, index:int) -> Task: return t break return None - - def SetProjector(self, on:bool, brightness:float, color:List[float]) -> Task: - - """ - Sets the projector settings. - - Args: - * on (bool): True to turn the projector on, False to turn it off. - * brightness (float): The brightness of the projector, between 0.0 and 1.0. - * color ([float]): The RGB color of the projector, as a list of three floats between 0.0 and 1.0. - - Returns: - Task: The task object that was sent. - """ - set_projector_request = SetProjector.Request( - Index=self.__taskIndex, - Type="SetProjector", - Input=Settings_Projector(on=on, brightness=brightness, color=color) - ) - set_projector_response = SetProjector.Response( - Index=self.__taskIndex, - Type="SetProjector" - ) - - task = Task(Index=self.__taskIndex, Type="SetProjector", Input=set_projector_request, Output=set_projector_response) - self.__taskIndex += 1 - - print(self.SendTask(task)) - - return # Main function to run the code if __name__ == "__main__": - def on_task(task): - print(f"Task received: {task}") + # def on_task(task): + # print(f"Task received: {task}") - def on_message(message): - print(f"Message received: {message}") + # def on_message(message): + # print(f"Message received: {message}") - def on_buffer(buffer, data): - print(f"Buffer received: {data}") + # def on_buffer(buffer, data): + # print(f"Buffer received: {data}") - scanner = Scanner(OnTask=on_task, OnMessage=on_message, OnBuffer=on_buffer) + scanner = Scanner()#OnTask=on_task, OnMessage=on_message, OnBuffer=on_buffer) scanner.Connect("ws://matterandform.local:8081") # Set the projector settings for debugging - scanner.SetProjector(on=True, brightness=1.0, color=[1, 1, 1]) - time.sleep(1) - scanner.SetProjector(on=False, brightness=1.0, color=[1, 1, 1]) + scanner.set_projector(on=True, brightness=1.0, color=[1, 1, 1]) time.sleep(1) - scanner.SetProjector(on=True, brightness=0.0, color=[1, 1, 1]) + scanner.set_projector(on=False, brightness=1.0, color=[1, 1, 1]) time.sleep(1) - scanner.SetProjector(on=True, brightness=1.0, color=[1, 0, 0]) - time.sleep(1) - + scanner.Disconnect() \ No newline at end of file diff --git a/maf_three/scanner_functions.py b/maf_three/scanner_functions.py new file mode 100644 index 0000000..41e1c4d --- /dev/null +++ b/maf_three/scanner_functions.py @@ -0,0 +1,31 @@ +from MF.V3.Tasks.SetProjector import SetProjector, Projector +from MF.V3 import Task +from typing import List + +def set_projector(scanner, on: bool, brightness: float, color: list) -> Task: + """ + Sets the projector settings. + + Args: + * on (bool): True to turn the projector on, False to turn it off. + * brightness (float): The brightness of the projector, between 0.0 and 1.0. + * color ([float]): The RGB color of the projector, as a list of three floats between 0.0 and 1.0. + + Returns: + Task: The task object that was sent. + """ + set_projector_request = SetProjector.Request( + Index=0, + Type="SetProjector", + Input=Projector(on=on, brightness=brightness, color=color) + ) + set_projector_response = SetProjector.Response( + Index=0, + Type="SetProjector" + ) + + task = Task(Index=0, Type="SetProjector", Input=set_projector_request, Output=set_projector_response) + + scanner.SendTask(task) + + return task \ No newline at end of file diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index 6c42f75..4809620 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -32,6 +32,23 @@ def add_property(self, type_: str, name: str, optional: bool, comment: str, repe def add_nested_message(self, message): self.nested_messages.append(message) +class ProcedureType: + def __init__(self, name: str, comment: str, request: str, response: str) -> None: + self.name: str = name + self.comment: str = comment + self.request: str = request + self.response: str = response + +class ServiceType: + def __init__(self, name: str, comment: str, namespace: str) -> None: + self.name: str = name + self.comment: str = comment + self.namespace = namespace + self.procedures: List[ProcedureType] = [] + + def add_procedure(self, name: str, comment: str, request: str, response: str) -> None: + self.procedures.append(ProtoProperty(name, comment, request, response)) + def get_parent_name_from_stack(stack: List[MessageType]) -> str: if len(stack) == 0: return "" @@ -102,6 +119,9 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message comments = [] continue + elif "service" in line: + comment = "\n".join(comments) + elif "proto3" in line or "{" in line: continue diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 1ab477c..0b9e300 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -443,7 +443,50 @@ def generate_init_files(paths: set, tree: Tree, output_dir: str): f.write("") #guarantee a file for import_path in imports: f.write(f"from {import_path} import * \n") - + +def parse_service_file(file_path: str) -> List[dict]: + service_data = [] + with open(file_path, 'r') as f: + lines = f.readlines() + i = 0 + while i < len(lines): + line = lines[i].strip() + if line.startswith("service"): + service_name = line.split(" ")[1].strip("{") + i += 1 + while i < len(lines): + line = lines[i].strip() + if line.startswith("//"): + comment = line.lstrip("//").strip() + elif line.startswith("rpc"): + rpc_name = line.split(" ")[1].split("(")[0] + request_type = line.split("(")[1].split(")")[0].strip() + response_type = line.split("returns (")[1].split(")")[0].strip() + service_data.append({ + "comment": comment, + "name": rpc_name, + "request": request_type, + "response": response_type + }) + elif line == "}": + break + i += 1 + i += 1 + return service_data + +def generate_function_file(input_dir:str, output_dir: str, tree: Tree): + function_file = os.path.join(output_dir, "scanner_helper.py") + # Check to see if the file exists, if it does, delete it + if os.path.exists(function_file): + os.remove(function_file) + + service_file = os.path.join(input_dir, "MF/V3/Three.proto") + service_data = parse_service_file(service_file) + print(service_data) + # with open(function_file, 'w') as f: + + + def main(): parser = argparse.ArgumentParser(description="Generate Python classes and enums from protobuf schema objects.") @@ -461,6 +504,7 @@ def main(): tree= get_tree(proto_objects) paths = generate_python_code(proto_objects, args.output_dir, tree) generate_init_files(paths, tree, args.output_dir) + generate_function_file(args.input_dir, args.output_dir, tree) exit(0) From 83e73e9ba749f08dcfe51cc8093764f3adc698d9 Mon Sep 17 00:00:00 2001 From: Drew Shark Date: Wed, 11 Sep 2024 10:55:23 -0400 Subject: [PATCH 35/86] Parsing Service to Objects --- scripts/interpretProto.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index 4809620..1d0ee58 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -47,7 +47,7 @@ def __init__(self, name: str, comment: str, namespace: str) -> None: self.procedures: List[ProcedureType] = [] def add_procedure(self, name: str, comment: str, request: str, response: str) -> None: - self.procedures.append(ProtoProperty(name, comment, request, response)) + self.procedures.append(ProcedureType(name, comment, request, response)) def get_parent_name_from_stack(stack: List[MessageType]) -> str: if len(stack) == 0: @@ -66,6 +66,8 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message comments: List[str] = [] namespace: str = "" current_message_stack = [] + services :List[ServiceType] = [] + service_object = None for line in lines: line = line.strip() @@ -121,10 +123,22 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message continue elif "service" in line: comment = "\n".join(comments) + comments = [] + name = re.findall(r'service (\w+)', line)[0] + service_object = ServiceType(name, comment, namespace) elif "proto3" in line or "{" in line: continue - + elif "rpc" in line: + comment = "\n".join(comments) + comments = [] + name = re.findall(r'rpc (\w+)', line)[0] + request = re.findall(r'rpc\s+\w+\((\w+\.\w+)\)', line) + response = re.findall(r'rpc\s+\w+\(\w+\.\w+\)\s+returns\s+\((\w+\.\w+)\)', line) + service_object.add_procedure(name, comment, request, response) + elif "}" in line and service_object: + services.append(service_object) + service_object = None # elif current_message_stack is not empty, then we are in a message elif len(current_message_stack) > 0: if line == "}": @@ -153,14 +167,14 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message else: print(f"Error parsing line: {line}") - return imports, messages, namespace + return imports, messages, services, namespace def create_proto_objects(directory: str): proto_files = glob.glob(os.path.join(directory, '**', '*.proto'), recursive=True) all_objs = [] for proto_file in proto_files: - imports, messages, namespace = parse_proto(proto_file, directory) + imports, messages, services, namespace = parse_proto(proto_file, directory) # Get relative path of the file proto_file = os.path.relpath(proto_file, directory) @@ -169,7 +183,8 @@ def create_proto_objects(directory: str): "imports": imports, "messages": messages, "namespace": namespace, - "filename": proto_file + "filename": proto_file, + "services": services }) return all_objs From ca9974d1bf295534e956bffc1f80595b521363fb Mon Sep 17 00:00:00 2001 From: Drew Shark Date: Wed, 11 Sep 2024 15:20:05 -0400 Subject: [PATCH 36/86] adds service to tree --- scripts/transpileProto.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 0b9e300..7940306 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -177,14 +177,18 @@ def get_tree(proto_objects: List)-> Tree: def get_nested_messages(message): # concat message.name with message.parent - tree_path = f"{namespace}.{message.parent + '.' if message.parent else ''}{message.name}" - message.path = tree_path + message.path = f"{namespace}.{message.parent + '.' if message.parent else ''}{message.name}" #convert filename to namespace filespace = obj['filename'].replace('/', '.').replace('.proto', '') - tree.add_path(tree_path, filespace) + tree.add_path(message.path, filespace) for nested in message.nested_messages: get_nested_messages(nested) get_nested_messages(msg) + for service in obj['services']: + # I think services are top level definitions, so no parent needed + service_path = f"{namespace}.{service.name}" + filespace = obj['filename'].replace('/', '.').replace('.proto', '') + tree.add_path(service_path, filespace) return tree def generate_python_code(proto_objects: List, output_dir: str, tree:Tree) -> set: @@ -202,6 +206,7 @@ def generate_python_code(proto_objects: List, output_dir: str, tree:Tree) -> set messages = obj['messages'] file_path = obj['filename'] namespace = obj['namespace'] + services = obj['services'] # Get the base path of the file path = os.path.join(output_dir, os.path.dirname(file_path)) @@ -217,6 +222,11 @@ def generate_python_code(proto_objects: List, output_dir: str, tree:Tree) -> set # Generate imports paths for parsing importDescs = get_imports(imports) + # Generate code for Services + service_code = "" + for service in services: + print(service) + # Generate code for messages message_code = "" for message in messages: From 4c0d41b4204813348e7e86b3b9989401e9252f26 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 19 Sep 2024 18:45:29 -0400 Subject: [PATCH 37/86] Moving to Tree only --- scripts/interpretProto.py | 5 +- scripts/transpileProto.py | 262 ++++++++++++++++++++++---------------- 2 files changed, 157 insertions(+), 110 deletions(-) diff --git a/scripts/interpretProto.py b/scripts/interpretProto.py index 1d0ee58..5a5c0c0 100644 --- a/scripts/interpretProto.py +++ b/scripts/interpretProto.py @@ -133,8 +133,9 @@ def parse_proto(proto_file: str, base_dir: str) -> Tuple[List[str], List[Message comment = "\n".join(comments) comments = [] name = re.findall(r'rpc (\w+)', line)[0] - request = re.findall(r'rpc\s+\w+\((\w+\.\w+)\)', line) - response = re.findall(r'rpc\s+\w+\(\w+\.\w+\)\s+returns\s+\((\w+\.\w+)\)', line) + rr = re.findall(r'\(\s*([^)]+?)\s*\)', line) + request = rr[0] + response = rr[1] service_object.add_procedure(name, comment, request, response) elif "}" in line and service_object: services.append(service_object) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 7940306..6dedddf 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -4,15 +4,31 @@ from typing import List, Dict,Tuple, Set +class TreeProperty: + def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated) -> None: + self.type: str = type_ + self.name: str = name + self.optional: bool = optional + self.repeated: bool = repeated + self.comment: str = comment + class TreeNode: def __init__(self, name: str, parent = None, filespace = None): self.name = name self.parent = parent self.children = {} + self.properties = [] + self.imports = [] self.filespace = filespace def add_child(self, child_node): self.children[child_node.name] = child_node + + def add_property(self, type_: str, name: str, optional: bool, comment: str, repeated: bool) -> None: + self.properties.append(TreeProperty(type_, name, optional, comment, repeated)) + + def add_import(self, import_path: str): + self.imports.append(ImportDescriptor(import_path)) def get_child(self, name: str): parts = name.split('.') @@ -83,7 +99,7 @@ class Tree: def __init__(self): self.root = TreeNode("root") - def add_path(self, path: str, filespace): + def add_path(self, path: str, filespace) -> TreeNode: parts = path.split('.') current_node = self.root for part in parts: @@ -92,6 +108,7 @@ def add_path(self, path: str, filespace): current_node.add_child(new_node) current_node = current_node.get_child(part) current_node.filespace = filespace + return current_node def search(self, path: str) -> TreeNode: parts = path.split('.') @@ -129,6 +146,73 @@ def get_descriptor_by_name(name: str, descriptors: List[dict]) -> ImportDescript return descriptor return None +def get_descriptor_by_partial_name(name, import_descriptors, tree) -> ImportDescriptor: + for descriptor in import_descriptors: + descriptor_file_nodes = tree.get_nodes_with_filespace(descriptor.file) + for descriptor_node in descriptor_file_nodes: + if descriptor_node.name == name: + return descriptor + return None + +def generate_python_code(proto_objects: List, output_dir: str, tree:Tree) -> set: + # create a unique set of paths + paths = set() + + for obj in proto_objects: + print(f"Parsing file: {obj['filename']}") + + file_node = tree.search(obj['namespace']) + + # Access namespace, imports, messages, enums from the dictionary obj + #namespace = obj['namespace'] + imports = obj['imports'] + messages = obj['messages'] + file_path = obj['filename'] + namespace = obj['namespace'] + services = obj['services'] + + # Get the base path of the file + path = os.path.join(output_dir, os.path.dirname(file_path)) + + # Get the filename without the extension + filename = os.path.basename(file_path).replace('.proto', '') + + # Create the directory if it doesn't exist + os.makedirs(path, exist_ok=True) + # Add the path to a unique set + paths.add(path) + + # Generate imports paths for parsing + importDescs = get_imports(imports) + + # Generate code for Services + service_code = "" + for service in services: + code = generate_service_code(service, tree, file_node, importDescs) + service_code += code + "\n\n" + + + # Generate code for messages + message_code = "" + for message in messages: + current_node = file_node.get_child(message.name) + code = generate_message_code(message, tree, current_node, importDescs) + message_code += code + "\n\n" + + # Generate imports another time to get the final output of imports + import_lines = generate_import_lines(importDescs) + + # Combine imports, message code, and enum code + combined_code = import_lines + "\n\n" + message_code + "\n\n" + service_code + + # Write the combined code to a file with the name from the file_path + filename = os.path.join(path, f"{filename}.py") + with open(filename, 'w') as f: + f.write(combined_code) + + return paths + + def get_imports(imports: List[str]) -> List[ImportDescriptor]: module_parts_list:List[ImportDescriptor] = [] @@ -171,81 +255,49 @@ def generate_import_lines(descriptors:List[ImportDescriptor]) -> str: def get_tree(proto_objects: List)-> Tree: tree = Tree() + + # We need to go through the proto_objects twice. + # First to build the base tree + # Then to to add the properties to the objects in the tree (self referencing) for obj in proto_objects: namespace = obj['namespace'] + imports = obj['imports'] + importDescs = get_imports(imports) + filespace = obj['filename'].replace('/', '.').replace('.proto', '') + + if obj['filename'] == "MF/V3/Descriptors/ProjectActions.proto": + print("Debug") for msg in obj['messages']: - def get_nested_messages(message): + def get_nested_messages(message, nested_name_space): # concat message.name with message.parent - message.path = f"{namespace}.{message.parent + '.' if message.parent else ''}{message.name}" - #convert filename to namespace - filespace = obj['filename'].replace('/', '.').replace('.proto', '') - tree.add_path(message.path, filespace) + nested_name_space = f"{nested_name_space}.{message.name}" + #convert filename to namespace + node = tree.add_path(nested_name_space, filespace) + node.imports = importDescs for nested in message.nested_messages: - get_nested_messages(nested) - get_nested_messages(msg) + get_nested_messages(nested, nested_name_space) + get_nested_messages(msg, namespace) for service in obj['services']: # I think services are top level definitions, so no parent needed service_path = f"{namespace}.{service.name}" - filespace = obj['filename'].replace('/', '.').replace('.proto', '') - tree.add_path(service_path, filespace) - return tree - -def generate_python_code(proto_objects: List, output_dir: str, tree:Tree) -> set: - # create a unique set of paths - paths = set() - - for obj in proto_objects: - print(f"Parsing file: {obj['filename']}") + node = tree.add_path(service_path, filespace) + node.imports = importDescs - file_node = tree.search(obj['namespace']) - - # Access namespace, imports, messages, enums from the dictionary obj - #namespace = obj['namespace'] - imports = obj['imports'] - messages = obj['messages'] - file_path = obj['filename'] + for obj in proto_objects: namespace = obj['namespace'] - services = obj['services'] - - # Get the base path of the file - path = os.path.join(output_dir, os.path.dirname(file_path)) - - # Get the filename without the extension - filename = os.path.basename(file_path).replace('.proto', '') - - # Create the directory if it doesn't exist - os.makedirs(path, exist_ok=True) - # Add the path to a unique set - paths.add(path) - - # Generate imports paths for parsing - importDescs = get_imports(imports) - - # Generate code for Services - service_code = "" - for service in services: - print(service) - - # Generate code for messages - message_code = "" - for message in messages: - current_node = file_node.get_child(message.name) - code = generate_message_code(message, tree, current_node, importDescs) - message_code += code + "\n\n" - - # Generate imports another time to get the final output of imports - import_lines = generate_import_lines(importDescs) - - # Combine imports, message code, and enum code - combined_code = import_lines + "\n\n" + message_code + for msg in obj['messages']: + def parse_message_props(message): + message.path = f"{namespace}.{message.parent + '.' if message.parent else ''}{message.name}" + node = tree.search(message.path) + for prop in message.properties: + prop_type = get_property_type(prop, tree, node, node.imports, namespace) + node.add_property(prop_type, prop.name, prop.optional, prop.comment, prop.repeated) + for nested in message.nested_messages: + parse_message_props(nested) - # Write the combined code to a file with the name from the file_path - filename = os.path.join(path, f"{filename}.py") - with open(filename, 'w') as f: - f.write(combined_code) - - return paths + parse_message_props(msg) + return tree # Mapping of special types to Python types type_mapping = { @@ -434,6 +486,44 @@ def generate_enum_code(enum) -> str: enum_code += f" {name} = \"{value.name}\" # {value.comment}\n" return enum_code +def generate_service_code(service, tree: Tree, current_node:TreeNode, import_descriptors: List[ImportDescriptor]) -> str: + comment = service.comment + name = service.name + procedures = service.procedures + service_namespace = service.namespace + + class_code = parseComment(comment) + class_code += f"class {name}:\n" + for procedure in procedures: + comment = procedure.comment + name = procedure.name + request = procedure.request + response = procedure.response + + descriptor = get_descriptor_by_partial_name(name, import_descriptors, tree) + # create a method name from the name value, by adding underscores between camel case + method_name = "" + for i, c in enumerate(name): + if c.isupper() and i != 0: + method_name += "_" + method_name += c.lower() + class_code += parseComment(comment) + + # Add the descriptor type so that it can be imported + assert descriptor != None, f"Descriptor not found for {name}" + descriptor.add_type(name, "") + + # Get the tree for the file + parent_node = tree.search(descriptor.file) + request_node = parent_node.get_child("Request") + response_node = parent_node.get_child("Response") + + if request == None: + request = "Empty" + + + return class_code + def generate_init_files(paths: set, tree: Tree, output_dir: str): for path in paths: init_file = os.path.join(path, "__init__.py") @@ -454,49 +544,6 @@ def generate_init_files(paths: set, tree: Tree, output_dir: str): for import_path in imports: f.write(f"from {import_path} import * \n") -def parse_service_file(file_path: str) -> List[dict]: - service_data = [] - with open(file_path, 'r') as f: - lines = f.readlines() - i = 0 - while i < len(lines): - line = lines[i].strip() - if line.startswith("service"): - service_name = line.split(" ")[1].strip("{") - i += 1 - while i < len(lines): - line = lines[i].strip() - if line.startswith("//"): - comment = line.lstrip("//").strip() - elif line.startswith("rpc"): - rpc_name = line.split(" ")[1].split("(")[0] - request_type = line.split("(")[1].split(")")[0].strip() - response_type = line.split("returns (")[1].split(")")[0].strip() - service_data.append({ - "comment": comment, - "name": rpc_name, - "request": request_type, - "response": response_type - }) - elif line == "}": - break - i += 1 - i += 1 - return service_data - -def generate_function_file(input_dir:str, output_dir: str, tree: Tree): - function_file = os.path.join(output_dir, "scanner_helper.py") - # Check to see if the file exists, if it does, delete it - if os.path.exists(function_file): - os.remove(function_file) - - service_file = os.path.join(input_dir, "MF/V3/Three.proto") - service_data = parse_service_file(service_file) - print(service_data) - # with open(function_file, 'w') as f: - - - def main(): parser = argparse.ArgumentParser(description="Generate Python classes and enums from protobuf schema objects.") @@ -514,7 +561,6 @@ def main(): tree= get_tree(proto_objects) paths = generate_python_code(proto_objects, args.output_dir, tree) generate_init_files(paths, tree, args.output_dir) - generate_function_file(args.input_dir, args.output_dir, tree) exit(0) From 6b63e1e21bef4136164b3c96757232b3f1230746 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 19 Sep 2024 18:45:45 -0400 Subject: [PATCH 38/86] Update Schema --- V3Schema | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/V3Schema b/V3Schema index edc6230..82177f5 160000 --- a/V3Schema +++ b/V3Schema @@ -1 +1 @@ -Subproject commit edc62306ba5ce8a18317fdc6eeabffa5f361c3f0 +Subproject commit 82177f599ea080edf81be69b4a20b6f4daa01525 From 1741350f9b4e90cbc6377564ee384753605f05d8 Mon Sep 17 00:00:00 2001 From: Drew Shark Date: Thu, 19 Sep 2024 21:28:31 -0400 Subject: [PATCH 39/86] Added launch.json. Moved tree to seperate file. Using Tree instead of Message Types --- .vscode/launch.json | 14 ++ V3Schema | 2 +- scripts/transpileProto.py | 272 +++++++++----------------------------- scripts/tree.py | 184 ++++++++++++++++++++++++++ 4 files changed, 265 insertions(+), 207 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 scripts/tree.py diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..35298e1 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Transpile", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/scripts/transpileProto.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}", + "justMyCode": true + } + ] +} diff --git a/V3Schema b/V3Schema index 82177f5..8ccc60a 160000 --- a/V3Schema +++ b/V3Schema @@ -1 +1 @@ -Subproject commit 82177f599ea080edf81be69b4a20b6f4daa01525 +Subproject commit 8ccc60ab1ee9d5f4ea4850bae80c89977c6c892c diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 6dedddf..8b70762 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -2,161 +2,46 @@ import argparse from interpretProto import create_proto_objects, MessageType, parse_proto from typing import List, Dict,Tuple, Set +from enum import Enum +from tree import TreeNode, Tree, TreeProperty, NodeType, ImportDescriptor, get_descriptor_by_name, get_descriptor_by_partial_name -class TreeProperty: - def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated) -> None: - self.type: str = type_ - self.name: str = name - self.optional: bool = optional - self.repeated: bool = repeated - self.comment: str = comment - -class TreeNode: - def __init__(self, name: str, parent = None, filespace = None): - self.name = name - self.parent = parent - self.children = {} - self.properties = [] - self.imports = [] - self.filespace = filespace - - def add_child(self, child_node): - self.children[child_node.name] = child_node - - def add_property(self, type_: str, name: str, optional: bool, comment: str, repeated: bool) -> None: - self.properties.append(TreeProperty(type_, name, optional, comment, repeated)) - - def add_import(self, import_path: str): - self.imports.append(ImportDescriptor(import_path)) - - def get_child(self, name: str): - parts = name.split('.') - # Check each part of the name to see if it is a child - temp = self - while temp and len(parts) > 0: - temp = temp.children.get(parts[0], None) - parts = parts[1:] - if temp: - return temp - return None - - def has_child(self, name: str): - temp = self.get_child(name) - if temp: - return True - return False - - def get_path(self): - path = [] - current_node = self - while current_node: - if current_node.name == "root": - break - path.append(current_node.name) - current_node = current_node.parent - return '.'.join(reversed(path)) - - def get_relative_path(self, node): - path = [] - current_node = self - while current_node != node: - if current_node.name == "root": - break - path.append(current_node.name) - current_node = current_node.parent - if current_node: - path.append(current_node.name) - return '.'.join(reversed(path)) - - def get_first_parent_with_name(self, name: str): - # Break the name into parts - top_name = name.split('.')[0] +# Mapping of special types to Python types +type_mapping = { + "int32": "int", + "Int32": "int", + "int64": "int", + "Int64": "int", + "uint64": "int", + "UInt64": "int", + "uint32": "int", + "UInt32": "int", + "bool": "bool", + "Bool": "bool", + "float": "float", + "Float": "float", + "double": "float", + "Double": "float", + "string": "str", + "String": "str", + "google.protobuf.Any": "_any_pb2" +} - current_node = self - while current_node: - if current_node.name == "root": - break - if current_node.name == top_name: - return current_node - current_node = current_node.parent - return None - - def climbing_search(self, name: str): - current_node = self - #find the top level node and return it's child - while current_node: - if current_node.name == "root": - break - if current_node.name == name: - return current_node - elif current_node.has_child(name): - return current_node.get_child(name) - current_node = current_node.parent - return None - -class Tree: - def __init__(self): - self.root = TreeNode("root") - - def add_path(self, path: str, filespace) -> TreeNode: - parts = path.split('.') - current_node = self.root - for part in parts: - if part not in current_node.children: - new_node = TreeNode(part, parent=current_node) - current_node.add_child(new_node) - current_node = current_node.get_child(part) - current_node.filespace = filespace - return current_node - - def search(self, path: str) -> TreeNode: - parts = path.split('.') - current_node = self.root - for part in parts: - current_node = current_node.get_child(part) - if current_node is None: - return None - return current_node - - def get_nodes_with_filespace(self, filespace: str) -> TreeNode: - nodes = [] - def get_nodes(node): - if node.filespace == filespace: - nodes.append(node) - for child in node.children.values(): - get_nodes(child) - get_nodes(self.root) - return nodes - -class ImportDescriptor: - def __init__(self, file:str): - self.file = file - self.types: List[dict[str,str]] = [] - def add_type(self, type:str, replacement:str): - # Check to see if the type is already in the list - for t in self.types: - if t["type"] == type: - return - self.types.append({"type":type, "replacement":replacement}) - -def get_descriptor_by_name(name: str, descriptors: List[dict]) -> ImportDescriptor: - for descriptor in descriptors: - if descriptor.file == name: - return descriptor - return None - -def get_descriptor_by_partial_name(name, import_descriptors, tree) -> ImportDescriptor: - for descriptor in import_descriptors: - descriptor_file_nodes = tree.get_nodes_with_filespace(descriptor.file) - for descriptor_node in descriptor_file_nodes: - if descriptor_node.name == name: - return descriptor - return None def generate_python_code(proto_objects: List, output_dir: str, tree:Tree) -> set: # create a unique set of paths paths = set() + + branches = tree.get_branches_by_filespace() + + for branch in branches.values(): + # First get imports + imports = set() + for node in branch: + imports.update(node.imports) + + code = generate_import_lines(imports) + for obj in proto_objects: print(f"Parsing file: {obj['filename']}") @@ -187,16 +72,16 @@ def generate_python_code(proto_objects: List, output_dir: str, tree:Tree) -> set # Generate code for Services service_code = "" - for service in services: - code = generate_service_code(service, tree, file_node, importDescs) - service_code += code + "\n\n" + # for service in services: + # code = generate_service_code(service, tree, file_node, importDescs) + # service_code += code + "\n\n" # Generate code for messages message_code = "" for message in messages: current_node = file_node.get_child(message.name) - code = generate_message_code(message, tree, current_node, importDescs) + code = generate_class_code(tree, current_node, importDescs) message_code += code + "\n\n" # Generate imports another time to get the final output of imports @@ -274,7 +159,12 @@ def get_nested_messages(message, nested_name_space): nested_name_space = f"{nested_name_space}.{message.name}" #convert filename to namespace node = tree.add_path(nested_name_space, filespace) + if message.type == "enum": + node.type = NodeType.Enum + elif message.type == "message": + node.type = NodeType.Class node.imports = importDescs + node.comment = parseComment(message.comment) for nested in message.nested_messages: get_nested_messages(nested, nested_name_space) get_nested_messages(msg, namespace) @@ -282,7 +172,9 @@ def get_nested_messages(message, nested_name_space): # I think services are top level definitions, so no parent needed service_path = f"{namespace}.{service.name}" node = tree.add_path(service_path, filespace) + node.type = NodeType.Service node.imports = importDescs + node.comment = parseComment(service.comment) for obj in proto_objects: namespace = obj['namespace'] @@ -292,39 +184,20 @@ def parse_message_props(message): node = tree.search(message.path) for prop in message.properties: prop_type = get_property_type(prop, tree, node, node.imports, namespace) - node.add_property(prop_type, prop.name, prop.optional, prop.comment, prop.repeated) + node.add_property(prop_type, prop.name, prop.optional, parseComment(prop.comment), prop.repeated) for nested in message.nested_messages: parse_message_props(nested) parse_message_props(msg) return tree -# Mapping of special types to Python types -type_mapping = { - "int32": "int", - "Int32": "int", - "int64": "int", - "Int64": "int", - "uint64": "int", - "UInt64": "int", - "uint32": "int", - "UInt32": "int", - "bool": "bool", - "Bool": "bool", - "float": "float", - "Float": "float", - "double": "float", - "Double": "float", - "string": "str", - "String": "str", - "google.protobuf.Any": "_any_pb2" -} - def parseComment(comment: str) -> str: if comment != "": if len(comment.split('\n')) > 1: class_code = f'"""{comment}"""\n' else: + # remove initial whitespace in comment + comment = comment.strip() class_code = f'# {comment}\n' else: class_code = '\n' @@ -411,27 +284,20 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L raise Exception("Property Type could not be resolved", property.type) -def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, import_descriptors: List[ImportDescriptor]) -> str: +def generate_class_code(tree: Tree, current_node:TreeNode, import_descriptors: List[ImportDescriptor]) -> str: - if message.type == "enum": - return generate_enum_code(message) + "\n\n" + if current_node.type == NodeType.Enum: + return generate_enum_code(current_node) + "\n\n" - comment = message.comment - name = message.name - properties = message.properties - nested_messages = message.nested_messages - message_namespace = message.namespace + properties = current_node.properties - class_code = parseComment(comment) + class_code = current_node.comment - class_code += f"class {name}:\n" + class_code += f"class {current_node.name}:\n" # Generate code for nested messages - for nested_message in nested_messages: - if nested_message.type == "enum": - nested_class_code = generate_enum_code(nested_message) + "\n\n" - else : - nested_class_code = generate_message_code(nested_message, tree, current_node.get_child(nested_message.name), import_descriptors) + for child in current_node.children.values(): + nested_class_code = generate_class_code(tree, child, import_descriptors) nested_class_code = add_indents(nested_class_code,1) class_code += f"\n{nested_class_code}\n" @@ -442,7 +308,6 @@ def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, impo class_code += " def __init__(self" for prop in properties: - prop_type = get_property_type(prop, tree, current_node, import_descriptors, message_namespace) # handle repeated if prop.repeated: @@ -452,17 +317,17 @@ def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, impo descriptor = ImportDescriptor("typing") import_descriptors.append(descriptor) descriptor.add_type("List", "") - class_code += f", {prop.name}:List[{prop_type}]" + class_code += f", {prop.name}:List[{prop.type}]" else: - class_code += f", {prop.name}:{prop_type}" + class_code += f", {prop.name}:{prop.type}" # handle optionals if prop.optional: class_code += " = None" class_code += "):\n" for prop in properties: - # Add comments with parseComment function with spaces + # Add comments with spaces if prop.comment: - class_code += f"\n{add_indents(parseComment(prop.comment),2)}" + class_code += f"\n{add_indents(prop.comment,2)}" class_code += add_indents(f"self.{prop.name} = {prop.name}\n",2) else: class_code += " def __init__(self):\n" @@ -474,25 +339,20 @@ def generate_message_code(message: Dict, tree: Tree, current_node:TreeNode, impo "None": "Empty", } -def generate_enum_code(enum) -> str: - comment = enum.comment - name = enum.name - values = enum.properties - - enum_code = parseComment(comment) - enum_code += f"class {name}(Enum):\n" - for value in values: +def generate_enum_code(enum:TreeNode) -> str: + enum_code = enum.comment + enum_code += f"class {enum.name}(Enum):\n" + for value in enum.properties: name = name_mapping.get(value.name, value.name) - enum_code += f" {name} = \"{value.name}\" # {value.comment}\n" + enum_code += f" {name} = \"{value.name}\" {value.comment}\n" return enum_code def generate_service_code(service, tree: Tree, current_node:TreeNode, import_descriptors: List[ImportDescriptor]) -> str: - comment = service.comment name = service.name procedures = service.procedures service_namespace = service.namespace - class_code = parseComment(comment) + class_code = service.comment class_code += f"class {name}:\n" for procedure in procedures: comment = procedure.comment @@ -507,7 +367,7 @@ def generate_service_code(service, tree: Tree, current_node:TreeNode, import_des if c.isupper() and i != 0: method_name += "_" method_name += c.lower() - class_code += parseComment(comment) + class_code += comment # Add the descriptor type so that it can be imported assert descriptor != None, f"Descriptor not found for {name}" diff --git a/scripts/tree.py b/scripts/tree.py new file mode 100644 index 0000000..8321a1f --- /dev/null +++ b/scripts/tree.py @@ -0,0 +1,184 @@ +from enum import Enum +from typing import List, Dict + +class TreeProperty: + def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated) -> None: + self.type: str = type_ + self.name: str = name + self.optional: bool = optional + self.repeated: bool = repeated + self.comment: str = comment + +class NodeType(Enum): + Class = "Class" + Enum = "Enum" + Service = "Service" + Directory = "Directory" + +class TreeNode: + def __init__(self, name: str, nodeType: NodeType = NodeType.Directory, parent = None, filespace = None): + self.name = name + self.type = nodeType + self.parent = parent + self.children = {} + self.properties = [] + self.imports = [] + self.filespace = filespace + self.comment = None + + def add_child(self, child_node): + self.children[child_node.name] = child_node + + def add_property(self, type_: str, name: str, optional: bool, comment: str, repeated: bool) -> None: + self.properties.append(TreeProperty(type_, name, optional, comment, repeated)) + + def add_import(self, import_path: str): + self.imports.append(ImportDescriptor(import_path)) + + def get_child(self, name: str): + parts = name.split('.') + # Check each part of the name to see if it is a child + temp = self + while temp and len(parts) > 0: + temp = temp.children.get(parts[0], None) + parts = parts[1:] + if temp: + return temp + return None + + def has_child(self, name: str): + temp = self.get_child(name) + if temp: + return True + return False + + def get_path(self): + path = [] + current_node = self + while current_node: + if current_node.name == "root": + break + path.append(current_node.name) + current_node = current_node.parent + return '.'.join(reversed(path)) + + def get_relative_path(self, node): + path = [] + current_node = self + while current_node != node: + if current_node.name == "root": + break + path.append(current_node.name) + current_node = current_node.parent + if current_node: + path.append(current_node.name) + return '.'.join(reversed(path)) + + def get_first_parent_with_name(self, name: str): + # Break the name into parts + top_name = name.split('.')[0] + + current_node = self + while current_node: + if current_node.name == "root": + break + if current_node.name == top_name: + return current_node + current_node = current_node.parent + return None + + def climbing_search(self, name: str): + current_node = self + #find the top level node and return it's child + while current_node: + if current_node.name == "root": + break + if current_node.name == name: + return current_node + elif current_node.has_child(name): + return current_node.get_child(name) + current_node = current_node.parent + return None + +class Tree: + def __init__(self): + self.root = TreeNode("root") + + def add_path(self, path: str, filespace) -> TreeNode: + parts = path.split('.') + current_node = self.root + for part in parts: + if part not in current_node.children: + new_node = TreeNode(part, parent=current_node) + current_node.add_child(new_node) + current_node = current_node.get_child(part) + current_node.filespace = filespace + return current_node + + def search(self, path: str) -> TreeNode: + parts = path.split('.') + current_node = self.root + for part in parts: + current_node = current_node.get_child(part) + if current_node is None: + return None + return current_node + + def get_nodes_with_filespace(self, filespace: str) -> TreeNode: + nodes = [] + def get_nodes(node): + if node.filespace == filespace: + nodes.append(node) + for child in node.children.values(): + get_nodes(child) + get_nodes(self.root) + return nodes + + def get_branches_by_filespace(self) -> Dict[str, List[TreeNode]]: + """ + Traverse the tree and collect nodes by their filespace. + + Returns: + Dict[str, List[TreeNode]]: A dictionary where the keys are filespace + identifiers and the values are lists of TreeNode objects that belong + to that filespace. + """ + branch_nodes = {} + + def traverse_for_filespace(node: TreeNode): + if node.filespace: + if node.filespace not in branch_nodes: + branch_nodes[node.filespace] = [] + branch_nodes[node.filespace].append(node) + else: + for child in node.children.values(): + traverse_for_filespace(child) + + traverse_for_filespace(self.root) + + return branch_nodes + +class ImportDescriptor: + def __init__(self, file:str): + self.file = file + self.types: List[dict[str,str]] = [] + def add_type(self, type:str, replacement:str): + # Check to see if the type is already in the list + for t in self.types: + if t["type"] == type: + return + self.types.append({"type":type, "replacement":replacement}) + +def get_descriptor_by_name(name: str, descriptors: List[dict]) -> ImportDescriptor: + for descriptor in descriptors: + if descriptor.file == name: + return descriptor + return None + +def get_descriptor_by_partial_name(name, import_descriptors, tree) -> ImportDescriptor: + for descriptor in import_descriptors: + descriptor_file_nodes = tree.get_nodes_with_filespace(descriptor.file) + for descriptor_node in descriptor_file_nodes: + if descriptor_node.name == name: + return descriptor + return None \ No newline at end of file From 457bc1df1a1864a3848bc9d7bd5ff14a188c9f24 Mon Sep 17 00:00:00 2001 From: Drew Shark Date: Thu, 19 Sep 2024 21:46:13 -0400 Subject: [PATCH 40/86] Sliding over to Tree instead of Messages --- scripts/transpileProto.py | 73 ++++++++++++++------------------------- 1 file changed, 25 insertions(+), 48 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 8b70762..5a8afce 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -28,73 +28,50 @@ } -def generate_python_code(proto_objects: List, output_dir: str, tree:Tree) -> set: +def generate_python_code(output_dir: str, tree:Tree) -> set: # create a unique set of paths paths = set() branches = tree.get_branches_by_filespace() - for branch in branches.values(): - # First get imports - imports = set() - for node in branch: - imports.update(node.imports) - - code = generate_import_lines(imports) - - - for obj in proto_objects: - print(f"Parsing file: {obj['filename']}") - - file_node = tree.search(obj['namespace']) - - # Access namespace, imports, messages, enums from the dictionary obj - #namespace = obj['namespace'] - imports = obj['imports'] - messages = obj['messages'] - file_path = obj['filename'] - namespace = obj['namespace'] - services = obj['services'] + for key, branch in branches.items(): - # Get the base path of the file - path = os.path.join(output_dir, os.path.dirname(file_path)) + # Get the file path + file_path = os.path.join(output_dir, key.replace(".", "/") + ".py") + path = os.path.dirname(file_path) - # Get the filename without the extension - filename = os.path.basename(file_path).replace('.proto', '') - + print(f"Parsing file: {file_path}") + # Create the directory if it doesn't exist os.makedirs(path, exist_ok=True) # Add the path to a unique set paths.add(path) + + # Get imports + imports = set() + for node in branch: + imports.update(node.imports) - # Generate imports paths for parsing - importDescs = get_imports(imports) + import_lines = generate_import_lines(imports) # Generate code for Services service_code = "" # for service in services: # code = generate_service_code(service, tree, file_node, importDescs) # service_code += code + "\n\n" - # Generate code for messages - message_code = "" - for message in messages: - current_node = file_node.get_child(message.name) - code = generate_class_code(tree, current_node, importDescs) - message_code += code + "\n\n" - - # Generate imports another time to get the final output of imports - import_lines = generate_import_lines(importDescs) - + class_code = "" + for node in branch: + class_code += generate_class_code(node) + "\n\n" + # Combine imports, message code, and enum code - combined_code = import_lines + "\n\n" + message_code + "\n\n" + service_code + combined_code = import_lines + "\n\n" + class_code + "\n\n" + service_code # Write the combined code to a file with the name from the file_path - filename = os.path.join(path, f"{filename}.py") - with open(filename, 'w') as f: + with open(file_path, 'w') as f: f.write(combined_code) - + return paths @@ -284,7 +261,7 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L raise Exception("Property Type could not be resolved", property.type) -def generate_class_code(tree: Tree, current_node:TreeNode, import_descriptors: List[ImportDescriptor]) -> str: +def generate_class_code(current_node:TreeNode) -> str: if current_node.type == NodeType.Enum: return generate_enum_code(current_node) + "\n\n" @@ -297,7 +274,7 @@ def generate_class_code(tree: Tree, current_node:TreeNode, import_descriptors: L # Generate code for nested messages for child in current_node.children.values(): - nested_class_code = generate_class_code(tree, child, import_descriptors) + nested_class_code = generate_class_code(child) nested_class_code = add_indents(nested_class_code,1) class_code += f"\n{nested_class_code}\n" @@ -312,10 +289,10 @@ def generate_class_code(tree: Tree, current_node:TreeNode, import_descriptors: L # handle repeated if prop.repeated: # Get importDescriptor for List "typing" - descriptor = get_descriptor_by_name("typing", import_descriptors) + descriptor = get_descriptor_by_name("typing", current_node.imports) if descriptor == None: descriptor = ImportDescriptor("typing") - import_descriptors.append(descriptor) + current_node.imports.append(descriptor) descriptor.add_type("List", "") class_code += f", {prop.name}:List[{prop.type}]" else: @@ -419,7 +396,7 @@ def main(): proto_objects = create_proto_objects(args.input_dir) tree= get_tree(proto_objects) - paths = generate_python_code(proto_objects, args.output_dir, tree) + paths = generate_python_code(args.output_dir, tree) generate_init_files(paths, tree, args.output_dir) exit(0) From c384f4ad879e7d4014bf374e1a966bc1c6e28a56 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 20 Sep 2024 13:35:02 -0400 Subject: [PATCH 41/86] Comments inside class --- scripts/transpileProto.py | 107 ++++++++++++++++++++++++-------------- scripts/tree.py | 22 ++++++-- 2 files changed, 84 insertions(+), 45 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 5a8afce..1e0d968 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -53,17 +53,17 @@ def generate_python_code(output_dir: str, tree:Tree) -> set: imports.update(node.imports) import_lines = generate_import_lines(imports) - - # Generate code for Services + + # Generate code for messages + class_code = "" service_code = "" - # for service in services: - # code = generate_service_code(service, tree, file_node, importDescs) - # service_code += code + "\n\n" - # Generate code for messages class_code = "" for node in branch: - class_code += generate_class_code(node) + "\n\n" + if node.type == NodeType.Class: + class_code += generate_class_code(node) + "\n\n" + elif node.type == NodeType.Service: + service_code += generate_service_code(node, tree) + "\n\n" # Combine imports, message code, and enum code combined_code = import_lines + "\n\n" + class_code + "\n\n" + service_code @@ -120,7 +120,7 @@ def get_tree(proto_objects: List)-> Tree: # We need to go through the proto_objects twice. # First to build the base tree - # Then to to add the properties to the objects in the tree (self referencing) + for obj in proto_objects: namespace = obj['namespace'] imports = obj['imports'] @@ -152,7 +152,8 @@ def get_nested_messages(message, nested_name_space): node.type = NodeType.Service node.imports = importDescs node.comment = parseComment(service.comment) - + + # Then Loop again to to add the properties to the objects in the tree (self referencing) for obj in proto_objects: namespace = obj['namespace'] for msg in obj['messages']: @@ -166,6 +167,32 @@ def parse_message_props(message): parse_message_props(nested) parse_message_props(msg) + for service in obj['services']: + service_path = f"{namespace}.{service.name}" + node = tree.search(service_path) + for procedure in service.procedures: + # Remove only the last word from procedure.request and procedure.response + request_base = procedure.request.rsplit('.', 1)[0] + response_base = procedure.response.rsplit('.', 1)[0] + + import_descriptor_request = get_descriptor_by_partial_name(request_base, node.imports) + import_descriptor_response = get_descriptor_by_partial_name(response_base, node.imports) + # Check if the import descriptor is found and throw a message if not + assert import_descriptor_request != None, f"Descriptor not found for {procedure.request}" + assert import_descriptor_response != None, f"Descriptor not found for {procedure.response}" + + request_node = tree.search(import_descriptor_request.file) + response_node = tree.search(import_descriptor_response.file) + + # Check if the nodes are valid + assert request_node != None, f"Node not found for {procedure.request}" + assert response_node != None, f"Node not found for {procedure.response}" + + assert request_node.has_child("Request"), f"Request node not found for {procedure.request}" + assert response_node.has_child("Response"), f"Response node not found for {procedure.response}" + + # Add the procedure + node.add_procedure(procedure.name, request_node.get_path(), response_node.get_path(), parseComment(procedure.comment)) return tree def parseComment(comment: str) -> str: @@ -191,8 +218,6 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L return type_mapping.get(property.type, property.type) property_type_parts = property.type.split('.') - # if property.type == "Settings.Export" and node.filespace == "MF.V3.Tasks.ExportMerge": - # print("Debug") if len(property_type_parts) > 1: # Combine message_namespace with property type @@ -268,9 +293,9 @@ def generate_class_code(current_node:TreeNode) -> str: properties = current_node.properties - class_code = current_node.comment - - class_code += f"class {current_node.name}:\n" + class_code = f"class {current_node.name}:\n" + + class_code += add_indents(current_node.comment,1) # Generate code for nested messages for child in current_node.children.values(): @@ -278,11 +303,11 @@ def generate_class_code(current_node:TreeNode) -> str: nested_class_code = add_indents(nested_class_code,1) class_code += f"\n{nested_class_code}\n" + class_code += " def __init__(self" + if properties: # sort properties so optionals are last properties = sorted(properties, key=lambda x: x.optional) - - class_code += " def __init__(self" for prop in properties: @@ -307,7 +332,6 @@ def generate_class_code(current_node:TreeNode) -> str: class_code += f"\n{add_indents(prop.comment,2)}" class_code += add_indents(f"self.{prop.name} = {prop.name}\n",2) else: - class_code += " def __init__(self):\n" class_code += " pass\n" return class_code @@ -324,42 +348,45 @@ def generate_enum_code(enum:TreeNode) -> str: enum_code += f" {name} = \"{value.name}\" {value.comment}\n" return enum_code -def generate_service_code(service, tree: Tree, current_node:TreeNode, import_descriptors: List[ImportDescriptor]) -> str: - name = service.name - procedures = service.procedures - service_namespace = service.namespace +def generate_service_code( current_node:TreeNode, tree:Tree) -> str: + name = current_node.name - class_code = service.comment - class_code += f"class {name}:\n" - for procedure in procedures: - comment = procedure.comment + + service_code = f"class {name}:\n" + + service_code += add_indents(current_node.comment, 1) + service_code += " def __init__(self" + service_code += " pass\n" + + for procedure in current_node.procedures: + service_code += procedure.comment name = procedure.name - request = procedure.request - response = procedure.response - descriptor = get_descriptor_by_partial_name(name, import_descriptors, tree) + request_node = tree.search(procedure.request) + response_node = tree.search(procedure.response) + # create a method name from the name value, by adding underscores between camel case method_name = "" for i, c in enumerate(name): if c.isupper() and i != 0: - method_name += "_" + method_name += "_" method_name += c.lower() - class_code += comment - - # Add the descriptor type so that it can be imported - assert descriptor != None, f"Descriptor not found for {name}" - descriptor.add_type(name, "") + + + # Add the descriptor type so that it can be imported + # assert descriptor != None, f"Descriptor not found for {name}" + # descriptor.add_type(name, "") # Get the tree for the file - parent_node = tree.search(descriptor.file) - request_node = parent_node.get_child("Request") - response_node = parent_node.get_child("Response") + # parent_node = tree.search(descriptor.file) + # request_node = parent_node.get_child("Request") + # response_node = parent_node.get_child("Response") - if request == None: - request = "Empty" + # if request == None: + # request = "Empty" - return class_code + return service_code def generate_init_files(paths: set, tree: Tree, output_dir: str): for path in paths: diff --git a/scripts/tree.py b/scripts/tree.py index 8321a1f..c935e9d 100644 --- a/scripts/tree.py +++ b/scripts/tree.py @@ -9,6 +9,13 @@ def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated self.repeated: bool = repeated self.comment: str = comment +class TreeProcedure: + def __init__(self, name: str, request: str, response: str, comment: str) -> None: + self.name: str = name + self.request: str = request + self.response: str = response + self.comment: str = comment + class NodeType(Enum): Class = "Class" Enum = "Enum" @@ -22,6 +29,7 @@ def __init__(self, name: str, nodeType: NodeType = NodeType.Directory, parent = self.parent = parent self.children = {} self.properties = [] + self.procedures = [] self.imports = [] self.filespace = filespace self.comment = None @@ -32,6 +40,9 @@ def add_child(self, child_node): def add_property(self, type_: str, name: str, optional: bool, comment: str, repeated: bool) -> None: self.properties.append(TreeProperty(type_, name, optional, comment, repeated)) + def add_procedure(self, name: str, request: str, response: str, comment: str) -> None: + self.procedures.append(TreeProcedure(name, request, response, comment)) + def add_import(self, import_path: str): self.imports.append(ImportDescriptor(import_path)) @@ -175,10 +186,11 @@ def get_descriptor_by_name(name: str, descriptors: List[dict]) -> ImportDescript return descriptor return None -def get_descriptor_by_partial_name(name, import_descriptors, tree) -> ImportDescriptor: +def get_descriptor_by_partial_name(name, import_descriptors) -> ImportDescriptor: for descriptor in import_descriptors: - descriptor_file_nodes = tree.get_nodes_with_filespace(descriptor.file) - for descriptor_node in descriptor_file_nodes: - if descriptor_node.name == name: - return descriptor + # replace any . in name with / + nameAsPath = name.replace('.', '/') + # match nameAsPath against the last part of descriptor.file + if descriptor.file.endswith(nameAsPath): + return descriptor return None \ No newline at end of file From 5cc25b2b50a7ab9aaaa285a60a158841fbf590d0 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 20 Sep 2024 16:11:23 -0400 Subject: [PATCH 42/86] Starting to write methods for Service --- scripts/transpileProto.py | 99 +++++++++++++++++++++++++++------------ scripts/tree.py | 3 +- 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 1e0d968..515294c 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -46,13 +46,6 @@ def generate_python_code(output_dir: str, tree:Tree) -> set: os.makedirs(path, exist_ok=True) # Add the path to a unique set paths.add(path) - - # Get imports - imports = set() - for node in branch: - imports.update(node.imports) - - import_lines = generate_import_lines(imports) # Generate code for messages class_code = "" @@ -65,6 +58,13 @@ def generate_python_code(output_dir: str, tree:Tree) -> set: elif node.type == NodeType.Service: service_code += generate_service_code(node, tree) + "\n\n" + # Get imports + imports = set() + for node in branch: + imports.update(node.imports) + + import_lines = generate_import_lines(imports) + # Combine imports, message code, and enum code combined_code = import_lines + "\n\n" + class_code + "\n\n" + service_code @@ -161,8 +161,8 @@ def parse_message_props(message): message.path = f"{namespace}.{message.parent + '.' if message.parent else ''}{message.name}" node = tree.search(message.path) for prop in message.properties: - prop_type = get_property_type(prop, tree, node, node.imports, namespace) - node.add_property(prop_type, prop.name, prop.optional, parseComment(prop.comment), prop.repeated) + property = get_property(prop, tree, node, node.imports, namespace) + node.properties.append(property) for nested in message.nested_messages: parse_message_props(nested) @@ -177,10 +177,14 @@ def parse_message_props(message): import_descriptor_request = get_descriptor_by_partial_name(request_base, node.imports) import_descriptor_response = get_descriptor_by_partial_name(response_base, node.imports) + # Check if the import descriptor is found and throw a message if not assert import_descriptor_request != None, f"Descriptor not found for {procedure.request}" assert import_descriptor_response != None, f"Descriptor not found for {procedure.response}" + import_descriptor_request.add_type(request_base, "") + import_descriptor_response.add_type(response_base, "") + request_node = tree.search(import_descriptor_request.file) response_node = tree.search(import_descriptor_response.file) @@ -192,7 +196,7 @@ def parse_message_props(message): assert response_node.has_child("Response"), f"Response node not found for {procedure.response}" # Add the procedure - node.add_procedure(procedure.name, request_node.get_path(), response_node.get_path(), parseComment(procedure.comment)) + node.add_procedure(procedure.name, request_node.get_child("Request").get_path(), response_node.get_child("Response").get_path(), parseComment(procedure.comment)) return tree def parseComment(comment: str) -> str: @@ -211,11 +215,14 @@ def add_indents(code: str, indent: int) -> str: # Indent the code by adding spaces if the line is not empty return "\n".join([f"{' ' * indent}{line}" if line.strip() else line for line in code.split("\n")]) -def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: List[ImportDescriptor], message_namespace:str) -> str: +def get_property(property, tree: Tree, node:TreeNode, import_descriptors: List[ImportDescriptor], message_namespace:str) -> TreeProperty: + tree_property = TreeProperty("", property.name, property.optional, parseComment(property.comment), property.repeated) + # Check to see if the property type can be mapped to a Python type if property.type in type_mapping: - return type_mapping.get(property.type, property.type) + tree_property.type = type_mapping.get(property.type, property.type) + return tree_property property_type_parts = property.type.split('.') @@ -236,7 +243,8 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L raise Exception("Property Type could not be resolved", property.type) if (property_node.filespace == node.filespace): - return f"'{property.type}'" + tree_property.type = f"'{property.type}'" + return tree_property temp = property_node while temp.parent.filespace == property_node.filespace: @@ -249,7 +257,9 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L unique_name = unique_name.replace(".", "_") descriptor.add_type(temp.name, unique_name) - return f"'{unique_name}'" + tree_property.import_descriptor = descriptor + tree_property.type = f"'{unique_name}'" + return tree_property else: sibling_nodes = tree.get_nodes_with_filespace(node.filespace) @@ -257,18 +267,23 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L if sibling_node.has_child(property.type): if sibling_node.parent.name == node.parent.name: #true siblings - return f"'{property.type}'" + tree_property.type = f"'{property.type}'" + return tree_property else: - return f"'{sibling_node.name}.{property.type}'" + tree_property.type = f"'{sibling_node.name}.{property.type}'" + return tree_property elif sibling_node.name == property.type: - return f"'{property.type}'" + tree_property.type = f"'{property.type}'" + return tree_property for descriptor in import_descriptors: # Search for direct imports first descriptor_file_node = tree.search(descriptor.file) if descriptor_file_node: if descriptor_file_node.name == property.type: descriptor.add_type(property.type, "") - return f"'{property.type}'" + tree_property.import_descriptor = descriptor + tree_property.type = f"'{property.type}'" + return tree_property for descriptor in import_descriptors: # Search for imports with the same filespace descriptor_file_nodes = tree.get_nodes_with_filespace(descriptor.file) @@ -277,10 +292,14 @@ def get_property_type(property, tree: Tree, node:TreeNode, import_descriptors: L continue elif descriptor_node.name == property.type: descriptor.add_type(property.type, "") - return f"'{property.type}'" + tree_property.import_descriptor = descriptor + tree_property.type = f"'{property.type}'" + return tree_property elif descriptor_node.has_child(property.type): descriptor.add_type(property.type, "") - return f"'{property.type}'" + tree_property.import_descriptor = descriptor + tree_property.type = f"'{property.type}'" + return tree_property raise Exception("Property Type could not be resolved", property.type) @@ -290,8 +309,6 @@ def generate_class_code(current_node:TreeNode) -> str: if current_node.type == NodeType.Enum: return generate_enum_code(current_node) + "\n\n" - - properties = current_node.properties class_code = f"class {current_node.name}:\n" @@ -305,9 +322,9 @@ def generate_class_code(current_node:TreeNode) -> str: class_code += " def __init__(self" - if properties: + if current_node.properties: # sort properties so optionals are last - properties = sorted(properties, key=lambda x: x.optional) + properties = sorted(current_node.properties, key=lambda x: x.optional) for prop in properties: @@ -355,11 +372,11 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: service_code = f"class {name}:\n" service_code += add_indents(current_node.comment, 1) - service_code += " def __init__(self" + service_code += " def __init__(self):\n" service_code += " pass\n" for procedure in current_node.procedures: - service_code += procedure.comment + name = procedure.name request_node = tree.search(procedure.request) @@ -372,11 +389,31 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: method_name += "_" method_name += c.lower() - - # Add the descriptor type so that it can be imported - # assert descriptor != None, f"Descriptor not found for {name}" - # descriptor.add_type(name, "") - + service_code += f" def {method_name}(self" + # loop over all the properties from the request node to get the input node + + method_properties = [] + for prop in request_node.properties: + if prop.name == "Input": + if prop.import_descriptor != None: + input_node = tree.search(prop.import_descriptor.file) + print(f"Found input node: {prop.type}") + for input_prop in input_node.properties: + method_properties.append(input_prop) + else: + method_properties.append(prop) + + for prop in method_properties: + service_code += f", {prop.name}:{prop.type}" + if prop.import_descriptor != None: + current_node.imports.append(prop.import_descriptor) + + service_code += f"):\n" + service_code += add_indents(procedure.comment,2) + service_code += f" {method_name}_request = {request_node.name}(\n" + for prop in request_node.properties: + service_code += f" {prop.name}={prop.name},\n" + service_code += " )\n" # Get the tree for the file # parent_node = tree.search(descriptor.file) # request_node = parent_node.get_child("Request") diff --git a/scripts/tree.py b/scripts/tree.py index c935e9d..c5cc9d0 100644 --- a/scripts/tree.py +++ b/scripts/tree.py @@ -2,12 +2,13 @@ from typing import List, Dict class TreeProperty: - def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated) -> None: + def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated: bool, import_descriptor = None) -> None: self.type: str = type_ self.name: str = name self.optional: bool = optional self.repeated: bool = repeated self.comment: str = comment + self.import_descriptor: ImportDescriptor = import_descriptor class TreeProcedure: def __init__(self, name: str, request: str, response: str, comment: str) -> None: From 598831b6933e85e9e67c28c2dfc69eda882e9c13 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Tue, 24 Sep 2024 16:51:31 -0400 Subject: [PATCH 43/86] Changes to tree property to help simplify before service --- scripts/transpileProto.py | 343 +++++++++++++++++++++++--------------- scripts/tree.py | 27 +-- 2 files changed, 218 insertions(+), 152 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 515294c..e3b47cd 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -3,8 +3,10 @@ from interpretProto import create_proto_objects, MessageType, parse_proto from typing import List, Dict,Tuple, Set from enum import Enum -from tree import TreeNode, Tree, TreeProperty, NodeType, ImportDescriptor, get_descriptor_by_name, get_descriptor_by_partial_name - +from tree import TreeNode, Tree, TreeProperty, NodeType, ImportDescriptor, get_descriptor_by_partial_filename +import ast +import os +import subprocess # Mapping of special types to Python types type_mapping = { @@ -27,6 +29,14 @@ "google.protobuf.Any": "_any_pb2" } +python_types = [ + "int", + "float", + "bool", + "str", + "bytes" +] + def generate_python_code(output_dir: str, tree:Tree) -> set: # create a unique set of paths @@ -53,15 +63,13 @@ def generate_python_code(output_dir: str, tree:Tree) -> set: class_code = "" for node in branch: - if node.type == NodeType.Class: + if node.type == NodeType.Class or node.type == NodeType.Enum: class_code += generate_class_code(node) + "\n\n" - elif node.type == NodeType.Service: - service_code += generate_service_code(node, tree) + "\n\n" + # elif node.type == NodeType.Service: + # service_code += generate_service_code(node, tree) + "\n\n" - # Get imports - imports = set() - for node in branch: - imports.update(node.imports) + # Get imports + imports = get_imports_from_nodes(branch) import_lines = generate_import_lines(imports) @@ -74,7 +82,6 @@ def generate_python_code(output_dir: str, tree:Tree) -> set: return paths - def get_imports(imports: List[str]) -> List[ImportDescriptor]: module_parts_list:List[ImportDescriptor] = [] @@ -88,30 +95,66 @@ def get_imports(imports: List[str]) -> List[ImportDescriptor]: foundModule = module break if foundModule == None: - module_parts_list.append(ImportDescriptor(module_path)) + module_parts_list.append(ImportDescriptor(module_path, "", "")) return module_parts_list -def generate_import_lines(descriptors:List[ImportDescriptor]) -> str: - import_lines = [] - - for descriptor in descriptors: - # Split the import path into parts - module_path = descriptor.file - module_parts = module_path.split('.') - module_name = module_parts[-1] +def get_imports_from_nodes(nodes:List[TreeNode]) -> Dict[str, List[ImportDescriptor]]: + imports = [] + for node in nodes: + def nested_imports(node) -> List[ImportDescriptor]: + imports = [] + for imp in node.imports: + imports.append(imp) + for prop in node.properties: + if prop.import_descriptor != None: + imports.append(prop.import_descriptor) + for child in node.children.values(): + imports += nested_imports(child) + return imports - # Special consideration for google imports and enum - if "google" in module_parts: - import_lines.append(f"from {'.'.join(module_parts[:-1])} import {module_name}_pb2 as _{module_name}_pb2") - elif module_path == "enum": - import_lines.append(f"from enum import Enum") - else: - # Go through all the types in the descriptor and add them to the import line - for type in descriptor.types: - import_line = f"from {'.'.join(module_parts[:])} import {type['type']}" - if type['replacement'] != "": - import_line += f" as {type['replacement']}" - import_lines.append(import_line) + imports += nested_imports(node) + + # Group import descriptors by their file property + grouped_imports: Dict[str, List[ImportDescriptor]] = {} + for imp in imports: + if imp.file not in grouped_imports: + grouped_imports[imp.file] = [] + grouped_imports[imp.file].append(imp) + + # Convert the dictionary to a list of lists + unique_imports = list(grouped_imports.values()) + + + return unique_imports + +def generate_import_lines(descriptorsLists:Dict[str, List[ImportDescriptor]]) -> str: + import_lines = [] + + for descriptors in descriptorsLists: + for combined in descriptors.values(): + # If single import, then just add the import line + # otherwise let's put them all on one line + + for descriptor in combined: + # Split the import path into parts + module_path = descriptor.file + module_parts = module_path.split('.') + module_name = module_parts[-1] + + # Special consideration for google imports and enum + if "google" in module_parts: + import_lines.append(f"from {'.'.join(module_parts[:-1])} import {module_name}_pb2 as _{module_name}_pb2") + elif module_path == "enum": + import_lines.append(f"from enum import Enum") + else: + # Go through all the types in the descriptor and add them to the import line + if descriptor.type == "": + import_line = f"import {'.'.join(module_parts[:])}" + else: + import_line = f"from {'.'.join(module_parts[:])} import {descriptor.type}" + if descriptor.replacement != "": + import_line += f" as {descriptor.replacement}" + import_lines.append(import_line) return "\n".join(import_lines) @@ -161,7 +204,9 @@ def parse_message_props(message): message.path = f"{namespace}.{message.parent + '.' if message.parent else ''}{message.name}" node = tree.search(message.path) for prop in message.properties: - property = get_property(prop, tree, node, node.imports, namespace) + if node.filespace == "MF.V3.Tasks.DownloadProject" and node.name == "Response" and prop.name == "State": + print("debug") + property = get_property(prop, tree, node, namespace) node.properties.append(property) for nested in message.nested_messages: parse_message_props(nested) @@ -175,15 +220,15 @@ def parse_message_props(message): request_base = procedure.request.rsplit('.', 1)[0] response_base = procedure.response.rsplit('.', 1)[0] - import_descriptor_request = get_descriptor_by_partial_name(request_base, node.imports) - import_descriptor_response = get_descriptor_by_partial_name(response_base, node.imports) + import_descriptor_request = get_descriptor_by_partial_filename(request_base, node.imports) + import_descriptor_response = get_descriptor_by_partial_filename(response_base, node.imports) # Check if the import descriptor is found and throw a message if not assert import_descriptor_request != None, f"Descriptor not found for {procedure.request}" assert import_descriptor_response != None, f"Descriptor not found for {procedure.response}" - import_descriptor_request.add_type(request_base, "") - import_descriptor_response.add_type(response_base, "") + node.imports.append(ImportDescriptor(import_descriptor_request.file, request_base, "")) + node.imports.append(ImportDescriptor(import_descriptor_response.file, response_base, "")) request_node = tree.search(import_descriptor_request.file) response_node = tree.search(import_descriptor_response.file) @@ -215,92 +260,46 @@ def add_indents(code: str, indent: int) -> str: # Indent the code by adding spaces if the line is not empty return "\n".join([f"{' ' * indent}{line}" if line.strip() else line for line in code.split("\n")]) -def get_property(property, tree: Tree, node:TreeNode, import_descriptors: List[ImportDescriptor], message_namespace:str) -> TreeProperty: +def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> TreeProperty: - tree_property = TreeProperty("", property.name, property.optional, parseComment(property.comment), property.repeated) + tree_property = TreeProperty(property.type, property.name, property.optional, parseComment(property.comment), property.repeated, None) + if property.type == "TaskState": + print("debug") - # Check to see if the property type can be mapped to a Python type + # 1 Check to see if property is a python type if property.type in type_mapping: tree_property.type = type_mapping.get(property.type, property.type) return tree_property - - property_type_parts = property.type.split('.') - - if len(property_type_parts) > 1: - # Combine message_namespace with property type - property_type_with_namespace = f"{message_namespace}.{property.type}" - - # Try getting the node directly - property_node = tree.search(property.type) - - # If the property node is not found, try getting the node with the namespace - if property_node == None: - property_node = tree.search(property_type_with_namespace) - if property_node == None: - property_node = node.climbing_search(property.type) - if property_node == None: - raise Exception("Property Type could not be resolved", property.type) - - if (property_node.filespace == node.filespace): - tree_property.type = f"'{property.type}'" + # 2 Check to see if the property is directly accessible + import_descriptor = ImportDescriptor(node.filespace, property.type.split(".")[0], "") + tree_property.import_descriptor = import_descriptor + + direct_node = tree.search(property.type) + if (direct_node): + import_descriptor.file = direct_node.filespace + return tree_property + + # 3 Check to see if the property type is in this file (get root node) + # - Is it a child of the node? + if node.has_child(property.type): + return tree_property + + # - Check if the property is a node of a parent + root_node = node + while root_node.parent.name != "root": + root_node = root_node.parent + if root_node.has_child(property.type) or root_node.name == property.type: + property_node = root_node.get_child(property.type) + import_descriptor.file = property_node.filespace return tree_property - - temp = property_node - while temp.parent.filespace == property_node.filespace: - temp = temp.parent - relativePath = property_node.get_relative_path(temp) - - descriptor = get_descriptor_by_name(property_node.filespace, import_descriptors) - # Make a unique name for the type based on the filespace and the property type - unique_name = f"{property.type}" - unique_name = unique_name.replace(".", "_") - - descriptor.add_type(temp.name, unique_name) - tree_property.import_descriptor = descriptor - tree_property.type = f"'{unique_name}'" + + # - Check if the property shares a namespace + property_type_with_namespace = f"{message_namespace}.{property.type}" + property_node = tree.search(property_type_with_namespace) + if property_node: + import_descriptor.file = property_node.filespace return tree_property - else: - - sibling_nodes = tree.get_nodes_with_filespace(node.filespace) - for sibling_node in sibling_nodes: - if sibling_node.has_child(property.type): - if sibling_node.parent.name == node.parent.name: - #true siblings - tree_property.type = f"'{property.type}'" - return tree_property - else: - tree_property.type = f"'{sibling_node.name}.{property.type}'" - return tree_property - elif sibling_node.name == property.type: - tree_property.type = f"'{property.type}'" - return tree_property - for descriptor in import_descriptors: - # Search for direct imports first - descriptor_file_node = tree.search(descriptor.file) - if descriptor_file_node: - if descriptor_file_node.name == property.type: - descriptor.add_type(property.type, "") - tree_property.import_descriptor = descriptor - tree_property.type = f"'{property.type}'" - return tree_property - for descriptor in import_descriptors: - # Search for imports with the same filespace - descriptor_file_nodes = tree.get_nodes_with_filespace(descriptor.file) - for descriptor_node in descriptor_file_nodes: - if descriptor_node == None: - continue - elif descriptor_node.name == property.type: - descriptor.add_type(property.type, "") - tree_property.import_descriptor = descriptor - tree_property.type = f"'{property.type}'" - return tree_property - elif descriptor_node.has_child(property.type): - descriptor.add_type(property.type, "") - tree_property.import_descriptor = descriptor - tree_property.type = f"'{property.type}'" - return tree_property - raise Exception("Property Type could not be resolved", property.type) @@ -308,11 +307,13 @@ def get_property(property, tree: Tree, node:TreeNode, import_descriptors: List[I def generate_class_code(current_node:TreeNode) -> str: if current_node.type == NodeType.Enum: - return generate_enum_code(current_node) + "\n\n" - + return generate_enum_code(current_node) + class_code = f"class {current_node.name}:\n" class_code += add_indents(current_node.comment,1) + if current_node.name == "DownloadProject": + print("debug") # Generate code for nested messages for child in current_node.children.values(): @@ -321,24 +322,27 @@ def generate_class_code(current_node:TreeNode) -> str: class_code += f"\n{nested_class_code}\n" class_code += " def __init__(self" - + if current_node.properties: # sort properties so optionals are last properties = sorted(current_node.properties, key=lambda x: x.optional) for prop in properties: + prop_type = prop.type + # Wrap the type in single quotes if it is a self referencing type + if prop.import_descriptor != None: + if prop.import_descriptor.file == current_node.filespace: + prop_type = f"'{prop.type}'" # handle repeated if prop.repeated: # Get importDescriptor for List "typing" - descriptor = get_descriptor_by_name("typing", current_node.imports) - if descriptor == None: - descriptor = ImportDescriptor("typing") - current_node.imports.append(descriptor) - descriptor.add_type("List", "") - class_code += f", {prop.name}:List[{prop.type}]" + + descriptor = ImportDescriptor("typing", "List", "") + current_node.imports.append(descriptor) + class_code += f", {prop.name}:List[{prop_type}]" else: - class_code += f", {prop.name}:{prop.type}" + class_code += f", {prop.name}:{prop_type}" # handle optionals if prop.optional: class_code += " = None" @@ -349,7 +353,7 @@ def generate_class_code(current_node:TreeNode) -> str: class_code += f"\n{add_indents(prop.comment,2)}" class_code += add_indents(f"self.{prop.name} = {prop.name}\n",2) else: - class_code += " pass\n" + class_code += "):\n pass\n" return class_code @@ -365,26 +369,29 @@ def generate_enum_code(enum:TreeNode) -> str: enum_code += f" {name} = \"{value.name}\" {value.comment}\n" return enum_code + def generate_service_code( current_node:TreeNode, tree:Tree) -> str: name = current_node.name service_code = f"class {name}:\n" + service_code += add_indents("_index = 0\n", 1) + service_code += add_indents(current_node.comment, 1) service_code += " def __init__(self):\n" service_code += " pass\n" for procedure in current_node.procedures: - - name = procedure.name + if procedure.name == "update_settings": + print("Debug") request_node = tree.search(procedure.request) response_node = tree.search(procedure.response) # create a method name from the name value, by adding underscores between camel case method_name = "" - for i, c in enumerate(name): + for i, c in enumerate(procedure.name): if c.isupper() and i != 0: method_name += "_" method_name += c.lower() @@ -393,26 +400,54 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: # loop over all the properties from the request node to get the input node method_properties = [] + + # Get the property that has the name Input for prop in request_node.properties: if prop.name == "Input": if prop.import_descriptor != None: + current_node.imports.append(prop.import_descriptor) input_node = tree.search(prop.import_descriptor.file) - print(f"Found input node: {prop.type}") for input_prop in input_node.properties: + # Check if the input_prop.type is not a python type + if input_prop.type not in python_types: + if input_prop.import_descriptor == None: + # Remove the single quotes and concat + input_prop.type = f"{prop.type}.{input_prop.type}" + else: + # find the matching type in import descriptor + t = [x for x in input_prop.import_descriptor.types if x['type'] == input_prop.type] + # if (t[0]['replacement'] != ""): + # t[0]['repl'] + method_properties.append(input_prop) else: method_properties.append(prop) + # Sort the properties so that optionals are last + method_properties = sorted(method_properties, key=lambda x: x.optional) + for prop in method_properties: service_code += f", {prop.name}:{prop.type}" + if prop.optional: + service_code += " = None" if prop.import_descriptor != None: current_node.imports.append(prop.import_descriptor) service_code += f"):\n" service_code += add_indents(procedure.comment,2) - service_code += f" {method_name}_request = {request_node.name}(\n" + service_code += f" {method_name}_request = {request_node.parent.name}.{request_node.name}(\n" for prop in request_node.properties: - service_code += f" {prop.name}={prop.name},\n" + if prop.name == "Input": + service_code += f" {prop.name}={prop.type}(\n" + for input_prop in method_properties: + service_code += f" {input_prop.name}={input_prop.name},\n" + service_code += " ),\n" + elif prop.name == "Type": + service_code += f" {prop.name}=\"{procedure.name}\",\n" + elif prop.name == "Index": + service_code += f" {prop.name}=self._index,\n" + else: + service_code += f" {prop.name}={prop.name},\n" service_code += " )\n" # Get the tree for the file # parent_node = tree.search(descriptor.file) @@ -445,6 +480,46 @@ def generate_init_files(paths: set, tree: Tree, output_dir: str): for import_path in imports: f.write(f"from {import_path} import * \n") +def check_undefined_names(file_path): + with open(file_path, 'r') as file: + tree = ast.parse(file.read(), filename=file_path) + + undefined_names = set() + defined_names = set() + + class NameVisitor(ast.NodeVisitor): + def visit_Name(self, node): + if isinstance(node.ctx, ast.Load): + if node.id not in defined_names and node.id not in dir(__builtins__): + undefined_names.add(node.id) + elif isinstance(node.ctx, ast.Store): + defined_names.add(node.id) + self.generic_visit(node) + + visitor = NameVisitor() + visitor.visit(tree) + + return undefined_names + +def run_flake8(file_path): + result = subprocess.run( + ['flake8', '--select=F', file_path], + capture_output=True, text=True + ) + return result.stdout + +def check_files(directory): + for root, _, files in os.walk(directory): + for file in files: + if file.endswith('.py'): + filepath = os.path.join(root, file) + # print(f"Running flake8 on {filepath}...") + flake8_output = run_flake8(filepath) + if flake8_output: + print(f"flake8 issues in {filepath}:\n{flake8_output}") + # else: + # print(f"No flake8 issues in {filepath}") + def main(): parser = argparse.ArgumentParser(description="Generate Python classes and enums from protobuf schema objects.") @@ -463,7 +538,11 @@ def main(): paths = generate_python_code(args.output_dir, tree) generate_init_files(paths, tree, args.output_dir) + check_files(args.output_dir) + + exit(0) if __name__ == "__main__": - main() \ No newline at end of file + main() + \ No newline at end of file diff --git a/scripts/tree.py b/scripts/tree.py index c5cc9d0..c02d8d1 100644 --- a/scripts/tree.py +++ b/scripts/tree.py @@ -2,7 +2,7 @@ from typing import List, Dict class TreeProperty: - def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated: bool, import_descriptor = None) -> None: + def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated: bool, import_descriptor:'ImportDescriptor') -> None: self.type: str = type_ self.name: str = name self.optional: bool = optional @@ -10,6 +10,7 @@ def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated self.comment: str = comment self.import_descriptor: ImportDescriptor = import_descriptor + class TreeProcedure: def __init__(self, name: str, request: str, response: str, comment: str) -> None: self.name: str = name @@ -43,9 +44,6 @@ def add_property(self, type_: str, name: str, optional: bool, comment: str, repe def add_procedure(self, name: str, request: str, response: str, comment: str) -> None: self.procedures.append(TreeProcedure(name, request, response, comment)) - - def add_import(self, import_path: str): - self.imports.append(ImportDescriptor(import_path)) def get_child(self, name: str): parts = name.split('.') @@ -171,26 +169,15 @@ def traverse_for_filespace(node: TreeNode): return branch_nodes class ImportDescriptor: - def __init__(self, file:str): + def __init__(self, file:str, type:str, replacement:str): self.file = file - self.types: List[dict[str,str]] = [] - def add_type(self, type:str, replacement:str): - # Check to see if the type is already in the list - for t in self.types: - if t["type"] == type: - return - self.types.append({"type":type, "replacement":replacement}) - -def get_descriptor_by_name(name: str, descriptors: List[dict]) -> ImportDescriptor: - for descriptor in descriptors: - if descriptor.file == name: - return descriptor - return None + self.type = type + self.replacement = replacement -def get_descriptor_by_partial_name(name, import_descriptors) -> ImportDescriptor: +def get_descriptor_by_partial_filename(filename, import_descriptors) -> ImportDescriptor: for descriptor in import_descriptors: # replace any . in name with / - nameAsPath = name.replace('.', '/') + nameAsPath = filename.replace('.', '/') # match nameAsPath against the last part of descriptor.file if descriptor.file.endswith(nameAsPath): return descriptor From bd2b38493ea1ce3ead0fe8decbe3ee98abd4265d Mon Sep 17 00:00:00 2001 From: Drew Shark Date: Tue, 24 Sep 2024 21:28:03 -0400 Subject: [PATCH 44/86] Better import lists --- scripts/transpileProto.py | 70 ++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index e3b47cd..230b498 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -127,34 +127,52 @@ def nested_imports(node) -> List[ImportDescriptor]: return unique_imports +class ImportList: + def __init__(self): + self.file:str = "" + self.types:List[Dict[str,str]] = [] + + def generate_import_lines(descriptorsLists:Dict[str, List[ImportDescriptor]]) -> str: import_lines = [] - for descriptors in descriptorsLists: - for combined in descriptors.values(): - # If single import, then just add the import line - # otherwise let's put them all on one line - - for descriptor in combined: - # Split the import path into parts - module_path = descriptor.file - module_parts = module_path.split('.') - module_name = module_parts[-1] - - # Special consideration for google imports and enum - if "google" in module_parts: - import_lines.append(f"from {'.'.join(module_parts[:-1])} import {module_name}_pb2 as _{module_name}_pb2") - elif module_path == "enum": - import_lines.append(f"from enum import Enum") - else: - # Go through all the types in the descriptor and add them to the import line - if descriptor.type == "": - import_line = f"import {'.'.join(module_parts[:])}" - else: - import_line = f"from {'.'.join(module_parts[:])} import {descriptor.type}" - if descriptor.replacement != "": - import_line += f" as {descriptor.replacement}" - import_lines.append(import_line) + ImportListArray = [] + for combined in descriptorsLists: + importList = ImportList() + importList.file = combined[0].file + for descriptor in combined: + importList.types.append({"type":descriptor.type, "replacement":descriptor.replacement}) + ImportListArray.append(importList) + + for importList in ImportListArray: + + if importList.file == "enum": + import_lines.append(f"from enum import Enum") + continue + if "google" in importList.file: + split = importList.file.split('.') + import_lines.append(f"from {'.'.join(split[:-1])} import {split[-1]}_pb2 as _{split[-1]}_pb2") + continue + + # remove duplicates from types + types = {} + for imp in importList.types: + if imp["type"] == "": + continue + types[imp["type"]] = imp["replacement"] + + if not types: + import_lines.append(f"import {importList.file}") + continue + + import_line = f"from {importList.file} import " + for i, (t, replacement) in enumerate(types.items()): + if i > 0: + import_line += ", " + import_line += f"{t}" + if replacement != "": + import_line += f" as {descriptor.replacement}" + import_lines.append(import_line) return "\n".join(import_lines) @@ -272,7 +290,7 @@ def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> return tree_property # 2 Check to see if the property is directly accessible - import_descriptor = ImportDescriptor(node.filespace, property.type.split(".")[0], "") + import_descriptor = ImportDescriptor(node.filespace, property.type.split(".")[-1], "") tree_property.import_descriptor = import_descriptor direct_node = tree.search(property.type) From ff3761d45a15d7371125a78bfa9324b562031bb2 Mon Sep 17 00:00:00 2001 From: Drew Shark Date: Tue, 24 Sep 2024 22:52:09 -0400 Subject: [PATCH 45/86] Chasing bug on import duplicates --- scripts/transpileProto.py | 10 ++++++++-- scripts/tree.py | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 230b498..6aa49f5 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -281,7 +281,7 @@ def add_indents(code: str, indent: int) -> str: def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> TreeProperty: tree_property = TreeProperty(property.type, property.name, property.optional, parseComment(property.comment), property.repeated, None) - if property.type == "TaskState": + if node.filespace == "MF.V3.Tasks.ListNetworkInterfaces" and node.name == "Response": print("debug") # 1 Check to see if property is a python type @@ -310,6 +310,12 @@ def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> if root_node.has_child(property.type) or root_node.name == property.type: property_node = root_node.get_child(property.type) import_descriptor.file = property_node.filespace + relative_path = property_node.get_relative_path_from_filespace() + import_descriptor.type = relative_path if relative_path != "" else property_node.name + if import_descriptor.file != node.filespace: + # replace all . with _ in the type + import_descriptor.replacement = property_node.get_path().replace(".", "_") + tree_property.type = import_descriptor.replacement return tree_property # - Check if the property shares a namespace @@ -556,7 +562,7 @@ def main(): paths = generate_python_code(args.output_dir, tree) generate_init_files(paths, tree, args.output_dir) - check_files(args.output_dir) + # check_files(args.output_dir) exit(0) diff --git a/scripts/tree.py b/scripts/tree.py index c02d8d1..e276e77 100644 --- a/scripts/tree.py +++ b/scripts/tree.py @@ -80,10 +80,20 @@ def get_relative_path(self, node): break path.append(current_node.name) current_node = current_node.parent - if current_node: - path.append(current_node.name) return '.'.join(reversed(path)) + def get_relative_path_from_filespace(self): + path = [] + current_node = self + while current_node: + if current_node.name == "root": + break + if current_node.filespace == None: + break + path.append(current_node.name) + current_node = current_node.parent + return '.'.join(reversed(path)) + def get_first_parent_with_name(self, name: str): # Break the name into parts top_name = name.split('.')[0] From 308fcd3e2737872a2c94dab7892628e09722fdef Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 25 Sep 2024 14:11:48 -0400 Subject: [PATCH 46/86] Property and importing on base classes clean --- scripts/transpileProto.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 6aa49f5..4857b08 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -71,7 +71,7 @@ def generate_python_code(output_dir: str, tree:Tree) -> set: # Get imports imports = get_imports_from_nodes(branch) - import_lines = generate_import_lines(imports) + import_lines = generate_import_lines(imports, branch[0].filespace) # Combine imports, message code, and enum code combined_code = import_lines + "\n\n" + class_code + "\n\n" + service_code @@ -124,7 +124,6 @@ def nested_imports(node) -> List[ImportDescriptor]: # Convert the dictionary to a list of lists unique_imports = list(grouped_imports.values()) - return unique_imports class ImportList: @@ -133,13 +132,15 @@ def __init__(self): self.types:List[Dict[str,str]] = [] -def generate_import_lines(descriptorsLists:Dict[str, List[ImportDescriptor]]) -> str: +def generate_import_lines(descriptorsLists:Dict[str, List[ImportDescriptor]], file_path:str) -> str: import_lines = [] ImportListArray = [] for combined in descriptorsLists: importList = ImportList() importList.file = combined[0].file + if (importList.file == file_path): + continue for descriptor in combined: importList.types.append({"type":descriptor.type, "replacement":descriptor.replacement}) ImportListArray.append(importList) @@ -161,6 +162,7 @@ def generate_import_lines(descriptorsLists:Dict[str, List[ImportDescriptor]]) -> continue types[imp["type"]] = imp["replacement"] + # If there are no types, just import the file if not types: import_lines.append(f"import {importList.file}") continue @@ -171,7 +173,7 @@ def generate_import_lines(descriptorsLists:Dict[str, List[ImportDescriptor]]) -> import_line += ", " import_line += f"{t}" if replacement != "": - import_line += f" as {descriptor.replacement}" + import_line += f" as {replacement}" import_lines.append(import_line) return "\n".join(import_lines) @@ -281,7 +283,7 @@ def add_indents(code: str, indent: int) -> str: def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> TreeProperty: tree_property = TreeProperty(property.type, property.name, property.optional, parseComment(property.comment), property.repeated, None) - if node.filespace == "MF.V3.Tasks.ListNetworkInterfaces" and node.name == "Response": + if node.filespace == "MF.V3.Descriptors.System" and node.name == "Package" and property.name == "name": print("debug") # 1 Check to see if property is a python type @@ -296,6 +298,11 @@ def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> direct_node = tree.search(property.type) if (direct_node): import_descriptor.file = direct_node.filespace + relative_path = direct_node.get_relative_path_from_filespace() + import_descriptor.type = relative_path if relative_path != "" else direct_node.name + import_descriptor.type = import_descriptor.type.split(".")[0] + # if import_descriptor.file != node.filespace: + tree_property.type = relative_path return tree_property # 3 Check to see if the property type is in this file (get root node) @@ -312,6 +319,7 @@ def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> import_descriptor.file = property_node.filespace relative_path = property_node.get_relative_path_from_filespace() import_descriptor.type = relative_path if relative_path != "" else property_node.name + tree_property.type = import_descriptor.type if import_descriptor.file != node.filespace: # replace all . with _ in the type import_descriptor.replacement = property_node.get_path().replace(".", "_") @@ -535,7 +543,7 @@ def run_flake8(file_path): def check_files(directory): for root, _, files in os.walk(directory): for file in files: - if file.endswith('.py'): + if file.endswith('.py') and file != '__init__.py': filepath = os.path.join(root, file) # print(f"Running flake8 on {filepath}...") flake8_output = run_flake8(filepath) @@ -562,7 +570,7 @@ def main(): paths = generate_python_code(args.output_dir, tree) generate_init_files(paths, tree, args.output_dir) - # check_files(args.output_dir) + check_files(args.output_dir+"/MF/V3/") exit(0) From accf9f8dc0e463564f744d92ff87ad10052f6af5 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 25 Sep 2024 14:51:16 -0400 Subject: [PATCH 47/86] Cleanup and comments. Moving to Services --- scripts/transpileProto.py | 107 +++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 37 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 4857b08..7998142 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -39,6 +39,12 @@ def generate_python_code(output_dir: str, tree:Tree) -> set: + """ + Generate Python code from the tree structure. + This method looks at messages, enums, and services and generates Python code for them. + Then produces the imports for the files + Then finally writes the code to the files. + """ # create a unique set of paths paths = set() @@ -82,23 +88,11 @@ def generate_python_code(output_dir: str, tree:Tree) -> set: return paths -def get_imports(imports: List[str]) -> List[ImportDescriptor]: - module_parts_list:List[ImportDescriptor] = [] - - for imp in imports: - # Split the import path into parts - module_path = os.path.splitext(imp.replace('/', '.'))[0] - # Check module_parts_list for existing module by filename - foundModule = None - for module in module_parts_list: - if module.file == module_path: - foundModule = module - break - if foundModule == None: - module_parts_list.append(ImportDescriptor(module_path, "", "")) - return module_parts_list - def get_imports_from_nodes(nodes:List[TreeNode]) -> Dict[str, List[ImportDescriptor]]: + """ + Get the import descriptors from a list of nodes. + This will also create base descriptors for the properties + """ imports = [] for node in nodes: def nested_imports(node) -> List[ImportDescriptor]: @@ -133,6 +127,9 @@ def __init__(self): def generate_import_lines(descriptorsLists:Dict[str, List[ImportDescriptor]], file_path:str) -> str: + """ + Generate import lines from a list of import descriptors. + """ import_lines = [] ImportListArray = [] @@ -178,20 +175,43 @@ def generate_import_lines(descriptorsLists:Dict[str, List[ImportDescriptor]], fi return "\n".join(import_lines) + +def get_imports(imports: List[str]) -> List[ImportDescriptor]: + """ + Get the import descriptors from a list of import paths. + This is the first step in linking the properties in the tree. + """ + module_parts_list:List[ImportDescriptor] = [] + + for imp in imports: + # Split the import path into parts + module_path = os.path.splitext(imp.replace('/', '.'))[0] + # Check module_parts_list for existing module by filename + foundModule = None + for module in module_parts_list: + if module.file == module_path: + foundModule = module + break + if foundModule == None: + module_parts_list.append(ImportDescriptor(module_path, "", "")) + return module_parts_list + def get_tree(proto_objects: List)-> Tree: + """ + Get's the tree structure of the proto objects + We use this for a proper reference to the objects that are created afterwards + """ + tree = Tree() - # We need to go through the proto_objects twice. - # First to build the base tree - + # We need to go through the proto_objects twice to build the tree properly. + # First to build the base tree without properties for obj in proto_objects: namespace = obj['namespace'] imports = obj['imports'] importDescs = get_imports(imports) filespace = obj['filename'].replace('/', '.').replace('.proto', '') - if obj['filename'] == "MF/V3/Descriptors/ProjectActions.proto": - print("Debug") for msg in obj['messages']: def get_nested_messages(message, nested_name_space): @@ -224,8 +244,6 @@ def parse_message_props(message): message.path = f"{namespace}.{message.parent + '.' if message.parent else ''}{message.name}" node = tree.search(message.path) for prop in message.properties: - if node.filespace == "MF.V3.Tasks.DownloadProject" and node.name == "Response" and prop.name == "State": - print("debug") property = get_property(prop, tree, node, namespace) node.properties.append(property) for nested in message.nested_messages: @@ -253,7 +271,7 @@ def parse_message_props(message): request_node = tree.search(import_descriptor_request.file) response_node = tree.search(import_descriptor_response.file) - # Check if the nodes are valid + # Check if the nodes are valid. Otherwise we're making some big assumptions assert request_node != None, f"Node not found for {procedure.request}" assert response_node != None, f"Node not found for {procedure.response}" @@ -265,6 +283,9 @@ def parse_message_props(message): return tree def parseComment(comment: str) -> str: + """ + Simply parse the comment and return it, wrapping multi lines or single lines appropriately + """ if comment != "": if len(comment.split('\n')) > 1: class_code = f'"""{comment}"""\n' @@ -277,24 +298,28 @@ def parseComment(comment: str) -> str: return class_code def add_indents(code: str, indent: int) -> str: + """ + Add indents to the code + """ # Indent the code by adding spaces if the line is not empty return "\n".join([f"{' ' * indent}{line}" if line.strip() else line for line in code.split("\n")]) def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> TreeProperty: - + """ + Get the property from the property object. This is complicated as the property could be self referencing, part of the parent class, or from an external import + """ tree_property = TreeProperty(property.type, property.name, property.optional, parseComment(property.comment), property.repeated, None) - if node.filespace == "MF.V3.Descriptors.System" and node.name == "Package" and property.name == "name": - print("debug") # 1 Check to see if property is a python type if property.type in type_mapping: tree_property.type = type_mapping.get(property.type, property.type) return tree_property - # 2 Check to see if the property is directly accessible + import_descriptor = ImportDescriptor(node.filespace, property.type.split(".")[-1], "") tree_property.import_descriptor = import_descriptor + # 2 Check to see if the property is directly accessible direct_node = tree.search(property.type) if (direct_node): import_descriptor.file = direct_node.filespace @@ -337,16 +362,16 @@ def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> def generate_class_code(current_node:TreeNode) -> str: - + """ + Generate the class code for a node in the tree. This is recursive for children nodes. + """ if current_node.type == NodeType.Enum: return generate_enum_code(current_node) class_code = f"class {current_node.name}:\n" class_code += add_indents(current_node.comment,1) - if current_node.name == "DownloadProject": - print("debug") - + # Generate code for nested messages for child in current_node.children.values(): nested_class_code = generate_class_code(child) @@ -393,7 +418,10 @@ def generate_class_code(current_node:TreeNode) -> str: "None": "Empty", } -def generate_enum_code(enum:TreeNode) -> str: +def generate_enum_code(enum:TreeNode) -> str: + """ + Generate the enum code for a node in the tree. + """ enum_code = enum.comment enum_code += f"class {enum.name}(Enum):\n" for value in enum.properties: @@ -403,6 +431,9 @@ def generate_enum_code(enum:TreeNode) -> str: def generate_service_code( current_node:TreeNode, tree:Tree) -> str: + """ + Generate the service code for a node in the tree. + """ name = current_node.name @@ -415,9 +446,7 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: service_code += " pass\n" for procedure in current_node.procedures: - if procedure.name == "update_settings": - print("Debug") - + request_node = tree.search(procedure.request) response_node = tree.search(procedure.response) @@ -493,6 +522,9 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: return service_code def generate_init_files(paths: set, tree: Tree, output_dir: str): + """ + Generates init files for use when accessing the classes and enums as a package + """ for path in paths: init_file = os.path.join(path, "__init__.py") @@ -512,6 +544,8 @@ def generate_init_files(paths: set, tree: Tree, output_dir: str): for import_path in imports: f.write(f"from {import_path} import * \n") + +# Checking files for consistency after building def check_undefined_names(file_path): with open(file_path, 'r') as file: tree = ast.parse(file.read(), filename=file_path) @@ -572,7 +606,6 @@ def main(): check_files(args.output_dir+"/MF/V3/") - exit(0) if __name__ == "__main__": From d346d60299334604e2e772547ba9f86605c563ff Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 25 Sep 2024 17:08:00 -0400 Subject: [PATCH 48/86] Creating Service Objects Requests for convencience methods --- scripts/transpileProto.py | 148 +++++++++++++++++++++++++------------- scripts/tree.py | 14 ++-- 2 files changed, 106 insertions(+), 56 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 7998142..232270d 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -71,8 +71,8 @@ def generate_python_code(output_dir: str, tree:Tree) -> set: for node in branch: if node.type == NodeType.Class or node.type == NodeType.Enum: class_code += generate_class_code(node) + "\n\n" - # elif node.type == NodeType.Service: - # service_code += generate_service_code(node, tree) + "\n\n" + elif node.type == NodeType.Service: + service_code += generate_service_code(node, tree) + "\n\n" # Get imports imports = get_imports_from_nodes(branch) @@ -254,6 +254,7 @@ def parse_message_props(message): service_path = f"{namespace}.{service.name}" node = tree.search(service_path) for procedure in service.procedures: + # Remove only the last word from procedure.request and procedure.response request_base = procedure.request.rsplit('.', 1)[0] response_base = procedure.response.rsplit('.', 1)[0] @@ -264,22 +265,22 @@ def parse_message_props(message): # Check if the import descriptor is found and throw a message if not assert import_descriptor_request != None, f"Descriptor not found for {procedure.request}" assert import_descriptor_response != None, f"Descriptor not found for {procedure.response}" - - node.imports.append(ImportDescriptor(import_descriptor_request.file, request_base, "")) - node.imports.append(ImportDescriptor(import_descriptor_response.file, response_base, "")) - request_node = tree.search(import_descriptor_request.file) - response_node = tree.search(import_descriptor_response.file) + request_root_node = tree.search(import_descriptor_request.file) + response_root_node = tree.search(import_descriptor_response.file) # Check if the nodes are valid. Otherwise we're making some big assumptions - assert request_node != None, f"Node not found for {procedure.request}" - assert response_node != None, f"Node not found for {procedure.response}" + assert request_root_node != None, f"Node not found for {procedure.request}" + assert response_root_node != None, f"Node not found for {procedure.response}" + + request_node = request_root_node.get_child("Request") + response_node = response_root_node.get_child("Response") - assert request_node.has_child("Request"), f"Request node not found for {procedure.request}" - assert response_node.has_child("Response"), f"Response node not found for {procedure.response}" + assert request_node, f"Request node not found for {procedure.request}" + assert response_node, f"Response node not found for {procedure.response}" # Add the procedure - node.add_procedure(procedure.name, request_node.get_child("Request").get_path(), response_node.get_child("Response").get_path(), parseComment(procedure.comment)) + node.add_procedure(procedure.name, request_node, response_node, parseComment(procedure.comment), import_descriptor_request, import_descriptor_response) return tree def parseComment(comment: str) -> str: @@ -347,7 +348,7 @@ def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> tree_property.type = import_descriptor.type if import_descriptor.file != node.filespace: # replace all . with _ in the type - import_descriptor.replacement = property_node.get_path().replace(".", "_") + import_descriptor.replacement = get_replacement_name(property_node) tree_property.type = import_descriptor.replacement return tree_property @@ -430,13 +431,16 @@ def generate_enum_code(enum:TreeNode) -> str: return enum_code +def get_replacement_name(node:TreeNode) -> str: + replacement_name = node.get_path().replace(".", "_") + return replacement_name + def generate_service_code( current_node:TreeNode, tree:Tree) -> str: """ Generate the service code for a node in the tree. """ name = current_node.name - service_code = f"class {name}:\n" service_code += add_indents("_index = 0\n", 1) @@ -447,8 +451,8 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: for procedure in current_node.procedures: - request_node = tree.search(procedure.request) - response_node = tree.search(procedure.response) + request_node = procedure.request + response_node = procedure.response # create a method name from the name value, by adding underscores between camel case method_name = "" @@ -461,29 +465,52 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: # loop over all the properties from the request node to get the input node method_properties = [] - - # Get the property that has the name Input + # Parse the request properties for convenience to the user for prop in request_node.properties: if prop.name == "Input": if prop.import_descriptor != None: - current_node.imports.append(prop.import_descriptor) + # Get the input node from the tree input_node = tree.search(prop.import_descriptor.file) + + # Create a new import descriptor because we're going to change the replacement name to avoid conflicts + prop.import_descriptor.replacement = get_replacement_name(input_node); + prop.type = prop.import_descriptor.replacement + # Add the import descriptor to the current node imports + current_node.imports.append(prop.import_descriptor) + + # Loop over the properties of the input node + # We need to make the convenience call easier than just the Request itself for input_prop in input_node.properties: # Check if the input_prop.type is not a python type - if input_prop.type not in python_types: - if input_prop.import_descriptor == None: - # Remove the single quotes and concat - input_prop.type = f"{prop.type}.{input_prop.type}" - else: - # find the matching type in import descriptor - t = [x for x in input_prop.import_descriptor.types if x['type'] == input_prop.type] - # if (t[0]['replacement'] != ""): - # t[0]['repl'] - - method_properties.append(input_prop) + if input_prop.type in python_types: + method_properties.append(input_prop) + continue; + if input_prop.import_descriptor == None: + print("debug") + if input_prop.import_descriptor != None and input_prop.import_descriptor.replacement == "": + import_file_node = tree.search(input_prop.import_descriptor.file) + import_node = import_file_node.get_child(input_prop.type) + assert(import_node != None) + relative_path = import_node.get_relative_path_from_filespace() + replacement_name = get_replacement_name(import_file_node) + new_descriptor = ImportDescriptor(import_node.filespace, relative_path.split(".")[0], replacement_name) + + #make a new property name by replacing the first part of the relative_path with replacement_name + split_relative_path = relative_path.split(".") + split_relative_path[0] = replacement_name + new_property_name = ".".join(split_relative_path) + + prop = TreeProperty(new_property_name,input_prop.name, input_prop.optional, input_prop.comment, input_prop.repeated, new_descriptor) + method_properties.append(prop) + continue; + else: + + method_properties.append(input_prop) else: method_properties.append(prop) + + # Sort the properties so that optionals are last method_properties = sorted(method_properties, key=lambda x: x.optional) @@ -496,29 +523,50 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: service_code += f"):\n" service_code += add_indents(procedure.comment,2) - service_code += f" {method_name}_request = {request_node.parent.name}.{request_node.name}(\n" - for prop in request_node.properties: - if prop.name == "Input": - service_code += f" {prop.name}={prop.type}(\n" - for input_prop in method_properties: - service_code += f" {input_prop.name}={input_prop.name},\n" - service_code += " ),\n" - elif prop.name == "Type": - service_code += f" {prop.name}=\"{procedure.name}\",\n" - elif prop.name == "Index": - service_code += f" {prop.name}=self._index,\n" - else: - service_code += f" {prop.name}={prop.name},\n" - service_code += " )\n" - # Get the tree for the file - # parent_node = tree.search(descriptor.file) - # request_node = parent_node.get_child("Request") - # response_node = parent_node.get_child("Response") - # if request == None: - # request = "Empty" + def create_object_code(node:TreeNode, postfix:str)->str: + code = "" + # Get the request node from the tree + request_filespace_node = tree.search(node.filespace) + req_filespace_replacement_name = get_replacement_name(request_filespace_node) + + # Get the relative path of the request node + rel_path = node.get_relative_path_from_filespace() + # Replace the first part of the relative path with the replacement name + split_relative_request_path = rel_path.split(".") + split_relative_request_path[0] = req_filespace_replacement_name + new_request_property_name = ".".join(split_relative_request_path) + + # Update the node import_descriptor to have a replacement name + procedure.request_import.replacement = req_filespace_replacement_name + procedure.request_import.type = request_filespace_node.name + + current_node.imports.append(procedure.request_import) + + code += f" {method_name}_{postfix} = {new_request_property_name}(" + for i, prop in enumerate(node.properties): + if i>0: + code += "," + code += "\n" + + if prop.name == "Input": + code += f" {prop.name}={prop.type}(\n" + for input_prop in method_properties: + code += f" {input_prop.name}={input_prop.name},\n" + code += " )" + elif prop.name == "Type": + code += f" {prop.name}=\"{procedure.name}\"" + elif prop.name == "Index": + code += f" {prop.name}=self._index" + else: + code += f" {prop.name}={prop.name}" + code += "\n )\n" + return code + service_code += create_object_code(request_node, "request") + # service_code += create_object_code(response_node, "response") + return service_code def generate_init_files(paths: set, tree: Tree, output_dir: str): diff --git a/scripts/tree.py b/scripts/tree.py index e276e77..d4c1097 100644 --- a/scripts/tree.py +++ b/scripts/tree.py @@ -12,11 +12,13 @@ def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated class TreeProcedure: - def __init__(self, name: str, request: str, response: str, comment: str) -> None: + def __init__(self, name: str, request: 'TreeNode', response: 'TreeNode', comment: str, request_import: 'ImportDescriptor', response_import: 'ImportDescriptor') -> None: self.name: str = name self.request: str = request self.response: str = response self.comment: str = comment + self.request_import: ImportDescriptor = request_import + self.response_import: ImportDescriptor = response_import class NodeType(Enum): Class = "Class" @@ -42,8 +44,8 @@ def add_child(self, child_node): def add_property(self, type_: str, name: str, optional: bool, comment: str, repeated: bool) -> None: self.properties.append(TreeProperty(type_, name, optional, comment, repeated)) - def add_procedure(self, name: str, request: str, response: str, comment: str) -> None: - self.procedures.append(TreeProcedure(name, request, response, comment)) + def add_procedure(self, name: str, request: 'TreeNode', response: 'TreeNode', comment: str, request_import: 'ImportDescriptor', response_import: 'ImportDescriptor') -> None: + self.procedures.append(TreeProcedure(name, request, response, comment, request_import, response_import)) def get_child(self, name: str): parts = name.split('.') @@ -185,10 +187,10 @@ def __init__(self, file:str, type:str, replacement:str): self.replacement = replacement def get_descriptor_by_partial_filename(filename, import_descriptors) -> ImportDescriptor: + for descriptor in import_descriptors: - # replace any . in name with / - nameAsPath = filename.replace('.', '/') + split_descriptor = descriptor.file.split('.') # match nameAsPath against the last part of descriptor.file - if descriptor.file.endswith(nameAsPath): + if split_descriptor[-1] == filename: return descriptor return None \ No newline at end of file From 03818cd1dafb1ad42c887be4fe2b8c10b178b262 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 26 Sep 2024 11:24:06 -0400 Subject: [PATCH 49/86] Cleanup propertys with nested names --- scripts/transpileProto.py | 52 +++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 232270d..75fba57 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -344,12 +344,20 @@ def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> property_node = root_node.get_child(property.type) import_descriptor.file = property_node.filespace relative_path = property_node.get_relative_path_from_filespace() - import_descriptor.type = relative_path if relative_path != "" else property_node.name - tree_property.type = import_descriptor.type + full_type = relative_path if relative_path != "" else property_node.name + + split = full_type.split(".") + import_descriptor.type = split[0] + remaining = ".".join(split[1:]) + + tree_property.type = full_type if import_descriptor.file != node.filespace: # replace all . with _ in the type - import_descriptor.replacement = get_replacement_name(property_node) + import_descriptor.replacement = get_replacement_name(import_descriptor.file) tree_property.type = import_descriptor.replacement + if (remaining != ""): + tree_property.type += "." + remaining + return tree_property # - Check if the property shares a namespace @@ -431,9 +439,9 @@ def generate_enum_code(enum:TreeNode) -> str: return enum_code -def get_replacement_name(node:TreeNode) -> str: - replacement_name = node.get_path().replace(".", "_") - return replacement_name +def get_replacement_name(path:str) -> str: + return path.replace(".", "_") + def generate_service_code( current_node:TreeNode, tree:Tree) -> str: """ @@ -473,7 +481,7 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: input_node = tree.search(prop.import_descriptor.file) # Create a new import descriptor because we're going to change the replacement name to avoid conflicts - prop.import_descriptor.replacement = get_replacement_name(input_node); + prop.import_descriptor.replacement = get_replacement_name(input_node.get_path()); prop.type = prop.import_descriptor.replacement # Add the import descriptor to the current node imports current_node.imports.append(prop.import_descriptor) @@ -492,7 +500,7 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: import_node = import_file_node.get_child(input_prop.type) assert(import_node != None) relative_path = import_node.get_relative_path_from_filespace() - replacement_name = get_replacement_name(import_file_node) + replacement_name = get_replacement_name(import_file_node.get_path()) new_descriptor = ImportDescriptor(import_node.filespace, relative_path.split(".")[0], replacement_name) #make a new property name by replacing the first part of the relative_path with replacement_name @@ -525,11 +533,11 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: service_code += add_indents(procedure.comment,2) - def create_object_code(node:TreeNode, postfix:str)->str: + def create_object_code(node:TreeNode, postfix:str, ignore_optionals:bool)->str: code = "" # Get the request node from the tree request_filespace_node = tree.search(node.filespace) - req_filespace_replacement_name = get_replacement_name(request_filespace_node) + req_filespace_replacement_name = get_replacement_name(request_filespace_node.get_path()) # Get the relative path of the request node rel_path = node.get_relative_path_from_filespace() @@ -546,15 +554,20 @@ def create_object_code(node:TreeNode, postfix:str)->str: code += f" {method_name}_{postfix} = {new_request_property_name}(" for i, prop in enumerate(node.properties): + if (prop.optional and ignore_optionals): + continue if i>0: code += "," - code += "\n" - + code += "\n" if prop.name == "Input": - code += f" {prop.name}={prop.type}(\n" - for input_prop in method_properties: - code += f" {input_prop.name}={input_prop.name},\n" - code += " )" + # some property types are python types, so we need to handle them differently + if len(method_properties) == 1 and method_properties[0].type in python_types: + code += f" {method_properties[0].name}={method_properties[0].name}" + else: # multiple properties will result in a complicated type + code += f" {prop.name}={prop.type}(\n" + for input_prop in method_properties: + code += f" {input_prop.name}={input_prop.name},\n" + code += " )" elif prop.name == "Type": code += f" {prop.name}=\"{procedure.name}\"" elif prop.name == "Index": @@ -564,8 +577,9 @@ def create_object_code(node:TreeNode, postfix:str)->str: code += "\n )\n" return code - service_code += create_object_code(request_node, "request") - # service_code += create_object_code(response_node, "response") + + service_code += create_object_code(request_node, "request", False) + service_code += create_object_code(response_node, "response", True) return service_code @@ -617,7 +631,7 @@ def visit_Name(self, node): def run_flake8(file_path): result = subprocess.run( - ['flake8', '--select=F', file_path], + ['flake8', '--select=E,F', file_path], capture_output=True, text=True ) return result.stdout From 3d387e2843ab91283bd9672ad316755dfe36d9ed Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 26 Sep 2024 11:30:31 -0400 Subject: [PATCH 50/86] update check to auto lint and ignore long lines --- scripts/transpileProto.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 75fba57..78f48ac 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -406,9 +406,9 @@ def generate_class_code(current_node:TreeNode) -> str: descriptor = ImportDescriptor("typing", "List", "") current_node.imports.append(descriptor) - class_code += f", {prop.name}:List[{prop_type}]" + class_code += f", {prop.name}: List[{prop_type}]" else: - class_code += f", {prop.name}:{prop_type}" + class_code += f", {prop.name}: {prop_type}" # handle optionals if prop.optional: class_code += " = None" @@ -631,7 +631,14 @@ def visit_Name(self, node): def run_flake8(file_path): result = subprocess.run( - ['flake8', '--select=E,F', file_path], + ['flake8', '--select=E,F', '--ignore=E501', file_path], + capture_output=True, text=True + ) + return result.stdout + +def run_black(file_path): + result = subprocess.run( + ['black', file_path], capture_output=True, text=True ) return result.stdout @@ -642,6 +649,9 @@ def check_files(directory): if file.endswith('.py') and file != '__init__.py': filepath = os.path.join(root, file) # print(f"Running flake8 on {filepath}...") + black_output = run_black(filepath) + if black_output: + print(f"black {filepath}:\n{black_output}") flake8_output = run_flake8(filepath) if flake8_output: print(f"flake8 issues in {filepath}:\n{flake8_output}") From 1995444f32324eadec9da0a020c777a5d1d4e03e Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 26 Sep 2024 12:16:57 -0400 Subject: [PATCH 51/86] Linting fixes --- scripts/transpileProto.py | 56 ++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 78f48ac..ceda376 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -80,7 +80,13 @@ def generate_python_code(output_dir: str, tree:Tree) -> set: import_lines = generate_import_lines(imports, branch[0].filespace) # Combine imports, message code, and enum code - combined_code = import_lines + "\n\n" + class_code + "\n\n" + service_code + combined_code = "" + if (import_lines != ""): + combined_code = import_lines + "\n\n\n" + if (class_code != ""): + combined_code += class_code + if (service_code != ""): + combined_code += "\n" + service_code # Write the combined code to a file with the name from the file_path with open(file_path, 'w') as f: @@ -157,6 +163,10 @@ def generate_import_lines(descriptorsLists:Dict[str, List[ImportDescriptor]], fi for imp in importList.types: if imp["type"] == "": continue + # if types already has the type, check to see if the values will be the same. Throw an error if they are not + # if imp["type"] in types: + # if types[imp["type"]] != imp["replacement"]: + # raise Exception(f"Type {imp['type']} has multiple replacements {types[imp['type']]} and {imp['replacement']}") types[imp["type"]] = imp["replacement"] # If there are no types, just import the file @@ -289,14 +299,14 @@ def parseComment(comment: str) -> str: """ if comment != "": if len(comment.split('\n')) > 1: - class_code = f'"""{comment}"""\n' + comment_code = f'"""{comment}"""\n' else: # remove initial whitespace in comment comment = comment.strip() - class_code = f'# {comment}\n' + comment_code = f'# {comment}\n' else: - class_code = '\n' - return class_code + return "" + return comment_code def add_indents(code: str, indent: int) -> str: """ @@ -315,7 +325,10 @@ def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> if property.type in type_mapping: tree_property.type = type_mapping.get(property.type, property.type) return tree_property - + + if (node.filespace == "MF.V3.Tasks.BoundingBox"): + print("debug") + import_descriptor = ImportDescriptor(node.filespace, property.type.split(".")[-1], "") tree_property.import_descriptor = import_descriptor @@ -353,7 +366,7 @@ def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> tree_property.type = full_type if import_descriptor.file != node.filespace: # replace all . with _ in the type - import_descriptor.replacement = get_replacement_name(import_descriptor.file) + import_descriptor.replacement = get_replacement_name( property_node.filespace + "." + import_descriptor.type ) tree_property.type = import_descriptor.replacement if (remaining != ""): tree_property.type += "." + remaining @@ -385,13 +398,14 @@ def generate_class_code(current_node:TreeNode) -> str: for child in current_node.children.values(): nested_class_code = generate_class_code(child) nested_class_code = add_indents(nested_class_code,1) - class_code += f"\n{nested_class_code}\n" + class_code += f"{nested_class_code}\n" class_code += " def __init__(self" if current_node.properties: # sort properties so optionals are last properties = sorted(current_node.properties, key=lambda x: x.optional) + # Class init arguments for prop in properties: prop_type = prop.type @@ -413,13 +427,14 @@ def generate_class_code(current_node:TreeNode) -> str: if prop.optional: class_code += " = None" class_code += "):\n" + # Internal properties assignment for prop in properties: # Add comments with spaces if prop.comment: - class_code += f"\n{add_indents(prop.comment,2)}" + class_code += f"{add_indents(prop.comment,2)}" class_code += add_indents(f"self.{prop.name} = {prop.name}\n",2) else: - class_code += "):\n pass\n" + class_code += "):\n pass" return class_code @@ -435,7 +450,11 @@ def generate_enum_code(enum:TreeNode) -> str: enum_code += f"class {enum.name}(Enum):\n" for value in enum.properties: name = name_mapping.get(value.name, value.name) - enum_code += f" {name} = \"{value.name}\" {value.comment}\n" + enum_code += f" {name} = \"{value.name}\"" + if value.comment != "": + enum_code += f" {value.comment}" + else: + enum_code += "\n" return enum_code @@ -481,7 +500,8 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: input_node = tree.search(prop.import_descriptor.file) # Create a new import descriptor because we're going to change the replacement name to avoid conflicts - prop.import_descriptor.replacement = get_replacement_name(input_node.get_path()); + if prop.import_descriptor.replacement == "": + prop.import_descriptor.replacement = get_replacement_name(input_node.get_path()); prop.type = prop.import_descriptor.replacement # Add the import descriptor to the current node imports current_node.imports.append(prop.import_descriptor) @@ -636,27 +656,15 @@ def run_flake8(file_path): ) return result.stdout -def run_black(file_path): - result = subprocess.run( - ['black', file_path], - capture_output=True, text=True - ) - return result.stdout - def check_files(directory): for root, _, files in os.walk(directory): for file in files: if file.endswith('.py') and file != '__init__.py': filepath = os.path.join(root, file) # print(f"Running flake8 on {filepath}...") - black_output = run_black(filepath) - if black_output: - print(f"black {filepath}:\n{black_output}") flake8_output = run_flake8(filepath) if flake8_output: print(f"flake8 issues in {filepath}:\n{flake8_output}") - # else: - # print(f"No flake8 issues in {filepath}") def main(): From d8b3e2893f027accd5e85ff8f92b2c56bac76397 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 26 Sep 2024 17:30:35 -0400 Subject: [PATCH 52/86] Three.py building requests and responses --- maf_three/scanner_functions.py | 3 ++- scripts/transpileProto.py | 31 +++++++++++++++++++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/maf_three/scanner_functions.py b/maf_three/scanner_functions.py index 41e1c4d..38bde5a 100644 --- a/maf_three/scanner_functions.py +++ b/maf_three/scanner_functions.py @@ -1,4 +1,5 @@ -from MF.V3.Tasks.SetProjector import SetProjector, Projector +from MF.V3.Tasks.SetProjector import SetProjector +from MF.V3.Settings.Projector import Projector from MF.V3 import Task from typing import List diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index ceda376..738574f 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -470,8 +470,6 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: service_code = f"class {name}:\n" - service_code += add_indents("_index = 0\n", 1) - service_code += add_indents(current_node.comment, 1) service_code += " def __init__(self):\n" service_code += " pass\n" @@ -521,6 +519,11 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: assert(import_node != None) relative_path = import_node.get_relative_path_from_filespace() replacement_name = get_replacement_name(import_file_node.get_path()) + for imp in current_node.imports: + if imp.file == import_node.filespace: + if imp.replacement != "": + replacement_name = imp.replacement + new_descriptor = ImportDescriptor(import_node.filespace, relative_path.split(".")[0], replacement_name) #make a new property name by replacing the first part of the relative_path with replacement_name @@ -532,7 +535,7 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: method_properties.append(prop) continue; else: - + assert(input_prop.import_descriptor != None) method_properties.append(input_prop) else: method_properties.append(prop) @@ -555,20 +558,24 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: def create_object_code(node:TreeNode, postfix:str, ignore_optionals:bool)->str: code = "" - # Get the request node from the tree - request_filespace_node = tree.search(node.filespace) - req_filespace_replacement_name = get_replacement_name(request_filespace_node.get_path()) + + if (procedure.name == "DepthMap"): + print("debug") + # Get the Request Or Response node from the tree + filespace_node = tree.search(node.filespace) + filespace_replacement_name = get_replacement_name(filespace_node.get_path()) - # Get the relative path of the request node + # Get the relative path of the node rel_path = node.get_relative_path_from_filespace() + # Replace the first part of the relative path with the replacement name split_relative_request_path = rel_path.split(".") - split_relative_request_path[0] = req_filespace_replacement_name + split_relative_request_path[0] = filespace_replacement_name new_request_property_name = ".".join(split_relative_request_path) # Update the node import_descriptor to have a replacement name - procedure.request_import.replacement = req_filespace_replacement_name - procedure.request_import.type = request_filespace_node.name + procedure.request_import.replacement = filespace_replacement_name + procedure.request_import.type = filespace_node.name current_node.imports.append(procedure.request_import) @@ -591,9 +598,9 @@ def create_object_code(node:TreeNode, postfix:str, ignore_optionals:bool)->str: elif prop.name == "Type": code += f" {prop.name}=\"{procedure.name}\"" elif prop.name == "Index": - code += f" {prop.name}=self._index" + code += f" {prop.name}=0" else: - code += f" {prop.name}={prop.name}" + code += f" {prop.name}=None" code += "\n )\n" return code From 19356300f405fe3b4c331a90c1f3dbca074ba783 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 27 Sep 2024 14:40:50 -0400 Subject: [PATCH 53/86] Convenience methods written --- scripts/transpileProto.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 738574f..94b9d20 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -86,7 +86,7 @@ def generate_python_code(output_dir: str, tree:Tree) -> set: if (class_code != ""): combined_code += class_code if (service_code != ""): - combined_code += "\n" + service_code + combined_code += service_code # Write the combined code to a file with the name from the file_path with open(file_path, 'w') as f: @@ -468,11 +468,17 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: """ name = current_node.name + task_descriptor = get_descriptor_by_partial_filename("Task", current_node.imports) + if task_descriptor == None: + task_descriptor = ImportDescriptor("MF.V3", "Task", "") + current_node.imports.append(task_descriptor) + task_name = task_descriptor.replacement if task_descriptor.replacement != '' else task_descriptor.type + service_code = f"class {name}:\n" service_code += add_indents(current_node.comment, 1) service_code += " def __init__(self):\n" - service_code += " pass\n" + service_code += " pass\n\n" for procedure in current_node.procedures: @@ -486,7 +492,7 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: method_name += "_" method_name += c.lower() - service_code += f" def {method_name}(self" + service_code += f" def {method_name}(scanner" # loop over all the properties from the request node to get the input node method_properties = [] @@ -511,8 +517,7 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: if input_prop.type in python_types: method_properties.append(input_prop) continue; - if input_prop.import_descriptor == None: - print("debug") + assert(input_prop.import_descriptor != None) if input_prop.import_descriptor != None and input_prop.import_descriptor.replacement == "": import_file_node = tree.search(input_prop.import_descriptor.file) import_node = import_file_node.get_child(input_prop.type) @@ -546,21 +551,20 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: method_properties = sorted(method_properties, key=lambda x: x.optional) for prop in method_properties: - service_code += f", {prop.name}:{prop.type}" + service_code += f", {prop.name}: {prop.type}" if prop.optional: service_code += " = None" if prop.import_descriptor != None: current_node.imports.append(prop.import_descriptor) - service_code += f"):\n" + + service_code += f") -> {task_name}:\n" service_code += add_indents(procedure.comment,2) def create_object_code(node:TreeNode, postfix:str, ignore_optionals:bool)->str: code = "" - if (procedure.name == "DepthMap"): - print("debug") # Get the Request Or Response node from the tree filespace_node = tree.search(node.filespace) filespace_replacement_name = get_replacement_name(filespace_node.get_path()) @@ -608,6 +612,10 @@ def create_object_code(node:TreeNode, postfix:str, ignore_optionals:bool)->str: service_code += create_object_code(request_node, "request", False) service_code += create_object_code(response_node, "response", True) + service_code += f" task = {task_name}(Index=0, Type=\"{procedure.name}\", Input={method_name}_request, Output={method_name}_response)\n" + service_code += f" scanner.SendTask(task)\n" + service_code += f" return task\n\n" + return service_code def generate_init_files(paths: set, tree: Tree, output_dir: str): From f65eddd9fabb6aadfa155ea1603c5e2c97aa0d84 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Fri, 27 Sep 2024 16:21:57 -0400 Subject: [PATCH 54/86] Including Generated files, and small cleanup --- .gitignore | 7 +- maf_three/MF/V3/Buffer.py | 66 + maf_three/MF/V3/Descriptors/BoundingBox.py | 24 + maf_three/MF/V3/Descriptors/Calibration.py | 79 ++ maf_three/MF/V3/Descriptors/Export.py | 38 + maf_three/MF/V3/Descriptors/Image.py | 13 + maf_three/MF/V3/Descriptors/Merge.py | 34 + maf_three/MF/V3/Descriptors/Network.py | 11 + maf_three/MF/V3/Descriptors/Project.py | 47 + maf_three/MF/V3/Descriptors/ProjectActions.py | 37 + maf_three/MF/V3/Descriptors/RemoveVertices.py | 26 + maf_three/MF/V3/Descriptors/ScanData.py | 53 + .../MF/V3/Descriptors/Settings/Advanced.py | 284 +++++ .../MF/V3/Descriptors/Settings/Camera.py | 71 ++ .../MF/V3/Descriptors/Settings/Capture.py | 46 + maf_three/MF/V3/Descriptors/Settings/I18n.py | 16 + .../MF/V3/Descriptors/Settings/Projector.py | 23 + .../MF/V3/Descriptors/Settings/Scanner.py | 37 + .../MF/V3/Descriptors/Settings/Software.py | 13 + maf_three/MF/V3/Descriptors/Settings/Style.py | 16 + .../MF/V3/Descriptors/Settings/Turntable.py | 33 + .../MF/V3/Descriptors/Settings/Tutorials.py | 30 + .../MF/V3/Descriptors/Settings/Viewer.py | 15 + .../MF/V3/Descriptors/Settings/__init__.py | 11 + maf_three/MF/V3/Descriptors/System.py | 59 + maf_three/MF/V3/Descriptors/Transform.py | 16 + maf_three/MF/V3/Descriptors/VideoFrame.py | 27 + maf_three/MF/V3/Descriptors/Wifi.py | 26 + maf_three/MF/V3/Descriptors/__init__.py | 12 + maf_three/MF/V3/Settings/Advanced.py | 185 +++ maf_three/MF/V3/Settings/Align.py | 82 ++ maf_three/MF/V3/Settings/AutoFocus.py | 24 + maf_three/MF/V3/Settings/BoundingBox.py | 15 + maf_three/MF/V3/Settings/Camera.py | 20 + maf_three/MF/V3/Settings/Capture.py | 25 + maf_three/MF/V3/Settings/Export.py | 27 + maf_three/MF/V3/Settings/Group.py | 26 + maf_three/MF/V3/Settings/I18n.py | 16 + maf_three/MF/V3/Settings/Merge.py | 85 ++ maf_three/MF/V3/Settings/NewGroup.py | 32 + maf_three/MF/V3/Settings/Project.py | 10 + maf_three/MF/V3/Settings/Projector.py | 58 + maf_three/MF/V3/Settings/Quality.py | 10 + maf_three/MF/V3/Settings/Rectangle.py | 13 + maf_three/MF/V3/Settings/Remesh.py | 36 + maf_three/MF/V3/Settings/RemoveVertices.py | 10 + maf_three/MF/V3/Settings/Scan.py | 157 +++ maf_three/MF/V3/Settings/ScanData.py | 40 + maf_three/MF/V3/Settings/ScanSelection.py | 22 + maf_three/MF/V3/Settings/Scanner.py | 37 + maf_three/MF/V3/Settings/Software.py | 20 + maf_three/MF/V3/Settings/Style.py | 15 + maf_three/MF/V3/Settings/Turntable.py | 11 + maf_three/MF/V3/Settings/Tutorials.py | 18 + maf_three/MF/V3/Settings/Upgrade.py | 9 + maf_three/MF/V3/Settings/Video.py | 31 + maf_three/MF/V3/Settings/Viewer.py | 7 + maf_three/MF/V3/Settings/Wifi.py | 9 + maf_three/MF/V3/Settings/__init__.py | 29 + maf_three/MF/V3/Task.py | 77 ++ maf_three/MF/V3/Tasks/AddMergeToProject.py | 66 + maf_three/MF/V3/Tasks/Align.py | 77 ++ maf_three/MF/V3/Tasks/AutoFocus.py | 94 ++ maf_three/MF/V3/Tasks/BoundingBox.py | 82 ++ maf_three/MF/V3/Tasks/CalibrateCameras.py | 58 + maf_three/MF/V3/Tasks/CalibrateTurntable.py | 61 + .../MF/V3/Tasks/CalibrationCaptureTargets.py | 66 + maf_three/MF/V3/Tasks/CameraCalibration.py | 60 + maf_three/MF/V3/Tasks/CloseProject.py | 53 + maf_three/MF/V3/Tasks/ConnectWifi.py | 67 + maf_three/MF/V3/Tasks/DepthMap.py | 141 +++ .../MF/V3/Tasks/DetectCalibrationCard.py | 65 + maf_three/MF/V3/Tasks/DownloadProject.py | 89 ++ maf_three/MF/V3/Tasks/Export.py | 103 ++ maf_three/MF/V3/Tasks/ExportLogs.py | 87 ++ maf_three/MF/V3/Tasks/ExportMerge.py | 97 ++ maf_three/MF/V3/Tasks/FlattenGroup.py | 72 ++ maf_three/MF/V3/Tasks/ForgetWifi.py | 53 + maf_three/MF/V3/Tasks/HasCameras.py | 56 + maf_three/MF/V3/Tasks/HasProjector.py | 56 + maf_three/MF/V3/Tasks/HasTurntable.py | 56 + maf_three/MF/V3/Tasks/ListExportFormats.py | 86 ++ maf_three/MF/V3/Tasks/ListGroups.py | 85 ++ .../MF/V3/Tasks/ListNetworkInterfaces.py | 61 + maf_three/MF/V3/Tasks/ListProjects.py | 61 + maf_three/MF/V3/Tasks/ListScans.py | 77 ++ maf_three/MF/V3/Tasks/ListSettings.py | 86 ++ maf_three/MF/V3/Tasks/ListWifi.py | 64 + maf_three/MF/V3/Tasks/Merge.py | 104 ++ maf_three/MF/V3/Tasks/MergeData.py | 239 ++++ maf_three/MF/V3/Tasks/MoveGroup.py | 79 ++ maf_three/MF/V3/Tasks/NewGroup.py | 77 ++ maf_three/MF/V3/Tasks/NewProject.py | 69 + maf_three/MF/V3/Tasks/NewScan.py | 82 ++ maf_three/MF/V3/Tasks/OpenProject.py | 66 + maf_three/MF/V3/Tasks/PopSettings.py | 92 ++ maf_three/MF/V3/Tasks/PushSettings.py | 86 ++ maf_three/MF/V3/Tasks/Reboot.py | 53 + maf_three/MF/V3/Tasks/RemoveGroups.py | 64 + maf_three/MF/V3/Tasks/RemoveProjects.py | 68 + .../MF/V3/Tasks/RestoreFactoryCalibration.py | 53 + maf_three/MF/V3/Tasks/RotateTurntable.py | 59 + maf_three/MF/V3/Tasks/ScanData.py | 239 ++++ maf_three/MF/V3/Tasks/SetCameras.py | 76 ++ maf_three/MF/V3/Tasks/SetGroup.py | 104 ++ maf_three/MF/V3/Tasks/SetProject.py | 80 ++ maf_three/MF/V3/Tasks/SetProjector.py | 75 ++ maf_three/MF/V3/Tasks/Shutdown.py | 53 + maf_three/MF/V3/Tasks/SplitGroup.py | 74 ++ maf_three/MF/V3/Tasks/StartVideo.py | 64 + maf_three/MF/V3/Tasks/StopVideo.py | 53 + maf_three/MF/V3/Tasks/SystemInfo.py | 92 ++ maf_three/MF/V3/Tasks/TransformGroup.py | 81 ++ maf_three/MF/V3/Tasks/TurntableCalibration.py | 61 + maf_three/MF/V3/Tasks/UpdateSettings.py | 105 ++ maf_three/MF/V3/Tasks/UploadProject.py | 79 ++ maf_three/MF/V3/Tasks/__init__.py | 56 + maf_three/MF/V3/Three.py | 1111 +++++++++++++++++ maf_three/MF/V3/__init__.py | 3 + maf_three/V3Task.py | 212 ---- maf_three/buffer.py | 23 - maf_three/scanner.py | 24 +- maf_three/scanner_functions.py | 32 - maf_three/task.py | 83 -- scripts/build-proto.py | 99 +- 125 files changed, 8019 insertions(+), 456 deletions(-) create mode 100644 maf_three/MF/V3/Buffer.py create mode 100644 maf_three/MF/V3/Descriptors/BoundingBox.py create mode 100644 maf_three/MF/V3/Descriptors/Calibration.py create mode 100644 maf_three/MF/V3/Descriptors/Export.py create mode 100644 maf_three/MF/V3/Descriptors/Image.py create mode 100644 maf_three/MF/V3/Descriptors/Merge.py create mode 100644 maf_three/MF/V3/Descriptors/Network.py create mode 100644 maf_three/MF/V3/Descriptors/Project.py create mode 100644 maf_three/MF/V3/Descriptors/ProjectActions.py create mode 100644 maf_three/MF/V3/Descriptors/RemoveVertices.py create mode 100644 maf_three/MF/V3/Descriptors/ScanData.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/Advanced.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/Camera.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/Capture.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/I18n.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/Projector.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/Scanner.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/Software.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/Style.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/Turntable.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/Tutorials.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/Viewer.py create mode 100644 maf_three/MF/V3/Descriptors/Settings/__init__.py create mode 100644 maf_three/MF/V3/Descriptors/System.py create mode 100644 maf_three/MF/V3/Descriptors/Transform.py create mode 100644 maf_three/MF/V3/Descriptors/VideoFrame.py create mode 100644 maf_three/MF/V3/Descriptors/Wifi.py create mode 100644 maf_three/MF/V3/Descriptors/__init__.py create mode 100644 maf_three/MF/V3/Settings/Advanced.py create mode 100644 maf_three/MF/V3/Settings/Align.py create mode 100644 maf_three/MF/V3/Settings/AutoFocus.py create mode 100644 maf_three/MF/V3/Settings/BoundingBox.py create mode 100644 maf_three/MF/V3/Settings/Camera.py create mode 100644 maf_three/MF/V3/Settings/Capture.py create mode 100644 maf_three/MF/V3/Settings/Export.py create mode 100644 maf_three/MF/V3/Settings/Group.py create mode 100644 maf_three/MF/V3/Settings/I18n.py create mode 100644 maf_three/MF/V3/Settings/Merge.py create mode 100644 maf_three/MF/V3/Settings/NewGroup.py create mode 100644 maf_three/MF/V3/Settings/Project.py create mode 100644 maf_three/MF/V3/Settings/Projector.py create mode 100644 maf_three/MF/V3/Settings/Quality.py create mode 100644 maf_three/MF/V3/Settings/Rectangle.py create mode 100644 maf_three/MF/V3/Settings/Remesh.py create mode 100644 maf_three/MF/V3/Settings/RemoveVertices.py create mode 100644 maf_three/MF/V3/Settings/Scan.py create mode 100644 maf_three/MF/V3/Settings/ScanData.py create mode 100644 maf_three/MF/V3/Settings/ScanSelection.py create mode 100644 maf_three/MF/V3/Settings/Scanner.py create mode 100644 maf_three/MF/V3/Settings/Software.py create mode 100644 maf_three/MF/V3/Settings/Style.py create mode 100644 maf_three/MF/V3/Settings/Turntable.py create mode 100644 maf_three/MF/V3/Settings/Tutorials.py create mode 100644 maf_three/MF/V3/Settings/Upgrade.py create mode 100644 maf_three/MF/V3/Settings/Video.py create mode 100644 maf_three/MF/V3/Settings/Viewer.py create mode 100644 maf_three/MF/V3/Settings/Wifi.py create mode 100644 maf_three/MF/V3/Settings/__init__.py create mode 100644 maf_three/MF/V3/Task.py create mode 100644 maf_three/MF/V3/Tasks/AddMergeToProject.py create mode 100644 maf_three/MF/V3/Tasks/Align.py create mode 100644 maf_three/MF/V3/Tasks/AutoFocus.py create mode 100644 maf_three/MF/V3/Tasks/BoundingBox.py create mode 100644 maf_three/MF/V3/Tasks/CalibrateCameras.py create mode 100644 maf_three/MF/V3/Tasks/CalibrateTurntable.py create mode 100644 maf_three/MF/V3/Tasks/CalibrationCaptureTargets.py create mode 100644 maf_three/MF/V3/Tasks/CameraCalibration.py create mode 100644 maf_three/MF/V3/Tasks/CloseProject.py create mode 100644 maf_three/MF/V3/Tasks/ConnectWifi.py create mode 100644 maf_three/MF/V3/Tasks/DepthMap.py create mode 100644 maf_three/MF/V3/Tasks/DetectCalibrationCard.py create mode 100644 maf_three/MF/V3/Tasks/DownloadProject.py create mode 100644 maf_three/MF/V3/Tasks/Export.py create mode 100644 maf_three/MF/V3/Tasks/ExportLogs.py create mode 100644 maf_three/MF/V3/Tasks/ExportMerge.py create mode 100644 maf_three/MF/V3/Tasks/FlattenGroup.py create mode 100644 maf_three/MF/V3/Tasks/ForgetWifi.py create mode 100644 maf_three/MF/V3/Tasks/HasCameras.py create mode 100644 maf_three/MF/V3/Tasks/HasProjector.py create mode 100644 maf_three/MF/V3/Tasks/HasTurntable.py create mode 100644 maf_three/MF/V3/Tasks/ListExportFormats.py create mode 100644 maf_three/MF/V3/Tasks/ListGroups.py create mode 100644 maf_three/MF/V3/Tasks/ListNetworkInterfaces.py create mode 100644 maf_three/MF/V3/Tasks/ListProjects.py create mode 100644 maf_three/MF/V3/Tasks/ListScans.py create mode 100644 maf_three/MF/V3/Tasks/ListSettings.py create mode 100644 maf_three/MF/V3/Tasks/ListWifi.py create mode 100644 maf_three/MF/V3/Tasks/Merge.py create mode 100644 maf_three/MF/V3/Tasks/MergeData.py create mode 100644 maf_three/MF/V3/Tasks/MoveGroup.py create mode 100644 maf_three/MF/V3/Tasks/NewGroup.py create mode 100644 maf_three/MF/V3/Tasks/NewProject.py create mode 100644 maf_three/MF/V3/Tasks/NewScan.py create mode 100644 maf_three/MF/V3/Tasks/OpenProject.py create mode 100644 maf_three/MF/V3/Tasks/PopSettings.py create mode 100644 maf_three/MF/V3/Tasks/PushSettings.py create mode 100644 maf_three/MF/V3/Tasks/Reboot.py create mode 100644 maf_three/MF/V3/Tasks/RemoveGroups.py create mode 100644 maf_three/MF/V3/Tasks/RemoveProjects.py create mode 100644 maf_three/MF/V3/Tasks/RestoreFactoryCalibration.py create mode 100644 maf_three/MF/V3/Tasks/RotateTurntable.py create mode 100644 maf_three/MF/V3/Tasks/ScanData.py create mode 100644 maf_three/MF/V3/Tasks/SetCameras.py create mode 100644 maf_three/MF/V3/Tasks/SetGroup.py create mode 100644 maf_three/MF/V3/Tasks/SetProject.py create mode 100644 maf_three/MF/V3/Tasks/SetProjector.py create mode 100644 maf_three/MF/V3/Tasks/Shutdown.py create mode 100644 maf_three/MF/V3/Tasks/SplitGroup.py create mode 100644 maf_three/MF/V3/Tasks/StartVideo.py create mode 100644 maf_three/MF/V3/Tasks/StopVideo.py create mode 100644 maf_three/MF/V3/Tasks/SystemInfo.py create mode 100644 maf_three/MF/V3/Tasks/TransformGroup.py create mode 100644 maf_three/MF/V3/Tasks/TurntableCalibration.py create mode 100644 maf_three/MF/V3/Tasks/UpdateSettings.py create mode 100644 maf_three/MF/V3/Tasks/UploadProject.py create mode 100644 maf_three/MF/V3/Tasks/__init__.py create mode 100644 maf_three/MF/V3/Three.py create mode 100644 maf_three/MF/V3/__init__.py delete mode 100644 maf_three/V3Task.py delete mode 100644 maf_three/buffer.py delete mode 100644 maf_three/scanner_functions.py delete mode 100644 maf_three/task.py diff --git a/.gitignore b/.gitignore index d0f94f3..d3c20c4 100644 --- a/.gitignore +++ b/.gitignore @@ -160,9 +160,4 @@ cython_debug/ #.idea/ -## Matter And Form ## - -# Don't include protobuf generated files. -maf_three/MF - - +## Matter And Form ## \ No newline at end of file diff --git a/maf_three/MF/V3/Buffer.py b/maf_three/MF/V3/Buffer.py new file mode 100644 index 0000000..ae224b1 --- /dev/null +++ b/maf_three/MF/V3/Buffer.py @@ -0,0 +1,66 @@ +from google.protobuf import any_pb2 as _any_pb2 +from MF.V3.Task import Task as MF_V3_Task_Task + + +class Buffer: + """* + Generic buffer message for the Three Scanner. + + Some tasks require the server and/or client to transfer binary data. In such cases the _buffer message_ is sent to inform the server/client what the data is and what task it belongs to. The binary data it refers to is sent immediately following the buffer message. + + For example, `DownloadProject` requires the server to transfer a ZIP file containing the project data to the client. + + > First, the client sends the task request to the server: + + ```json + { + "Task":{ + "Index":1, + "Type":"DownloadProject", + "Input":5 + } + } + ``` + + > The server sends the buffer message telling the client to expect a binary data transfer and what to do with it. Note that the buffer message `Task` field echoes the task request, making it clear which request this data is a response to. + + ```json + { + "Buffer":{ + "Descriptor":"Project-5.zip", + "Index":0, + "Size":15682096, + "Task":{ + "Index":1, + "Type":"DownloadProject", + "Input":5 + } + } + } + ``` + + > The server then sends the 15682096 byte data buffer of the project ZIP file. + > Finally, the server sends a task completion message. + + ```json + { + "Task":{ + "Index":1, + "Type":"DownloadProject" + "Input":5, + "State":"Completed" + } + } + ``` + """ + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: _any_pb2 = None): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The task associated with the data buffer. This informs the client which request this data buffer corresponds to. + self.Task = Task + # Optional data buffer descriptor. See each task definition for details. + self.Descriptor = Descriptor + + diff --git a/maf_three/MF/V3/Descriptors/BoundingBox.py b/maf_three/MF/V3/Descriptors/BoundingBox.py new file mode 100644 index 0000000..ad59c38 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/BoundingBox.py @@ -0,0 +1,24 @@ +from typing import List + + +class BoundingBox: + # BoundingBox descriptor. + def __init__(self, center: List[float], size: List[float], rotation: List[float], transform: List[float]): + # The center of the bounding box. + self.center = center + # The size of the bounding box. + self.size = size + """ + The 3x3 rotation matrix of the bounding box. + The first, second and third column vectors are the x, y and z axes of the bounding box. + """ + self.rotation = rotation + """ + The 4x4 matrix that transforms the canonical cube with corners [±1, ±1, ±1] to the + bounding box in world coordinates. + The transform can be used as the model matrix for rendering the bounding box with an + OpenGL shader. + """ + self.transform = transform + + diff --git a/maf_three/MF/V3/Descriptors/Calibration.py b/maf_three/MF/V3/Descriptors/Calibration.py new file mode 100644 index 0000000..15d0557 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Calibration.py @@ -0,0 +1,79 @@ +from enum import Enum +from typing import List + + +# Calibration quality. +class Quality(Enum): + Empty = "None" # The calibration does not exist. + Poor = "Poor" # Poor calibration quality. + Fair = "Fair" # Fair calibration quality. + Good = "Good" # Good calibration quality. + Excellent = "Excellent" # Excellent calibration quality. + + +class Camera: + # Camera calibration descriptor. + def __init__(self, quality: 'Quality', date: List[int]): + # Calibration quality. + self.quality = quality + # Calibration date and time [year, month, day, hour, minute, second]. + self.date = date + + +class Turntable: + # Turntable calibration descriptor. + def __init__(self, quality: 'Quality', date: List[int], focus: List[int]): + # Calibration quality. + self.quality = quality + # Calibration date and time [year, month, day, hour, minute, second]. + self.date = date + # Focus values of each camera during calibration. + self.focus = focus + + +class CaptureTarget: + """ + Calibration capture target. + + The camera calibration capture targets are used to draw quad overlays on the video stream to guide a user as to where to position the calibration card for each capture during camera calibration. + """ + def __init__(self, camera: int, quads: List[float]): + # Index of the camera that is displayed to the user for this capture. + self.camera = camera + """ + The target quad for each camera. + This is a set of 16 numbers defining the quad coordinates on the left and right camera. + The first 4 pairs of numbers define the quad on the left camera. + The last 4 pairs of numbers define the quad on the right camera. + """ + self.quads = quads + + +class DetectedCard: + # Detected calibration card descriptor. + class Target: + # Calibration capture target properties. + def __init__(self, match: float, hold: float): + """ + A normalized value indicating how closely the calibration card matches the target + overlay. 0 indicates a poor match. 1 indicates a good match. + """ + self.match = match + """ + A normalized value indicating how long the user has held the calibration card steady over + the target overlay. When the value reaches 1, the user has held the calibration card + steady for the complete required duration. + """ + self.hold = hold + + def __init__(self, size: List[int], quad: List[float], corners: List[float], target: 'Target' = None): + # The calibration card columns and rows. + self.size = size + # The calibration card bounding quadrilateral. + self.quad = quad + # The detected corners of the calibration card. + self.corners = corners + # The capture target properties, if a capture target is specified. + self.target = target + + diff --git a/maf_three/MF/V3/Descriptors/Export.py b/maf_three/MF/V3/Descriptors/Export.py new file mode 100644 index 0000000..42edae9 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Export.py @@ -0,0 +1,38 @@ +from enum import Enum +from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export +from typing import List + + +class Export: + # Scan data descriptor. + # Geometry face types. + class Face(Enum): + NoFace = "NoFace" # No faces. + Point = "Point" # Point faces. + Line = "Line" # Line faces. + Triangle = "Triangle" # Triangle faces. + Quad = "Quad" # Quad faces. + + # Texture support types. + class Texture(Enum): + Empty = "None" # The format does not support textures. + Single = "Single" # The format supports a single texture only. + Multiple = "Multiple" # The format supports multiple textures. + + def __init__(self, format: MF_V3_Settings_Export_Export.Format, extension: str, description: str, faces: List['Face'], normals: bool, colors: bool, textures: 'Texture'): + # Export format. + self.format = format + # Export file extension. e.g. ".ply" + self.extension = extension + # Export format description. e.g. "Polygon format" + self.description = description + # Types of supported faces. + self.faces = faces + # Vertex normal support. + self.normals = normals + # Vertex color support. + self.colors = colors + # Texture (UV) support. + self.textures = textures + + diff --git a/maf_three/MF/V3/Descriptors/Image.py b/maf_three/MF/V3/Descriptors/Image.py new file mode 100644 index 0000000..1e830d4 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Image.py @@ -0,0 +1,13 @@ +class Image: + # Image descriptor. + def __init__(self, width: int, height: int, step: int, type: int): + # Image width. + self.width = width + # Image height. + self.height = height + # Image row step in bytes. + self.step = step + # OpenCV image [type](https:gist.github.com/yangcha/38f2fa630e223a8546f9b48ebbb3e61a). + self.type = type + + diff --git a/maf_three/MF/V3/Descriptors/Merge.py b/maf_three/MF/V3/Descriptors/Merge.py new file mode 100644 index 0000000..daeaf43 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Merge.py @@ -0,0 +1,34 @@ +from typing import List + + +class Merge: + # Merge descriptor. + class Mesh: + # Mesh descriptor. + def __init__(self, name: str, triangles: int, quads: int, positions: int, normals: int, uvs: int, size: int): + # The mesh name. + self.name = name + # Number of mesh triangle faces. + self.triangles = triangles + # Number of quad faces. + self.quads = quads + # Number of vertex positions. + self.positions = positions + # Number of vertex normals. + self.normals = normals + # Number of UV coordinates. + self.uvs = uvs + # Total mesh size in bytes. + self.size = size + + def __init__(self, scans: int, textures: int, maxSimplifyCount: int, meshes: List['Mesh']): + # The number of input scans. + self.scans = scans + # The number of input textures. + self.textures = textures + # The maximum number of faces for the simplify merge step. + self.maxSimplifyCount = maxSimplifyCount + # The set of merged mesh descriptors. + self.meshes = meshes + + diff --git a/maf_three/MF/V3/Descriptors/Network.py b/maf_three/MF/V3/Descriptors/Network.py new file mode 100644 index 0000000..9f5ce91 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Network.py @@ -0,0 +1,11 @@ +class Interface: + # Network interface descriptor. + def __init__(self, name: str, ip: str, ssid: str): + # The name of the interface. + self.name = name + # The address associated with the interface. + self.ip = ip + # The ssid or name of the network. + self.ssid = ssid + + diff --git a/maf_three/MF/V3/Descriptors/Project.py b/maf_three/MF/V3/Descriptors/Project.py new file mode 100644 index 0000000..16a487f --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Project.py @@ -0,0 +1,47 @@ +from typing import List + + +class Project: + # V3 project descriptor. + class Brief: + # V3 project brief descriptor. + def __init__(self, index: int, name: str, size: int, modified: List[int]): + # Project index. + self.index = index + # Project name. + self.name = name + # Size in bytes. + self.size = size + # Project last modified date and time [year, month, day, hour, minute, second]. + self.modified = modified + + class Group: + # V3 project scan group tree descriptor. + def __init__(self, index: int, name: str, color: List[float], visible: bool, collapsed: bool, rotation: List[float], translation: List[float], groups: List['Project.Group'], scan: int = None): + # Group index. + self.index = index + # Group name. + self.name = name + # Color in the renderer. + self.color = color + # Visibility in the renderer. + self.visible = visible + # Collapsed state in the group tree. + self.collapsed = collapsed + # Axis-angle rotation vector. The direction of the vector is the rotation axis. The magnitude of the vector is rotation angle in radians. + self.rotation = rotation + # Translation vector. + self.translation = translation + # Subgroups. + self.groups = groups + # The scan index. If defined this group is a scan and cannot have subgroups. + self.scan = scan + + def __init__(self, index: int, name: str, groups: 'Group'): + # Project index. + self.index = index + # Project name. + self.name = name + self.groups = groups + + diff --git a/maf_three/MF/V3/Descriptors/ProjectActions.py b/maf_three/MF/V3/Descriptors/ProjectActions.py new file mode 100644 index 0000000..cdf58ca --- /dev/null +++ b/maf_three/MF/V3/Descriptors/ProjectActions.py @@ -0,0 +1,37 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from typing import List + + +class ProjectAction: + # Descriptor for a project undo/redo action. + class Scan: + # Scan vertices removal/insertion metadata. + def __init__(self, index: int, vertices: int, triangles: int): + # The scan index. + self.index = index + # The number of vertices after undo or redo. + self.vertices = vertices + # The number of triangles after undo or redo. + self.triangles = triangles + + def __init__(self, task: str, scans: List['Scan'], project: MF_V3_Descriptors_Project_Project = None): + # The original websocket task that the action is undoing or redoing. + self.task = task + # The list of scans whose vertex/triangle elements were changed by the undo/redo action. + self.scans = scans + """ + The updated project data after undo or redo. + If undefined, then there was no change to the project. + """ + self.project = project + + +class ProjectActions: + # Project undo and redo action descriptors. + def __init__(self, undo: List[str], redo: List[str]): + # Project undo action descriptors. + self.undo = undo + # Project redo action descriptors. + self.redo = redo + + diff --git a/maf_three/MF/V3/Descriptors/RemoveVertices.py b/maf_three/MF/V3/Descriptors/RemoveVertices.py new file mode 100644 index 0000000..81800b8 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/RemoveVertices.py @@ -0,0 +1,26 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from typing import List + + +class RemoveVertices: + # Descriptor a remove vertices task. + class Scan: + # Scan vertex and triangle removal metadata. + def __init__(self, index: int, vertices: int, triangles: int): + # The scan index. + self.index = index + # The number of vertices after the removal. + self.vertices = vertices + # The number of triangles after the removal. + self.triangles = triangles + + def __init__(self, scans: List['Scan'], groups: MF_V3_Descriptors_Project_Project.Group = None): + # The list of scans whose vertices were removed. + self.scans = scans + """ + The updated project data after undo or redo. + If undefined, then there was no change to the project. + """ + self.groups = groups + + diff --git a/maf_three/MF/V3/Descriptors/ScanData.py b/maf_three/MF/V3/Descriptors/ScanData.py new file mode 100644 index 0000000..d052ba9 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/ScanData.py @@ -0,0 +1,53 @@ +from enum import Enum +from typing import List + + +class ScanData: + # Scan data descriptor. + class Buffer: + # Scan buffer descriptor. + class Component: + # Scan buffer component descriptor. + # Scan buffer component types. + class Type(Enum): + Position = "Position" # Vertex position. + Normal = "Normal" # Vertex normal. + Color = "Color" # Vertex color. + UV = "UV" # Vertex texture coordinate. + Triangle = "Triangle" # Triangle index. + Texture = "Texture" # Texture. + + def __init__(self, type: 'Type', size: int, offset: int, normalized: bool): + # Scan buffer component type. + self.type = type + # Scan buffer component size (ie. the number of elements). + self.size = size + """ + Scan buffer component offset. + This is the starting element for this component at every stride of the buffer. + """ + self.offset = offset + # Indicates if the data is normalized. + self.normalized = normalized + + def __init__(self, components: List['Component'], stride: int): + # Scan buffer components. + self.components = components + # Scan buffer stride. This should be greater or equal to the sum of the component sizes. + self.stride = stride + + def __init__(self, index: int, name: str, buffers: List['Buffer'], mean: List[float], stddev: List[float], axisAlignedBoundingBox: List[float]): + # Scan index. + self.index = index + # Scan name. + self.name = name + # Scan buffer descriptors. + self.buffers = buffers + # The mean (centroid) of the vertex positions. + self.mean = mean + # The standard deviation of the vertex positions. + self.stddev = stddev + # The axis-aligned bounding box of the vertex positions. + self.axisAlignedBoundingBox = axisAlignedBoundingBox + + diff --git a/maf_three/MF/V3/Descriptors/Settings/Advanced.py b/maf_three/MF/V3/Descriptors/Settings/Advanced.py new file mode 100644 index 0000000..f71f88f --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/Advanced.py @@ -0,0 +1,284 @@ +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from typing import List + + +class Advanced: + # Advanced settings descriptor. + class Use: + # Use advanced settings. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + class Capture: + # Capture settings descriptor. + class HorizontalFrequencies: + def __init__(self, value: List[int], default: List[int], min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class VerticalFrequencies: + def __init__(self, value: List[int], default: List[int], min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, use: 'Advanced.Use', horizontalFrequencies: 'HorizontalFrequencies', verticalFrequencies: 'VerticalFrequencies'): + self.use = use + self.horizontalFrequencies = horizontalFrequencies + self.verticalFrequencies = verticalFrequencies + + class Sampling: + # Sampling settings descriptor. + class ProjectorSampleRate: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class ImageSampleRate: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, use: 'Advanced.Use', projectorSampleRate: 'ProjectorSampleRate', imageSampleRate: 'ImageSampleRate'): + # Use sampling settings. + self.use = use + self.projectorSampleRate = projectorSampleRate + self.imageSampleRate = imageSampleRate + + class EdgeDetection: + # Edge detection settings descriptor. + class Threshold: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class LaplacianKernelRadius: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class GaussianBlurRadius: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class GaussianBlurStdDev: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class MaximumWidthForProcessing: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, use: 'Advanced.Use', threshold: 'Threshold', laplacianKernelRadius: 'LaplacianKernelRadius', gaussianBlurRadius: 'GaussianBlurRadius', gaussianBlurStdDev: 'GaussianBlurStdDev', maximumWidthForProcessing: 'MaximumWidthForProcessing'): + self.use = use + self.threshold = threshold + self.laplacianKernelRadius = laplacianKernelRadius + self.gaussianBlurRadius = gaussianBlurRadius + self.gaussianBlurStdDev = gaussianBlurStdDev + self.maximumWidthForProcessing = maximumWidthForProcessing + + class PhaseFilter: + # Phase filter settings descriptor. + class KernelRadius: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class SpatialWeightStdDev: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, use: 'Advanced.Use', kernelRadius: 'KernelRadius', spatialWeightStdDev: 'SpatialWeightStdDev'): + self.use = use + self.kernelRadius = kernelRadius + self.spatialWeightStdDev = spatialWeightStdDev + + class AdaptiveSampling: + # Adaptive sampling settings descriptor. + class Type: + def __init__(self, value: MF_V3_Settings_Scan_Scan.Processing.AdaptiveSampling.Type, default: MF_V3_Settings_Scan_Scan.Processing.AdaptiveSampling.Type): + self.value = value + self.default = default + + class Rate: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, use: 'Advanced.Use', type: 'Type', rate: 'Rate'): + self.use = use + self.type = type + self.rate = rate + + class NormalEstimation: + # Normal estimation settings descriptor. + class Method: + def __init__(self, value: MF_V3_Settings_Scan_Scan.Processing.NormalEstimation.Method, default: MF_V3_Settings_Scan_Scan.Processing.NormalEstimation.Method): + self.value = value + self.default = default + + class MaximumNeighbourCount: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class MaximumNeighbourRadius: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class UseMaximumNeighbourCount: + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + class UseMaximumNeighbourRadius: + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, use: 'Advanced.Use', method: 'Method', maximumNeighbourCount: 'MaximumNeighbourCount', maximumNeighbourRadius: 'MaximumNeighbourRadius', useMaximumNeighbourCount: 'UseMaximumNeighbourCount', useMaximumNeighbourRadius: 'UseMaximumNeighbourRadius'): + self.use = use + self.method = method + self.maximumNeighbourCount = maximumNeighbourCount + self.maximumNeighbourRadius = maximumNeighbourRadius + self.useMaximumNeighbourCount = useMaximumNeighbourCount + self.useMaximumNeighbourRadius = useMaximumNeighbourRadius + + class OutlierRemoval: + # Outlier removal settings descriptor. + class NeighbourCount: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class NeighbourRadius: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, use: 'Advanced.Use', neighbourCount: 'NeighbourCount', neighbourRadius: 'NeighbourRadius'): + self.use = use + self.neighbourCount = neighbourCount + self.neighbourRadius = neighbourRadius + + class Remesh: + # Remesh settings descriptor. + class VoxelSize: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class Depth: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class Scale: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class LinearInterpolation: + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, use: 'Advanced.Use', voxelSize: 'VoxelSize', depth: 'Depth', scale: 'Scale', linearInterpolation: 'LinearInterpolation'): + self.use = use + self.voxelSize = voxelSize + self.depth = depth + self.scale = scale + self.linearInterpolation = linearInterpolation + + class Camera: + # Camera settings descriptor. + class UseContinuousExposureValues: + # Use continuous exposure values settings descriptor. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, useContinuousExposureValues: 'UseContinuousExposureValues'): + # Use continuous exposure values settings descriptor. + self.useContinuousExposureValues = useContinuousExposureValues + + class Turntable: + # Turntable settings descriptor. + class RampAngle: + # The angle in degrees to slow down the turntable at the end of a rotation. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, rampAngle: 'RampAngle'): + # The angle in degrees to slow down the turntable at the end of a rotation. + self.rampAngle = rampAngle + + def __init__(self, capture: 'Capture', sampling: 'Sampling', edgeDetection: 'EdgeDetection', phaseFilter: 'PhaseFilter', adaptiveSampling: 'AdaptiveSampling', normalEstimation: 'NormalEstimation', outlierRemoval: 'OutlierRemoval', remesh: 'Remesh', camera: 'Camera', turntable: 'Turntable'): + # Capture settings descriptor. + self.capture = capture + # Sampling settings descriptor. + self.sampling = sampling + # Edge detection settings descriptor. + self.edgeDetection = edgeDetection + # Phase filter settings descriptor. + self.phaseFilter = phaseFilter + # Adaptive sampling settings descriptor. + self.adaptiveSampling = adaptiveSampling + # Normal estimation settings descriptor. + self.normalEstimation = normalEstimation + # Outlier removal settings descriptor. + self.outlierRemoval = outlierRemoval + # Remesh settings descriptor. + self.remesh = remesh + # Camera settings descriptor. + self.camera = camera + # Turntable settings descriptor. + self.turntable = turntable + + diff --git a/maf_three/MF/V3/Descriptors/Settings/Camera.py b/maf_three/MF/V3/Descriptors/Settings/Camera.py new file mode 100644 index 0000000..a59dcb5 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/Camera.py @@ -0,0 +1,71 @@ +from MF.V3.Settings.Rectangle import Rectangle as MF_V3_Settings_Rectangle_Rectangle +from typing import List + + +class Camera: + # Camera settings descriptor. + class AutoExposure: + # Auto exposure. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + class Exposure: + # Exposure. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class AnalogGain: + # Analog gain. + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class DigitalGain: + # Digital gain. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class Focus: + # Focus settings descriptor. + class Value: + # Focus value. + def __init__(self, value: List[int], default: List[int], min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class Box: + # Auto focus box. + def __init__(self, value: List[MF_V3_Settings_Rectangle_Rectangle], default: List[MF_V3_Settings_Rectangle_Rectangle]): + self.value = value + self.default = default + + def __init__(self, value: 'Value', box: 'Box'): + # Focus value. + self.value = value + # Auto focus box. + self.box = box + + def __init__(self, autoExposure: 'AutoExposure', exposure: 'Exposure', analogGain: 'AnalogGain', digitalGain: 'DigitalGain', focus: 'Focus'): + # Auto exposure. + self.autoExposure = autoExposure + # Exposure. + self.exposure = exposure + # Analog gain. + self.analogGain = analogGain + # Digital gain. + self.digitalGain = digitalGain + # Focus settings descriptor. + self.focus = focus + + diff --git a/maf_three/MF/V3/Descriptors/Settings/Capture.py b/maf_three/MF/V3/Descriptors/Settings/Capture.py new file mode 100644 index 0000000..8143c07 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/Capture.py @@ -0,0 +1,46 @@ +from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality + + +class Capture: + # Capture settings descriptor. + class Quality: + # Capture quality preset. + def __init__(self, value: MF_V3_Settings_Quality_Quality, default: MF_V3_Settings_Quality_Quality): + self.value = value + self.default = default + + class Texture: + # Capture texture. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + class BlendCount: + # Capture image blend count for noise reduction. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class BlendFrequency: + # The starting frequency for which multiple capture images are blended. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, quality: 'Quality', texture: 'Texture', blendCount: 'BlendCount', horizontalBlendFrequency: 'BlendFrequency', verticalBlendFrequency: 'BlendFrequency'): + # Capture quality preset. + self.quality = quality + # Capture texture. + self.texture = texture + # Capture blend count. + self.blendCount = blendCount + # Starting horizontal blend frequency. + self.horizontalBlendFrequency = horizontalBlendFrequency + # Starting vertical blend frequency. + self.verticalBlendFrequency = verticalBlendFrequency + + diff --git a/maf_three/MF/V3/Descriptors/Settings/I18n.py b/maf_three/MF/V3/Descriptors/Settings/I18n.py new file mode 100644 index 0000000..f6ece28 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/I18n.py @@ -0,0 +1,16 @@ +from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n + + +class I18n: + # I18n language settings descriptor. + class Language: + # Language settings descriptor. + def __init__(self, value: MF_V3_Settings_I18n_I18n.Language, default: MF_V3_Settings_I18n_I18n.Language): + self.value = value + self.default = default + + def __init__(self, language: 'Language'): + # Language settings descriptor. + self.language = language + + diff --git a/maf_three/MF/V3/Descriptors/Settings/Projector.py b/maf_three/MF/V3/Descriptors/Settings/Projector.py new file mode 100644 index 0000000..60310dc --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/Projector.py @@ -0,0 +1,23 @@ +class Projector: + # Projector settings descriptor. + class Brightness: + # Projector brightness. + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class On: + # Projector on/off. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, brightness: 'Brightness', on: 'On'): + # Projector brightness. + self.brightness = brightness + # Projector on/off. + self.on = on + + diff --git a/maf_three/MF/V3/Descriptors/Settings/Scanner.py b/maf_three/MF/V3/Descriptors/Settings/Scanner.py new file mode 100644 index 0000000..1e987c6 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/Scanner.py @@ -0,0 +1,37 @@ +from MF.V3.Descriptors.Settings.Style import Style as MF_V3_Descriptors_Settings_Style_Style +from MF.V3.Descriptors.Settings.Turntable import Turntable as MF_V3_Descriptors_Settings_Turntable_Turntable +from MF.V3.Descriptors.Settings.Advanced import Advanced as MF_V3_Descriptors_Settings_Advanced_Advanced +from MF.V3.Descriptors.Settings.I18n import I18n as MF_V3_Descriptors_Settings_I18n_I18n +from MF.V3.Descriptors.Settings.Tutorials import Tutorials as MF_V3_Descriptors_Settings_Tutorials_Tutorials +from MF.V3.Descriptors.Settings.Capture import Capture as MF_V3_Descriptors_Settings_Capture_Capture +from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera +from MF.V3.Descriptors.Settings.Projector import Projector as MF_V3_Descriptors_Settings_Projector_Projector +from MF.V3.Descriptors.Settings.Software import Software as MF_V3_Descriptors_Settings_Software_Software +from MF.V3.Descriptors.Settings.Viewer import Viewer as MF_V3_Descriptors_Settings_Viewer_Viewer + + +class Scanner: + # Scanner settings descriptor. + def __init__(self, advanced: MF_V3_Descriptors_Settings_Advanced_Advanced, camera: MF_V3_Descriptors_Settings_Camera_Camera, capture: MF_V3_Descriptors_Settings_Capture_Capture, projector: MF_V3_Descriptors_Settings_Projector_Projector, i18n: MF_V3_Descriptors_Settings_I18n_I18n, style: MF_V3_Descriptors_Settings_Style_Style, turntable: MF_V3_Descriptors_Settings_Turntable_Turntable, tutorials: MF_V3_Descriptors_Settings_Tutorials_Tutorials, viewer: MF_V3_Descriptors_Settings_Viewer_Viewer, software: MF_V3_Descriptors_Settings_Software_Software): + # Advanced settings descriptor. + self.advanced = advanced + # Camera settings descriptor. + self.camera = camera + # Capture settings descriptor. + self.capture = capture + # Projector settings descriptor. + self.projector = projector + # Internalization setting descriptor. + self.i18n = i18n + # Style settings descriptor. + self.style = style + # Turntable settings descriptor. + self.turntable = turntable + # Tutorials settings descriptor. + self.tutorials = tutorials + # Viewer settings descriptor. + self.viewer = viewer + # Style settings descriptor. + self.software = software + + diff --git a/maf_three/MF/V3/Descriptors/Settings/Software.py b/maf_three/MF/V3/Descriptors/Settings/Software.py new file mode 100644 index 0000000..de56143 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/Software.py @@ -0,0 +1,13 @@ +class Software: + # Software settings descriptor. + class NightlyIncluded: + # Nightly releases included descriptor. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, nightlyIncluded: 'NightlyIncluded'): + # Nightly releases included. + self.nightlyIncluded = nightlyIncluded + + diff --git a/maf_three/MF/V3/Descriptors/Settings/Style.py b/maf_three/MF/V3/Descriptors/Settings/Style.py new file mode 100644 index 0000000..274447f --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/Style.py @@ -0,0 +1,16 @@ +from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style + + +class Style: + # Style settings descriptor. + class Theme: + # Theme settings descriptor. + def __init__(self, value: MF_V3_Settings_Style_Style.Theme, default: MF_V3_Settings_Style_Style.Theme): + self.value = value + self.default = default + + def __init__(self, theme: 'Theme'): + # Theme settings descriptor. + self.theme = theme + + diff --git a/maf_three/MF/V3/Descriptors/Settings/Turntable.py b/maf_three/MF/V3/Descriptors/Settings/Turntable.py new file mode 100644 index 0000000..1655db7 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/Turntable.py @@ -0,0 +1,33 @@ +class Turntable: + # Turntable settings descriptor. + class Scans: + # The number of turntable scans. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class Sweep: + # Turntable angle sweep in degrees. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class Use: + # Use the turntable. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, scans: 'Scans', sweep: 'Sweep', use: 'Use'): + # The number of turntable scans. + self.scans = scans + # Turntable angle sweep in degrees. + self.sweep = sweep + # Use the turntable. + self.use = use + + diff --git a/maf_three/MF/V3/Descriptors/Settings/Tutorials.py b/maf_three/MF/V3/Descriptors/Settings/Tutorials.py new file mode 100644 index 0000000..383efda --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/Tutorials.py @@ -0,0 +1,30 @@ +from typing import List + + +class Tutorials: + # Tutorials settings descriptor. + class Show: + # Tutorials to show. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + class Viewed: + # Viewed tutorials. + class Pages: + # Viewed tutorials pages. + def __init__(self, value: List[str], default: List[str]): + self.value = value + self.default = default + + def __init__(self, pages: 'Pages'): + # Viewed tutorials pages. + self.pages = pages + + def __init__(self, show: 'Show', viewed: 'Viewed'): + # Show tutorials. + self.show = show + # Viewed tutorials. + self.viewed = viewed + + diff --git a/maf_three/MF/V3/Descriptors/Settings/Viewer.py b/maf_three/MF/V3/Descriptors/Settings/Viewer.py new file mode 100644 index 0000000..296fead --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/Viewer.py @@ -0,0 +1,15 @@ +class Viewer: + # 3D Viewer settings descriptor. + class TextureOpacity: + # Texture opacity. + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, textureOpacity: 'TextureOpacity'): + # Texture opacity. + self.textureOpacity = textureOpacity + + diff --git a/maf_three/MF/V3/Descriptors/Settings/__init__.py b/maf_three/MF/V3/Descriptors/Settings/__init__.py new file mode 100644 index 0000000..50bc7c1 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Settings/__init__.py @@ -0,0 +1,11 @@ +from MF.V3.Descriptors.Settings.Software import * +from MF.V3.Descriptors.Settings.I18n import * +from MF.V3.Descriptors.Settings.Scanner import * +from MF.V3.Descriptors.Settings.Viewer import * +from MF.V3.Descriptors.Settings.Style import * +from MF.V3.Descriptors.Settings.Tutorials import * +from MF.V3.Descriptors.Settings.Projector import * +from MF.V3.Descriptors.Settings.Turntable import * +from MF.V3.Descriptors.Settings.Advanced import * +from MF.V3.Descriptors.Settings.Camera import * +from MF.V3.Descriptors.Settings.Capture import * diff --git a/maf_three/MF/V3/Descriptors/System.py b/maf_three/MF/V3/Descriptors/System.py new file mode 100644 index 0000000..ef53333 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/System.py @@ -0,0 +1,59 @@ +from MF.V3.Settings.Software import Software +from typing import List + + +class System: + # System descriptor. + class DiskSpace: + # Disk space descriptor. + def __init__(self, capacity: int, available: int): + # Disk space capacity in bytes. + self.capacity = capacity + # Available disk space in bytes. + self.available = available + + class Software: + # Software descriptor. + class Version: + # Software version descriptor. + def __init__(self, major: int, minor: int, patch: int, suffix: str, string: str): + # The major version. + self.major = major + # The minor version. + self.minor = minor + # The patch version. + self.patch = patch + # The alphanumeric suffix. e.g. "rc0" + self.suffix = suffix + # The version string. e.g. "1.2.3-rc0" + self.string = string + + class Package: + # Software package descriptor. + def __init__(self, name: Software.Package, version: 'System.Software.Version', changelog: str): + # The package name. + self.name = name + # The package version. + self.version = version + # The package changelog. + self.changelog = changelog + + def __init__(self, installed: List['Package'], available: List['Package'], nightlyIncluded: bool): + # Installed software versions. + self.installed = installed + # Available software versions. + self.available = available + # Nightly releases are included. + self.nightlyIncluded = nightlyIncluded + + def __init__(self, serialNumber: str, diskSpace: 'DiskSpace', software: 'Software', publicKey: str): + # Serial number; + self.serialNumber = serialNumber + # Used and available disk space. + self.diskSpace = diskSpace + # Software descriptor. + self.software = software + # GPG public key. + self.publicKey = publicKey + + diff --git a/maf_three/MF/V3/Descriptors/Transform.py b/maf_three/MF/V3/Descriptors/Transform.py new file mode 100644 index 0000000..e18b19d --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Transform.py @@ -0,0 +1,16 @@ +from typing import List + + +class Transform: + # V3 transform descriptor. + def __init__(self, rotation: List[float], translation: List[float]): + """ + Axis-angle rotation vector. + The direction of the vector is the rotation axis. + The magnitude of the vector is rotation angle in radians. + """ + self.rotation = rotation + # Translation vector. + self.translation = translation + + diff --git a/maf_three/MF/V3/Descriptors/VideoFrame.py b/maf_three/MF/V3/Descriptors/VideoFrame.py new file mode 100644 index 0000000..2147fa3 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/VideoFrame.py @@ -0,0 +1,27 @@ +from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video +from MF.V3.Descriptors.Calibration import DetectedCard as MF_V3_Descriptors_Calibration_DetectedCard + + +class VideoFrame: + # Video frame descriptor. + def __init__(self, codec: MF_V3_Settings_Video_Video.Codec, format: MF_V3_Settings_Video_Video.Format, width: int, height: int, step: int, number: int, timestamp: int, duration: int, calibrationCard: MF_V3_Descriptors_Calibration_DetectedCard): + # Video codec. + self.codec = codec + # Pixel format. + self.format = format + # Image width. + self.width = width + # Image height. + self.height = height + # Image row step in bytes. + self.step = step + # Frame number. + self.number = number + # Frame timestamp. + self.timestamp = timestamp + # Frame duration. + self.duration = duration + # Calibration card detection. + self.calibrationCard = calibrationCard + + diff --git a/maf_three/MF/V3/Descriptors/Wifi.py b/maf_three/MF/V3/Descriptors/Wifi.py new file mode 100644 index 0000000..d8193e3 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Wifi.py @@ -0,0 +1,26 @@ +from typing import List + + +class Wifi: + # The wifi descriptor. + class Network: + # The wifi network descriptor. + def __init__(self, ssid: str, isPublic: bool, isActive: bool, password: str = None, quality: int = None): + # The service set identifier. + self.ssid = ssid + # Is the network public? + self.isPublic = isPublic + # Is the network active? + self.isActive = isActive + # The network password. + self.password = password + # Signal quality [0 ; 100]. + self.quality = quality + + def __init__(self, ssid: str, networks: List['Network']): + # The wifi ssid. + self.ssid = ssid + # The list of wifi networks. + self.networks = networks + + diff --git a/maf_three/MF/V3/Descriptors/__init__.py b/maf_three/MF/V3/Descriptors/__init__.py new file mode 100644 index 0000000..7e7658b --- /dev/null +++ b/maf_three/MF/V3/Descriptors/__init__.py @@ -0,0 +1,12 @@ +from MF.V3.Descriptors.ScanData import * +from MF.V3.Descriptors.ProjectActions import * +from MF.V3.Descriptors.Transform import * +from MF.V3.Descriptors.Wifi import * +from MF.V3.Descriptors.BoundingBox import * +from MF.V3.Descriptors.Project import * +from MF.V3.Descriptors.VideoFrame import * +from MF.V3.Descriptors.RemoveVertices import * +from MF.V3.Descriptors.Image import * +from MF.V3.Descriptors.Export import * +from MF.V3.Descriptors.Merge import * +from MF.V3.Descriptors.System import * diff --git a/maf_three/MF/V3/Settings/Advanced.py b/maf_three/MF/V3/Settings/Advanced.py new file mode 100644 index 0000000..b8a8e69 --- /dev/null +++ b/maf_three/MF/V3/Settings/Advanced.py @@ -0,0 +1,185 @@ +from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from typing import List + + +class Advanced: + # Advanced settings. + class Capture: + # Capture settings. + def __init__(self, horizontalFrequencies: List[int], verticalFrequencies: List[int], use: bool = None): + # Projector sample rate. + self.horizontalFrequencies = horizontalFrequencies + # Image sample rate. + self.verticalFrequencies = verticalFrequencies + # Use the capture settings. + self.use = use + + class Sampling: + # Sampling settings. + def __init__(self, projectorSampleRate: float = None, imageSampleRate: float = None, use: bool = None): + # Projector sample rate. + self.projectorSampleRate = projectorSampleRate + # Image sample rate. + self.imageSampleRate = imageSampleRate + # Use the sampling settings. + self.use = use + + class EdgeDetection: + # Edge detection settings. + def __init__(self, threshold: float = None, laplacianKernelRadius: int = None, gaussianBlurRadius: int = None, gaussianBlurStdDev: float = None, maximumWidthForProcessing: int = None, use: bool = None): + # The edge detection threshold. + self.threshold = threshold + # The Laplacian kernel radius. This must be in the range [1..5]. + self.laplacianKernelRadius = laplacianKernelRadius + """ + Gaussian blur kernel radius. (Optional) To disable, set to 0. + + The phase images can optionally blurred before taking the Laplacian to reduce noise. + However as a result, the detected edges are wider. + """ + self.gaussianBlurRadius = gaussianBlurRadius + """ + Gaussian blur kernel standard deviation. This parameter is ignored if + \p gaussianBlurSize is zero. + """ + self.gaussianBlurStdDev = gaussianBlurStdDev + """ + The maximum image width for processing. (Optional) To disable, set to 0. + + If this value is greater than zero, the phase images are resized to the maximum + width prior to computing the Laplacian and the the detected edges are then upsampled to the + original size. + + This would be done to speed up processing or to detect edges on a larger scale. + """ + self.maximumWidthForProcessing = maximumWidthForProcessing + # Use the edge detection settings. + self.use = use + + class PhaseFilter: + # Phase filter settings. + def __init__(self, kernelRadius: int = None, spatialWeightStdDev: float = None, use: bool = None): + """ + The filter kernel radius. + + A neighboring value must be within this radius to be included in the filter. + If the kernel radius is set to zero, the phase filtering is disabled. + """ + self.kernelRadius = kernelRadius + """ + The standard deviation of the spatial weights. + + The weight of a neighboring value is \f$ exp(-(r/s)^2) \f$ where \f$ r \f$ + is the distance to the central value and \f$ s \f$ is the spatial weight + standard deviation. + + If the spatial weight standard deviation is set to zero, all the spatial + weights are uniformly set to 1. + """ + self.spatialWeightStdDev = spatialWeightStdDev + # Use the phase filter settings. + self.use = use + + class AdaptiveSampling: + """ + Adaptive sampling settings + + Adaptive sampling will downsample points in regions of low detail + and keep points in regions of high detail. + """ + def __init__(self, rate: float, type: MF_V3_Settings_Scan_Scan.Processing.AdaptiveSampling.Type = None, use: bool = None): + # The sample rate [0..1] for the regions of low detail. + self.rate = rate + # Sampling type. + self.type = type + # Use the adaptive sampling settings. + self.use = use + + class PointClipping: + # Point32 clipping settings. + def __init__(self, transform: List[float], type: MF_V3_Settings_Scan_Scan.Processing.PointClipping.Type = None, use: bool = None): + # 4x4 transform mapping 3D points to the canonical point32 clipping coordinates. + self.transform = transform + # Point32 clipping type. + self.type = type + # Use the point32 clipping settings. + self.use = use + + class NormalEstimation: + # Normal estimation settings. + def __init__(self, method: MF_V3_Settings_Scan_Scan.Processing.NormalEstimation.Method = None, maximumNeighbourCount: int = None, maximumNeighbourRadius: float = None, useMaximumNeighbourCount: bool = None, useMaximumNeighbourRadius: bool = None, use: bool = None): + # Normal estimation method. + self.method = method + """ + Maximum number of nearest neighbors used to compute the normal. + This value is only used with the NORMAL_OPEN3D method. + """ + self.maximumNeighbourCount = maximumNeighbourCount + # Maximum radius for a point32 to be considered a neighbour. + self.maximumNeighbourRadius = maximumNeighbourRadius + self.useMaximumNeighbourCount = useMaximumNeighbourCount + self.useMaximumNeighbourRadius = useMaximumNeighbourRadius + # Use the normal estimation settings. + self.use = use + + class OutlierRemoval: + # Radius outlier removal settings. + def __init__(self, neighbourCount: int = None, neighbourRadius: float = None, use: bool = None): + # The minimum number of points within the radius for a point32 to be retained. + self.neighbourCount = neighbourCount + # The neighbour search radius. + self.neighbourRadius = neighbourRadius + # Use the outlier removal settings. + self.use = use + + class Remesh: + # Remesh settings. + def __init__(self, quality: MF_V3_Settings_Quality_Quality = None, voxelSize: float = None, depth: int = None, scale: float = None, linearInterpolation: bool = None, use: bool = None): + # Remesh quality preset. + self.quality = quality + # Voxel size. + self.voxelSize = voxelSize + # Depth. + self.depth = depth + # Scale. + self.scale = scale + # Linear Interpolation. + self.linearInterpolation = linearInterpolation + # Use the remesh settings. + self.use = use + + class Camera: + # Camera settings. + def __init__(self, useContinuousExposureValues: bool = None): + self.useContinuousExposureValues = useContinuousExposureValues + + class Turntable: + # Turntable settings. + def __init__(self, rampAngle: int = None): + # The angle in degrees to slow down the turntable at the end of a rotation. + self.rampAngle = rampAngle + + def __init__(self, capture: 'Capture' = None, sampling: 'Sampling' = None, edgeDetection: 'EdgeDetection' = None, phaseFilter: 'PhaseFilter' = None, adaptiveSampling: 'AdaptiveSampling' = None, normalEstimation: 'NormalEstimation' = None, outlierRemoval: 'OutlierRemoval' = None, remesh: 'Remesh' = None, camera: 'Camera' = None, turntable: 'Turntable' = None): + # Capture settings. + self.capture = capture + # Sampling settings. + self.sampling = sampling + # Edge detection settings. + self.edgeDetection = edgeDetection + # Phase filter settings. + self.phaseFilter = phaseFilter + # Adaptive sampling settings. + self.adaptiveSampling = adaptiveSampling + # Normal estimation settings. + self.normalEstimation = normalEstimation + # Radius outlier removal settings. + self.outlierRemoval = outlierRemoval + # Remesh settings. + self.remesh = remesh + # Camera settings. + self.camera = camera + # Turntable settings. + self.turntable = turntable + + diff --git a/maf_three/MF/V3/Settings/Align.py b/maf_three/MF/V3/Settings/Align.py new file mode 100644 index 0000000..33dbc32 --- /dev/null +++ b/maf_three/MF/V3/Settings/Align.py @@ -0,0 +1,82 @@ +from enum import Enum +from typing import List + + +class Align: + # Alignment settings. + class Points: + # Point pair alignment settings. + def __init__(self, points: List[float], absoluteError: float = None, relativeError: float = None, useAllPoints: bool = None): + # The set of corresponding point pairs. + self.points = points + # The maximum absolute error for a point pair to be an inlier to the model. + self.absoluteError = absoluteError + # The maximum error relative to the size of the aligned scans for a point pair to be an inlier to the model. + self.relativeError = relativeError + # Ignore alignment errors and use all selected points for alignment. + self.useAllPoints = useAllPoints + + class Ransac: + # Ransac alignment settings. + def __init__(self, downsampleVoxelSize: float = None, maximumFeatureRadius: float = None, maximumFeaturePointCount: int = None, maximumMatchDistance: float = None, minimumMatchSimilarity: float = None, mutualFilter: bool = None): + self.downsampleVoxelSize = downsampleVoxelSize + self.maximumFeatureRadius = maximumFeatureRadius + self.maximumFeaturePointCount = maximumFeaturePointCount + self.maximumMatchDistance = maximumMatchDistance + self.minimumMatchSimilarity = minimumMatchSimilarity + self.mutualFilter = mutualFilter + + class ICP: + # Iterative closest point alignment settings. + def __init__(self, matchDistance: float): + # The maximum distance for two points to be considered a match. + self.matchDistance = matchDistance + + class Rough: + # Rough alignment settings. + # Rough alignment methods. + class Method(Enum): + Empty = "None" # No rough alignment. + FastGlobal = "FastGlobal" # Fast global alignment. + Ransac = "Ransac" # Ransac alignment. + Points = "Points" # Point pair alignment. + + def __init__(self, method: 'Method', ransac: 'Align.Ransac' = None, points: 'Align.Points' = None): + # Rough alignment method. + self.method = method + # FastGlobal fastGlobal; + self.ransac = ransac + # Point pair alignment settings. + self.points = points + + class Fine: + # Fine alignment settings. + # Fine alignment methods. + class Method(Enum): + Empty = "None" # No fine alignment. + ICP = "ICP" # Iterative closest point alignment. + + class Transform: + def __init__(self, rotation: List[float], translation: List[float]): + self.rotation = rotation + self.translation = translation + + def __init__(self, method: 'Method', icp: 'Align.ICP' = None, initialTransform: 'Transform' = None): + # Fine alignment method. + self.method = method + # Iterative closest point settings. + self.icp = icp + # The initial transform for fine alignment. + self.initialTransform = initialTransform + + def __init__(self, source: int, target: int, rough: 'Rough' = None, fine: 'Fine' = None): + # Index of the scan or group to align. + self.source = source + # Index of the scan or group to align to. + self.target = target + # Rough alignment settings. + self.rough = rough + # Fine alignment settings. + self.fine = fine + + diff --git a/maf_three/MF/V3/Settings/AutoFocus.py b/maf_three/MF/V3/Settings/AutoFocus.py new file mode 100644 index 0000000..5a5ed13 --- /dev/null +++ b/maf_three/MF/V3/Settings/AutoFocus.py @@ -0,0 +1,24 @@ +from MF.V3.Settings.Rectangle import Rectangle as MF_V3_Settings_Rectangle_Rectangle +from typing import List + + +class AutoFocus: + # Auto focus settings. + class Camera: + # Auto focus camera settings. + def __init__(self, index: int, box: MF_V3_Settings_Rectangle_Rectangle = None): + # The index of the camera on which to apply auto focus. + self.index = index + # The image rectangle in video image pixels on which to apply auto focus. + self.box = box + + def __init__(self, cameras: List['Camera'], applyAll: bool): + # The set of cameras on which to apply auto focus. + self.cameras = cameras + """ + Apply the final focus value to both cameras. + This setting is ignored if more than one camera is selected. + """ + self.applyAll = applyAll + + diff --git a/maf_three/MF/V3/Settings/BoundingBox.py b/maf_three/MF/V3/Settings/BoundingBox.py new file mode 100644 index 0000000..3dd48ac --- /dev/null +++ b/maf_three/MF/V3/Settings/BoundingBox.py @@ -0,0 +1,15 @@ +from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection + + +class BoundingBox: + # Bounding box settings. + def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool): + # The scan selection. + self.selection = selection + """ + If `true`, align the bounding box with the world axes. + Otherwise orient the bounding box with the scans. + """ + self.axisAligned = axisAligned + + diff --git a/maf_three/MF/V3/Settings/Camera.py b/maf_three/MF/V3/Settings/Camera.py new file mode 100644 index 0000000..fc58f6a --- /dev/null +++ b/maf_three/MF/V3/Settings/Camera.py @@ -0,0 +1,20 @@ +from typing import List + + +class Camera: + # Camera settings. + def __init__(self, selection: List[int], autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None): + # Camera selection. Default is all cameras. + self.selection = selection + # Auto exposure. + self.autoExposure = autoExposure + # Exposure. + self.exposure = exposure + # Analog gain. + self.analogGain = analogGain + # Digital gain. + self.digitalGain = digitalGain + # Focus value. + self.focus = focus + + diff --git a/maf_three/MF/V3/Settings/Capture.py b/maf_three/MF/V3/Settings/Capture.py new file mode 100644 index 0000000..673ff46 --- /dev/null +++ b/maf_three/MF/V3/Settings/Capture.py @@ -0,0 +1,25 @@ +from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality +from typing import List + + +class Capture: + # Capture settings. + def __init__(self, horizontalFrequencies: List[int], verticalFrequencies: List[int], quality: MF_V3_Settings_Quality_Quality = None, texture: bool = None, calibrationCard: bool = None, blendCount: int = None, horizontalBlendFrequency: int = None, verticalBlendFrequency: int = None): + # Horizontal pattern frequencies. + self.horizontalFrequencies = horizontalFrequencies + # Vertical pattern frequencies. + self.verticalFrequencies = verticalFrequencies + # Capture quality preset. + self.quality = quality + # Capture texture. + self.texture = texture + # Detect the calibration card. + self.calibrationCard = calibrationCard + # The number of capture images blended together for noise reduction. + self.blendCount = blendCount + # The starting horizontal frequency for blending capture images for noise reduction. + self.horizontalBlendFrequency = horizontalBlendFrequency + # The starting vertical frequency for blending capture images for noise reduction. + self.verticalBlendFrequency = verticalBlendFrequency + + diff --git a/maf_three/MF/V3/Settings/Export.py b/maf_three/MF/V3/Settings/Export.py new file mode 100644 index 0000000..46ea8ee --- /dev/null +++ b/maf_three/MF/V3/Settings/Export.py @@ -0,0 +1,27 @@ +from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection +from enum import Enum + + +class Export: + # Export settings. + # Scan export formats. + class Format(Enum): + ply = "ply" # Polygon format. + dae = "dae" # Digital asset exchange format. + fbx = "fbx" # Autodesk format. + glb = "glb" # GL transmission format. + obj = "obj" # Wavefront format. + stl = "stl" # Stereolithography format. + xyz = "xyz" # Chemical format. + + def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: 'Format' = None): + # The scan selection. + self.selection = selection + # Export textures. + self.texture = texture + # Merge the scans into a single file. + self.merge = merge + # The export format. + self.format = format + + diff --git a/maf_three/MF/V3/Settings/Group.py b/maf_three/MF/V3/Settings/Group.py new file mode 100644 index 0000000..f3d4ac7 --- /dev/null +++ b/maf_three/MF/V3/Settings/Group.py @@ -0,0 +1,26 @@ +from typing import List + + +class Group: + # Scan group settings. + def __init__(self, index: int, color: List[float], rotation: List[float], translation: List[float], name: str = None, visible: bool = None, collapsed: bool = None): + # The unique group index that identifies the group within the group tree. + self.index = index + # Color in the renderer. + self.color = color + """ + Axis-angle rotation vector. + The direction of the vector is the rotation axis. + The magnitude of the vector is rotation angle in radians. + """ + self.rotation = rotation + # Translation vector. + self.translation = translation + # Group name. + self.name = name + # Visibility in the renderer. + self.visible = visible + # Collapsed state in the group tree. + self.collapsed = collapsed + + diff --git a/maf_three/MF/V3/Settings/I18n.py b/maf_three/MF/V3/Settings/I18n.py new file mode 100644 index 0000000..b6d2957 --- /dev/null +++ b/maf_three/MF/V3/Settings/I18n.py @@ -0,0 +1,16 @@ +from enum import Enum + + +class I18n: + # I18n language settings. + # Available languages. + class Language(Enum): + en = "en" + fr = "fr" + de = "de" + + def __init__(self, language: 'Language' = None): + # The language setting. Supported languages are ["en", "fr", "de"]. + self.language = language + + diff --git a/maf_three/MF/V3/Settings/Merge.py b/maf_three/MF/V3/Settings/Merge.py new file mode 100644 index 0000000..21807fb --- /dev/null +++ b/maf_three/MF/V3/Settings/Merge.py @@ -0,0 +1,85 @@ +from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection +from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality +from enum import Enum + + +class Merge: + # Scan merge settings. + class Remesh: + # Remesh settings. + # Remesh method. + class Method(Enum): + FlowTriangles = "FlowTriangles" # Flow remesh as triangles. + FlowQuads = "FlowQuads" # Flow remesh as quads. + FlowQuadDominant = "FlowQuadDominant" # Flow remesh as quad-dominant mesh. + PoissonTriangles = "PoissonTriangles" # Poisson remesh as triangles. + + class Flow: + # Flow remesh settings + def __init__(self, scale: float = None, faceCount: int = None, vertexCount: int = None, creaseAngleThreshold: float = None, extrinsicSmoothness: bool = None, alignToBoundaries: bool = None, smoothIterations: int = None, knnPoints: int = None, deterministic: bool = None): + # Output resolution scale. Smaller means more faces. + self.scale = scale + # The approximate number of remeshed faces. + self.faceCount = faceCount + # The approximate number of remeshed vertices. + self.vertexCount = vertexCount + # The crease angle threshold. + self.creaseAngleThreshold = creaseAngleThreshold + # Use extrinsic smoothness. + self.extrinsicSmoothness = extrinsicSmoothness + # Align mesh to boundaries. + self.alignToBoundaries = alignToBoundaries + # The number of smoothing iterations. + self.smoothIterations = smoothIterations + # The number of KNN points (point cloud input only). + self.knnPoints = knnPoints + # Use deterministic (repeatable) remeshing. + self.deterministic = deterministic + + class Poisson: + def __init__(self, voxelSize: float = None, depth: int = None, scale: float = None, linearInterpolation: bool = None): + # Voxel size. + self.voxelSize = voxelSize + # Depth. + self.depth = depth + # Scale. + self.scale = scale + # Linear Interpolation. + self.linearInterpolation = linearInterpolation + + def __init__(self, method: 'Method' = None, quality: MF_V3_Settings_Quality_Quality = None, flow: 'Flow' = None, poisson: 'Poisson' = None, voxelSize: float = None, depth: int = None, scale: float = None, linearInterpolation: bool = None): + # Remesh method. + self.method = method + # Remesh quality. + self.quality = quality + # Flow remesh options (Ignored if method is 'Poison'). + self.flow = flow + # Poisson remesh options (Ignored if method is not 'Poisson'). + self.poisson = poisson + """ Temporary for backwards compatibility + Voxel size.""" + self.voxelSize = voxelSize + # Depth. + self.depth = depth + # Scale. + self.scale = scale + # Linear Interpolation. + self.linearInterpolation = linearInterpolation + + class Simplify: + # Simplify settings. + def __init__(self, triangleCount: int): + # Target triangle count. + self.triangleCount = triangleCount + + def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: 'Remesh' = None, simplify: 'Simplify' = None, texturize: bool = None): + # The scan selection. + self.selection = selection + # Remesh settings. + self.remesh = remesh + # Simplify settings. + self.simplify = simplify + # Apply textures to the merged mesh. + self.texturize = texturize + + diff --git a/maf_three/MF/V3/Settings/NewGroup.py b/maf_three/MF/V3/Settings/NewGroup.py new file mode 100644 index 0000000..792d90d --- /dev/null +++ b/maf_three/MF/V3/Settings/NewGroup.py @@ -0,0 +1,32 @@ +from typing import List + + +class NewGroup: + # Scan group settings. + def __init__(self, color: List[float], rotation: List[float], translation: List[float], parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None): + # Group color. + self.color = color + """ + Group axis-angle rotation vector. + The direction of the vector is the rotation axis. + The magnitude of the vector is rotation angle in radians. + """ + self.rotation = rotation + # Group translation vector. + self.translation = translation + """ + The index of the parent group in which the new group is created. + If unspecified the new group is added to the root of the group tree. + """ + self.parentIndex = parentIndex + """ + Group base name. + The new group name will start with the base name followed by a unique index number chosen by the backend. + """ + self.baseName = baseName + # Group visibility. + self.visible = visible + # Collapsed state in the group tree. + self.collapsed = collapsed + + diff --git a/maf_three/MF/V3/Settings/Project.py b/maf_three/MF/V3/Settings/Project.py new file mode 100644 index 0000000..9d5f56f --- /dev/null +++ b/maf_three/MF/V3/Settings/Project.py @@ -0,0 +1,10 @@ +class Project: + # Project settings. + def __init__(self, index: int = None, name: str = None): + """ The index identifying which project the settings applies to. + If undefined the current open project is used.""" + self.index = index + # Project name. + self.name = name + + diff --git a/maf_three/MF/V3/Settings/Projector.py b/maf_three/MF/V3/Settings/Projector.py new file mode 100644 index 0000000..ecf88ae --- /dev/null +++ b/maf_three/MF/V3/Settings/Projector.py @@ -0,0 +1,58 @@ +from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video +from MF.V3.Settings.Rectangle import Rectangle as MF_V3_Settings_Rectangle_Rectangle +from enum import Enum +from typing import List + + +class Projector: + # Projector settings. + # Pattern orientation. + class Orientation(Enum): + Horizontal = "Horizontal" # Horizontal pattern. Image columns are identical. + Vertical = "Vertical" # Vertical pattern. Image rows are identical. + + class Pattern: + # Structured light pattern. + def __init__(self, orientation: 'Projector.Orientation', frequency: int, phase: int): + # Pattern orientation. + self.orientation = orientation + # Pattern frequency index. [0 - 8] + self.frequency = frequency + # Pattern phase. [0 - 2] + self.phase = phase + + class Image: + # Projector image settings + class Source: + # Image source. + def __init__(self, format: MF_V3_Settings_Video_Video.Format, width: int, height: int, step: int, fixAspectRatio: bool): + # Source image format + self.format = format + # Source image width. + self.width = width + # Source image height. + self.height = height + # Source image step in bytes. + self.step = step + # Fix the source aspect ratio to the target rectangle. + self.fixAspectRatio = fixAspectRatio + + def __init__(self, source: 'Source', target: MF_V3_Settings_Rectangle_Rectangle): + # Image source. + self.source = source + # Image target rectangle. + self.target = target + + def __init__(self, color: List[float], on: bool = None, brightness: float = None, pattern: 'Pattern' = None, image: 'Image' = None): + # Solid color + self.color = color + # Projector on/off. + self.on = on + # Projector brightness. + self.brightness = brightness + # Structured light pattern. + self.pattern = pattern + # Image to project + self.image = image + + diff --git a/maf_three/MF/V3/Settings/Quality.py b/maf_three/MF/V3/Settings/Quality.py new file mode 100644 index 0000000..a1d5011 --- /dev/null +++ b/maf_three/MF/V3/Settings/Quality.py @@ -0,0 +1,10 @@ +from enum import Enum + + +# Quality settings. +class Quality(Enum): + Low = "Low" # Low quality. + Medium = "Medium" # Medium quality. + High = "High" # High quality. + + diff --git a/maf_three/MF/V3/Settings/Rectangle.py b/maf_three/MF/V3/Settings/Rectangle.py new file mode 100644 index 0000000..8390e02 --- /dev/null +++ b/maf_three/MF/V3/Settings/Rectangle.py @@ -0,0 +1,13 @@ +class Rectangle: + # Rectangle settings. + def __init__(self, x: int, y: int, width: int, height: int): + # Rectangle x offset. + self.x = x + # Rectangle y offset. + self.y = y + # Rectangle width. + self.width = width + # Rectangle height. + self.height = height + + diff --git a/maf_three/MF/V3/Settings/Remesh.py b/maf_three/MF/V3/Settings/Remesh.py new file mode 100644 index 0000000..832d760 --- /dev/null +++ b/maf_three/MF/V3/Settings/Remesh.py @@ -0,0 +1,36 @@ +from enum import Enum + + +class Remesh: + # Field aligned remesh settings. + # Types of remesh output. + class Type(Enum): + triangle = "triangle" # Triangle mesh output. + quad = "quad" # Quad mesh output. + quadDominant = "quadDominant" # Quad-dominant mesh output. + + def __init__(self, scan: int, type: 'Type' = None, scale: float = None, faceCount: int = None, vertexCount: int = None, creaseAngleThreshold: float = None, extrinsicSmoothness: bool = None, alignToBoundaries: bool = None, smoothIterations: int = None, knnPoints: int = None, deterministic: bool = None): + # The scan index. + self.scan = scan + # The type of output mesh. + self.type = type + # Scale + self.scale = scale + # The approximate number of remeshed faces. + self.faceCount = faceCount + # The approximate number of remeshed vertices. + self.vertexCount = vertexCount + # The crease angle threshold. + self.creaseAngleThreshold = creaseAngleThreshold + # Use extrinsic smoothness. + self.extrinsicSmoothness = extrinsicSmoothness + # Align mesh to boundaries. + self.alignToBoundaries = alignToBoundaries + # The number of smoothing iterations. + self.smoothIterations = smoothIterations + # The number of KNN points (point cloud input only). + self.knnPoints = knnPoints + # Use deterministic (repeatable) remeshing. + self.deterministic = deterministic + + diff --git a/maf_three/MF/V3/Settings/RemoveVertices.py b/maf_three/MF/V3/Settings/RemoveVertices.py new file mode 100644 index 0000000..0fe0e53 --- /dev/null +++ b/maf_three/MF/V3/Settings/RemoveVertices.py @@ -0,0 +1,10 @@ +from typing import List + + +class RemoveVertices: + # Remove vertices. + def __init__(self, scans: List[int]): + # The scans indexes for which vertices are removed. + self.scans = scans + + diff --git a/maf_three/MF/V3/Settings/Scan.py b/maf_three/MF/V3/Settings/Scan.py new file mode 100644 index 0000000..a0c8adb --- /dev/null +++ b/maf_three/MF/V3/Settings/Scan.py @@ -0,0 +1,157 @@ +from enum import Enum +from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture +from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector +from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera +from typing import List + + +class Scan: + # Scan settings. + class Processing: + # Scan processing settings. + class PhaseEdgeDetection: + """ + Phase edge detection settings. + + Phase edge detection produces a binary mask indicating the edges of a horizontal/vertical pair of phase images. Since flat geometries give a constant phase image gradient, we use the second derivative (Laplacian) of the phase image to detect edges rather than the gradient. + + The edge mask generated by phase edge detection is an input to both phase filtering and adaptive sampling. If neither of these are enabled, the phase edge detection settings have no effect on the output point cloud. + """ + def __init__(self, threshold: float, laplacianKernelRadius: int, gaussianBlurRadius: int, gaussianBlurStdDev: float, maximumWidthForProcessing: int): + # The edge detection threshold. + self.threshold = threshold + # The Laplacian kernel radius. This must be in the range [1..5]. + self.laplacianKernelRadius = laplacianKernelRadius + """ + Gaussian blur kernel radius. (Optional) To disable, set to 0. + The phase images can optionally blurred before taking the Laplacian to reduce noise. + However as a result, the detected edges are wider. + """ + self.gaussianBlurRadius = gaussianBlurRadius + """ + Gaussian blur kernel standard deviation. + This parameter is ignored if `gaussianBlurSize` is zero. + """ + self.gaussianBlurStdDev = gaussianBlurStdDev + """ + The maximum image width for processing. (Optional) To disable, set to 0. + If this value is greater than zero, the phase images are resized to the maximum width prior + to computing the Laplacian and the the detected edges are then upsampled to the original size. + This would be done to speed up processing or to detect edges on a larger scale. + """ + self.maximumWidthForProcessing = maximumWidthForProcessing + + class PhaseFilter: + # Phase filter settings. + def __init__(self, kernelRadius: int, spatialWeightStdDev: float): + """ + The filter kernel radius. + A neighboring value must be within this radius to be included in the filter. + If the kernel radius is set to zero, the phase filtering is disabled. + """ + self.kernelRadius = kernelRadius + """ + The standard deviation of the spatial weights. + The weight of a neighboring value is $\exp(-(r/s)^2)$ where $r$ is the distance + to the central value and $s$ is the spatial weight standard deviation. + If the spatial weight standard deviation is set to zero, all the spatial + weights are uniformly set to 1. + """ + self.spatialWeightStdDev = spatialWeightStdDev + + class AdaptiveSampling: + """ + Adaptive sampling settings + + Adaptive sampling will downsample points in regions of low detail + and keep points in regions of high detail. + """ + class Type(Enum): + NONE = "NONE" # Do not use adaptive sampling. + REGULAR = "REGULAR" # Use a regular sampling mask in regions of low detail. + RANDOM = "RANDOM" # Use a random sampling mask in regions of low detail. + + def __init__(self, type: 'Type', rate: float): + # Sampling type. + self.type = type + # The sample rate [0..1] for the regions of low detail. + self.rate = rate + + class PointClipping: + # Point clipping settings. + # Point clipping type. + class Type(Enum): + OutsideCube = "OutsideCube" # Clip points outside a unit cube. + OutsideCylinder = "OutsideCylinder" # Clip points outside a unit cylinder. + OutsideSphere = "OutsideSphere" # Clip points outside a unit sphere. + InsideCube = "InsideCube" # Clip points inside a unit cube. + InsideCylinder = "InsideCylinder" # Clip points inside a unit cylinder. + InsideSphere = "InsideSphere" # Clip points inside a unit sphere. + + def __init__(self, type: 'Type', transform: List[float]): + # Point clipping type. + self.type = type + # 4x4 transform mapping 3D points to the canonical point clipping coordinates. + self.transform = transform + + class NormalEstimation: + # Normal estimation settings. + class Method(Enum): + NORMAL_LLS = "NORMAL_LLS" # Linear least squares method + NORMAL_OPEN3D = "NORMAL_OPEN3D" # Open3D method using KD tree search for nearest neighbors + + def __init__(self, method: 'Method', maximumNeighbourCount: int, maximumNeighbourRadius: float, useMaximumNeighbourCount: bool, useMaximumNeighbourRadius: bool): + # Normal estimation method. + self.method = method + """ + Maximum number of nearest neighbors used to compute the normal. + This value is only used with the NORMAL_OPEN3D method. + """ + self.maximumNeighbourCount = maximumNeighbourCount + # Maximum radius for a point to be considered a neighbour. + self.maximumNeighbourRadius = maximumNeighbourRadius + # Use the maximum neighbour count. + self.useMaximumNeighbourCount = useMaximumNeighbourCount + # Use the maximum neighbour radius. + self.useMaximumNeighbourRadius = useMaximumNeighbourRadius + + class OutlierRemoval: + # Outlier removal settings. + def __init__(self, neighbourCount: int, neighbourRadius: float): + # The minimum number of points within the radius for a point to be retained. + self.neighbourCount = neighbourCount + # The neighbour search radius. + self.neighbourRadius = neighbourRadius + + def __init__(self, pointClipping: List['PointClipping'], projectorSampleRate: float = None, imageSampleRate: float = None, edgeDetection: 'PhaseEdgeDetection' = None, phaseFilter: 'PhaseFilter' = None, adaptiveSampling: 'AdaptiveSampling' = None, normalEstimation: 'NormalEstimation' = None, outlierRemoval: 'OutlierRemoval' = None): + # Point clipping settings. + self.pointClipping = pointClipping + # Projector sample rate. + self.projectorSampleRate = projectorSampleRate + # Image sample rate. + self.imageSampleRate = imageSampleRate + # Phase edge detection settings. + self.edgeDetection = edgeDetection + # Phase filter settings. + self.phaseFilter = phaseFilter + # Adaptive sampling settings. + self.adaptiveSampling = adaptiveSampling + # Normal estimation settings. + self.normalEstimation = normalEstimation + # Outlier removal settings. + self.outlierRemoval = outlierRemoval + + def __init__(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: 'Processing' = None): + # Camera settings. + self.camera = camera + # Projector settings. + self.projector = projector + # Turntable settings. + self.turntable = turntable + # Capture settings. + self.capture = capture + # Processing settings. + self.processing = processing + + diff --git a/maf_three/MF/V3/Settings/ScanData.py b/maf_three/MF/V3/Settings/ScanData.py new file mode 100644 index 0000000..c1f534e --- /dev/null +++ b/maf_three/MF/V3/Settings/ScanData.py @@ -0,0 +1,40 @@ +from enum import Enum +from typing import List + + +class ScanData: + # Scan data request. + # Scan buffer type. + class Buffer(Enum): + Position = "Position" # Vertex position. + Normal = "Normal" # Vertex normal. + Color = "Color" # Vertex color. + UV = "UV" # Vertex UVs + Triangle = "Triangle" # Triangle index. + Texture = "Texture" # Texture. + All = "All" # All buffer types. + + # Scan metadata type. + class Metadata(Enum): + Mean = "Mean" # The mean (centroid) of the vertex positions. + StdDev = "StdDev" # The standard deviation of the vertex positions. + AxisAlignedBoundingBox = "AxisAlignedBoundingBox" # The axis-aligned bounding box of the vertex positions. + + # The merge processing step. + class MergeStep(Enum): + Combined = "Combined" # The scan meshes are simply combined into a single mesh. + Remeshed = "Remeshed" # The combined mesh is remeshed to give a single geometric surface. + Simplified = "Simplified" # The combined or remeshed mesh is simplified to a reduced number of triangles. + Textured = "Textured" # The merged mesh has been textured. + + def __init__(self, index: int, buffers: List['Buffer'], metadata: List['Metadata'], mergeStep: 'MergeStep' = None): + # Requested index of the scan in the current open project. + self.index = index + # Requested scan buffers. + self.buffers = buffers + # Requested scan metadata. + self.metadata = metadata + # The merge process step if requesting merge data. + self.mergeStep = mergeStep + + diff --git a/maf_three/MF/V3/Settings/ScanSelection.py b/maf_three/MF/V3/Settings/ScanSelection.py new file mode 100644 index 0000000..ed2e6be --- /dev/null +++ b/maf_three/MF/V3/Settings/ScanSelection.py @@ -0,0 +1,22 @@ +from enum import Enum +from typing import List + + +class ScanSelection: + # Scan selection. + # Scan selection mode. + class Mode(Enum): + selected = "selected" # Select user-selected groups. + visible = "visible" # Select visible scans. + all = "all" # Select all scans. + + def __init__(self, mode: 'Mode', groups: List[int]): + # The scan selection mode. + self.mode = mode + """ + The set of user-selected groups. + These are only used if the selection mode is 'selected'. + """ + self.groups = groups + + diff --git a/maf_three/MF/V3/Settings/Scanner.py b/maf_three/MF/V3/Settings/Scanner.py new file mode 100644 index 0000000..f21e0ca --- /dev/null +++ b/maf_three/MF/V3/Settings/Scanner.py @@ -0,0 +1,37 @@ +from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials +from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n +from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer +from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture +from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector +from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style +from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software +from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera +from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced + + +class Scanner: + # Scanner settings. + def __init__(self, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None): + # Advanced settings. + self.advanced = advanced + # Camera settings. + self.camera = camera + # Capture settings. + self.capture = capture + # I18n settings. + self.i18n = i18n + # Projector settings. + self.projector = projector + # Style settings. + self.style = style + # Turntable settings. + self.turntable = turntable + # Tutorials settings. + self.tutorials = tutorials + # Viewer settings. + self.viewer = viewer + # Software settings. + self.software = software + + diff --git a/maf_three/MF/V3/Settings/Software.py b/maf_three/MF/V3/Settings/Software.py new file mode 100644 index 0000000..8ab2263 --- /dev/null +++ b/maf_three/MF/V3/Settings/Software.py @@ -0,0 +1,20 @@ +from enum import Enum +from typing import List + + +class Software: + # V3 software settings. + # Software package types. + class Package(Enum): + server = "server" # The server software package. + frontend = "frontend" # The frontend software package. + + def __init__(self, installed: List['Package'], available: List['Package'], nightlyIncluded: bool = None): + # Request installed software packages. If undefined all installed packages are returned. + self.installed = installed + # Request available software packages. If undefined all available packages are returned. + self.available = available + # Permit nightly release upgrades. + self.nightlyIncluded = nightlyIncluded + + diff --git a/maf_three/MF/V3/Settings/Style.py b/maf_three/MF/V3/Settings/Style.py new file mode 100644 index 0000000..1cfdfc3 --- /dev/null +++ b/maf_three/MF/V3/Settings/Style.py @@ -0,0 +1,15 @@ +from enum import Enum + + +class Style: + # Style settings. + # Themes. + class Theme(Enum): + Light = "Light" # Light mode. + Dark = "Dark" # Dark mode. + + def __init__(self, theme: 'Theme' = None): + # Theme setting. + self.theme = theme + + diff --git a/maf_three/MF/V3/Settings/Turntable.py b/maf_three/MF/V3/Settings/Turntable.py new file mode 100644 index 0000000..b3b3063 --- /dev/null +++ b/maf_three/MF/V3/Settings/Turntable.py @@ -0,0 +1,11 @@ +class Turntable: + # Turntable settings. + def __init__(self, scans: int, sweep: int, use: bool = None): + # The number of turntable scans. + self.scans = scans + # Turntable angle sweep in degrees. + self.sweep = sweep + # Use the turntable. + self.use = use + + diff --git a/maf_three/MF/V3/Settings/Tutorials.py b/maf_three/MF/V3/Settings/Tutorials.py new file mode 100644 index 0000000..19d34f6 --- /dev/null +++ b/maf_three/MF/V3/Settings/Tutorials.py @@ -0,0 +1,18 @@ +from typing import List + + +class Tutorials: + # Tutorials settings. + class Viewed: + # Viewed tutorials. + def __init__(self, pages: List[str]): + # Viewed tutorials pages. + self.pages = pages + + def __init__(self, show: bool = None, viewed: 'Viewed' = None): + # Show tutorials. + self.show = show + # Viewed tutorials. + self.viewed = viewed + + diff --git a/maf_three/MF/V3/Settings/Upgrade.py b/maf_three/MF/V3/Settings/Upgrade.py new file mode 100644 index 0000000..3015efa --- /dev/null +++ b/maf_three/MF/V3/Settings/Upgrade.py @@ -0,0 +1,9 @@ +class Upgrade: + # Upgrade settings. + def __init__(self, majorVersion: bool = None, stable: bool = None): + # Upgrade major version which can have breaking API changes. + self.majorVersion = majorVersion + # Install the latest stable version. + self.stable = stable + + diff --git a/maf_three/MF/V3/Settings/Video.py b/maf_three/MF/V3/Settings/Video.py new file mode 100644 index 0000000..8a68ce2 --- /dev/null +++ b/maf_three/MF/V3/Settings/Video.py @@ -0,0 +1,31 @@ +from enum import Enum + + +class Video: + # Video settings. + # Video codecs. + class Codec(Enum): + NoCodec = "NoCodec" # No codec specified. + RAW = "RAW" # Raw encoding. + JPEG = "JPEG" # JPEG encoding. + H264 = "H264" # H264 encoding. + + # Pixel formats. + class Format(Enum): + NoFormat = "NoFormat" # No format specified. + RGB565 = "RGB565" # RGB565 16-bit + RGB888 = "RGB888" # RGB888 24-bit. + BGR888 = "BGR888" # BGR888 24-bit. + YUV420 = "YUV420" # YUV 420 planar. + + def __init__(self, codec: 'Codec', format: 'Format', width: int, height: int): + # Video codec. + self.codec = codec + # Pixel format. + self.format = format + # Image width. + self.width = width + # Image height. + self.height = height + + diff --git a/maf_three/MF/V3/Settings/Viewer.py b/maf_three/MF/V3/Settings/Viewer.py new file mode 100644 index 0000000..f797ad1 --- /dev/null +++ b/maf_three/MF/V3/Settings/Viewer.py @@ -0,0 +1,7 @@ +class Viewer: + # 3D Viewer settings. + def __init__(self, textureOpacity: float = None): + # Texture opacity. + self.textureOpacity = textureOpacity + + diff --git a/maf_three/MF/V3/Settings/Wifi.py b/maf_three/MF/V3/Settings/Wifi.py new file mode 100644 index 0000000..bc7b529 --- /dev/null +++ b/maf_three/MF/V3/Settings/Wifi.py @@ -0,0 +1,9 @@ +class Wifi: + # Wifi connection settings. + def __init__(self, ssid: str, password: str): + # The wifi ssid. + self.ssid = ssid + # The wifi password. + self.password = password + + diff --git a/maf_three/MF/V3/Settings/__init__.py b/maf_three/MF/V3/Settings/__init__.py new file mode 100644 index 0000000..c49d345 --- /dev/null +++ b/maf_three/MF/V3/Settings/__init__.py @@ -0,0 +1,29 @@ +from MF.V3.Settings.Turntable import * +from MF.V3.Settings.AutoFocus import * +from MF.V3.Settings.NewGroup import * +from MF.V3.Settings.Scanner import * +from MF.V3.Settings.RemoveVertices import * +from MF.V3.Settings.Wifi import * +from MF.V3.Settings.I18n import * +from MF.V3.Settings.Video import * +from MF.V3.Settings.ScanSelection import * +from MF.V3.Settings.Remesh import * +from MF.V3.Settings.Rectangle import * +from MF.V3.Settings.Viewer import * +from MF.V3.Settings.Quality import * +from MF.V3.Settings.Export import * +from MF.V3.Settings.Style import * +from MF.V3.Settings.Software import * +from MF.V3.Settings.Capture import * +from MF.V3.Settings.Tutorials import * +from MF.V3.Settings.BoundingBox import * +from MF.V3.Settings.Merge import * +from MF.V3.Settings.Align import * +from MF.V3.Settings.Camera import * +from MF.V3.Settings.Upgrade import * +from MF.V3.Settings.Projector import * +from MF.V3.Settings.Project import * +from MF.V3.Settings.ScanData import * +from MF.V3.Settings.Group import * +from MF.V3.Settings.Advanced import * +from MF.V3.Settings.Scan import * diff --git a/maf_three/MF/V3/Task.py b/maf_three/MF/V3/Task.py new file mode 100644 index 0000000..95529af --- /dev/null +++ b/maf_three/MF/V3/Task.py @@ -0,0 +1,77 @@ +from enum import Enum +from google.protobuf import any_pb2 as _any_pb2 + + +class TaskState(Enum): + Empty = "None" # The task state is not defined. + Sent = "Sent" # The task has been sent by the client. + Received = "Received" # The task has been received by the server. + Started = "Started" # The task started by the server. + Completed = "Completed" # The task is completed by the server. + Cancelled = "Cancelled" # The task has been cancelled by the client. + Failed = "Failed" # The task has failed. A string describing the error is returned with the task. + Dropped = "Dropped" # The task has not been received by the server, or task IDs were sent out of sequence. + Disconnected = "Disconnected" # The client has been disconnected from the server before the task could finish. + + +class Task: + """* + Generic task message for the Three Scanner. + + The task message is the generic message used for requesting a task of the Three Scanner and receiving updates and results. + + Example: Apply camera settings with the "SetCameras" task. + + > Example request: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetCameras" + "Input":{ + "analogGain":256, + "digitalGain":128, + "exposure":18000 + }, + } + } + ``` + + > Example response: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetCameras" + "Input":{ + "analogGain":256, + "digitalGain":512, + "exposure":18000 + }, + "Output":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":512}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "State":"Completed" + } + } + ``` + """ + def __init__(self, Index: int, Type: str, Input: _any_pb2 = None, Output: _any_pb2 = None, State: 'TaskState' = None, Error: str = None): + # A unique identifier generated by the client. This identifier associates all incoming and outgoing task messages with a specific task requested by the client. + self.Index = Index + # The string identifying the task type. See task definitions for the list of valid task strings. + self.Type = Type + # Optional input message. See each task definition for details. + self.Input = Input + # Optional output message. See each task definition for details. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + diff --git a/maf_three/MF/V3/Tasks/AddMergeToProject.py b/maf_three/MF/V3/Tasks/AddMergeToProject.py new file mode 100644 index 0000000..45d53ff --- /dev/null +++ b/maf_three/MF/V3/Tasks/AddMergeToProject.py @@ -0,0 +1,66 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class AddMergeToProject: + """* + Add a merged scan to the current project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"AddMergeToProject" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"AddMergeToProject", + "Output":{ + "groups":[ + { + "index":1, + "name":"Scan-1", + "scan": 1, + "color":[0.5, 0.8, 0.3] + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `AddMergeToProject` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "AddMergeToProject" + self.Type = Type + + class Response: + # Server response for the `AddMergeToProject` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "AddMergeToProject" + self.Type = Type + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/Align.py b/maf_three/MF/V3/Tasks/Align.py new file mode 100644 index 0000000..64c10f6 --- /dev/null +++ b/maf_three/MF/V3/Tasks/Align.py @@ -0,0 +1,77 @@ +from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align +from MF.V3.Descriptors.Transform import Transform as MF_V3_Descriptors_Transform_Transform +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class Align: + """* + Align two scan groups. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Align", + "Input":{ + "source":1, + "target":2, + "rough":{"method": "FastGlobal"}, + "fine":{"method": "ICP"} + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Align", + "Input":{ + "source":1, + "target":2, + "rough":{"method": "FastGlobal"}, + "fine":{"method": "ICP"} + }, + "Output":{ + "rotation":[0.2, 0.4, 0.6], + "translation":[11, -10, 24] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `Align` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Align_Align): + # A unique identifier generated by the client. + self.Index = Index + # "Align" + self.Type = Type + # The align settings. + self.Input = Input + + class Response: + # Server response for the `Align` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Align_Align, Output: MF_V3_Descriptors_Transform_Transform, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "Align" + self.Type = Type + # The requested align settings. + self.Input = Input + # The transform that aligns the source scan group to the target scan group. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/AutoFocus.py b/maf_three/MF/V3/Tasks/AutoFocus.py new file mode 100644 index 0000000..899ce35 --- /dev/null +++ b/maf_three/MF/V3/Tasks/AutoFocus.py @@ -0,0 +1,94 @@ +from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus +from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class AutoFocus: + """* + Auto focus one or both cameras. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"AutoFocus", + "Input":{ + "cameras":[{ + "index":1, + "box":{"x":196,"y":130,"width":64,"height":64} + }], + "applyAll":false + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"AutoFocus", + "Input":{ + "cameras":[{ + "index":1, + "box":{"x":196,"y":130,"width":64,"height":64} + }], + "applyAll":false + } + "Output":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "autoExposure":{"default":false,"value":true}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + "focus":{ + "box":{ + "default":[ + {"height":64,"width":64,"x":224,"y":158}, + {"height":64,"width":64,"x":224,"y":158} + ], + "value":[ + {"height":64,"width":64,"x":271,"y":134}, + {"height":64,"width":64,"x":196,"y":130} + ] + }, + "value":{"default":[350,350],"max":1024,"min":0,"value":[396,392]} + } + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `AutoFocus` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_AutoFocus_AutoFocus = None): + # A unique identifier generated by the client. + self.Index = Index + # "AutoFocus" + self.Type = Type + # AutoFocus settings. + self.Input = Input + + class Response: + # Server response for the `AutoFocus` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_AutoFocus_AutoFocus = None, Output: MF_V3_Descriptors_Settings_Camera_Camera = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "AutoFocus" + self.Type = Type + # Requested auto focus settings. + self.Input = Input + # Actual camera settings after auto focusing the camera(s). + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/BoundingBox.py b/maf_three/MF/V3/Tasks/BoundingBox.py new file mode 100644 index 0000000..bdff7bc --- /dev/null +++ b/maf_three/MF/V3/Tasks/BoundingBox.py @@ -0,0 +1,82 @@ +from MF.V3.Settings.BoundingBox import BoundingBox as MF_V3_Settings_BoundingBox_BoundingBox +from MF.V3.Descriptors.BoundingBox import BoundingBox as MF_V3_Descriptors_BoundingBox_BoundingBox +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class BoundingBox: + """* + Get the bounding box of a set of scan groups. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"BoundingBox", + "Input":{ + "selection":{"mode":"visible"}, + "axisAligned":false + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"BoundingBox", + "Input":{ + "selection":{"mode":"visible"}, + "axisAligned":false + }, + "Output":{ + "center":[11.9,-10.1,94.5], + "rotation":[ + 0.7, -0.7, 0.0, + 0.7, 0.7, 0.0, + 0.0, 0.0, 1.0], + "size":[442.2,253.1,447.1], + "transform":[ + 221, 0.0, 0.0, 11.9, + 0.0, 126, 0.0, -10.1, + 0.0, 0.0, 223, 94.5, + 0.0, 0.0, 0.0, 1.0] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `BoundingBox` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_BoundingBox_BoundingBox): + # A unique identifier generated by the client. + self.Index = Index + # "BoundingBox" + self.Type = Type + # The bounding box settings. + self.Input = Input + + class Response: + # Server response for the `BoundingBox` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_BoundingBox_BoundingBox, Output: MF_V3_Descriptors_BoundingBox_BoundingBox, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "BoundingBox" + self.Type = Type + # The requested bounding box settings. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/CalibrateCameras.py b/maf_three/MF/V3/Tasks/CalibrateCameras.py new file mode 100644 index 0000000..b56dfa7 --- /dev/null +++ b/maf_three/MF/V3/Tasks/CalibrateCameras.py @@ -0,0 +1,58 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class CalibrateCameras: + """* + Calibrate the cameras. + + This task starts the camera calibration capture sequence where the user is guided to place the calibration card with a card outline drawn on the video feed. Once each calibration card pose is captured, the cameras are calibrated and the calibration results are returned as a string. If the cameras cannot be calibrated the task finishes in a `Failed` state. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrateCameras" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrateCameras", + "Output":"Camera calibration results: ...", + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `CalibrateCameras` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "CalibrateCameras" + self.Type = Type + + class Response: + # Server response for the `CalibrateCameras` task. + def __init__(self, Index: int, Type: str, Output: str = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "CalibrateCameras" + self.Type = Type + # Camera calibration results. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/CalibrateTurntable.py b/maf_three/MF/V3/Tasks/CalibrateTurntable.py new file mode 100644 index 0000000..546383c --- /dev/null +++ b/maf_three/MF/V3/Tasks/CalibrateTurntable.py @@ -0,0 +1,61 @@ +from MF.V3.Descriptors.Calibration import Turntable as MF_V3_Descriptors_Calibration_Turntable +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class CalibrateTurntable: + """* + Calibrate the turntable. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrateTurntable" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrateTurntable", + "Output":{ + "date":[2024,4,27,16,57,35], + "quality":"Excellent", + "focus":[300,320] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `CalibrateTurntable` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "CalibrateTurntable" + self.Type = Type + + class Response: + # Server response for the `CalibrateTurntable` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_Turntable = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "CalibrateTurntable" + self.Type = Type + # The Turntable calibration descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/CalibrationCaptureTargets.py b/maf_three/MF/V3/Tasks/CalibrationCaptureTargets.py new file mode 100644 index 0000000..6505b0f --- /dev/null +++ b/maf_three/MF/V3/Tasks/CalibrationCaptureTargets.py @@ -0,0 +1,66 @@ +from MF.V3.Descriptors.Calibration import CaptureTarget as MF_V3_Descriptors_Calibration_CaptureTarget +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class CalibrationCaptureTargets: + """* + Get the camera calibration targets. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrationCaptureTargets" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrationCaptureTargets", + "Output":{[ + { + "camera":0, + "quads":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] + }, + { + "camera":1, + "quads":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] + }, + ]}, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `CalibrationCaptureTargets` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "CalibrationCaptureTargets" + self.Type = Type + + class Response: + # Server response for the `CalibrationCaptureTargets` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_CaptureTarget = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "CalibrationCaptureTargets" + self.Type = Type + # The calibration capture target descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/CameraCalibration.py b/maf_three/MF/V3/Tasks/CameraCalibration.py new file mode 100644 index 0000000..cabf59a --- /dev/null +++ b/maf_three/MF/V3/Tasks/CameraCalibration.py @@ -0,0 +1,60 @@ +from MF.V3.Descriptors.Calibration import Camera as MF_V3_Descriptors_Calibration_Camera +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class CameraCalibration: + """* + Get the camera calibration descriptor. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CameraCalibration" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CameraCalibration", + "Output":{ + "date":[2024,4,27,16,57,35], + "quality":"Excellent" + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `CameraCalibration` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "CameraCalibration" + self.Type = Type + + class Response: + # Server response for the `CameraCalibration` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_Camera = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "CameraCalibration" + self.Type = Type + # The camera calibration descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/CloseProject.py b/maf_three/MF/V3/Tasks/CloseProject.py new file mode 100644 index 0000000..9f17ced --- /dev/null +++ b/maf_three/MF/V3/Tasks/CloseProject.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class CloseProject: + """* + Close the current open project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CloseProject", + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CloseProject", + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `CloseProject` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "CloseProject" + self.Type = Type + + class Response: + # Server response for the `CloseProject` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "CloseProject" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ConnectWifi.py b/maf_three/MF/V3/Tasks/ConnectWifi.py new file mode 100644 index 0000000..911ef46 --- /dev/null +++ b/maf_three/MF/V3/Tasks/ConnectWifi.py @@ -0,0 +1,67 @@ +from MF.V3.Settings.Wifi import Wifi as MF_V3_Settings_Wifi_Wifi +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ConnectWifi: + """* + Connect to a wifi network. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ConnectWifi", + "Input":{ + "ssid":"Network1" + "password":"password" + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ConnectWifi", + "Input":{ + { + "ssid":"Network1" + "password":"password" + } + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ConnectWifi` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Wifi_Wifi): + # A unique identifier generated by the client. + self.Index = Index + # "ConnectWifi" + self.Type = Type + # Wifi settings. + self.Input = Input + + class Response: + # Server response for the `ConnectWifi` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Wifi_Wifi, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ConnectWifi" + self.Type = Type + # The requested wifi settings. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/DepthMap.py b/maf_three/MF/V3/Tasks/DepthMap.py new file mode 100644 index 0000000..d8da23d --- /dev/null +++ b/maf_three/MF/V3/Tasks/DepthMap.py @@ -0,0 +1,141 @@ +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from MF.V3.Descriptors.Image import Image as MF_V3_Descriptors_Image_Image +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task +from typing import List + + +class DepthMap: + """* + Capture a new scan. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"DepthMap" + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + }, + } + } + ``` + + > Depth map buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":13128960, + "Descriptor":{ + "cols":2104, + "rows":1560, + "step":8416, + "type":5 + }, + "Task":{ + "Index":1, + "Type":"DepthMap", + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + } + } + } + } + ``` + + > Depth map binary data transfer from server [13128960 bytes]. + + > Texture buffer message from server. + + ```json + { + "Buffer":{ + "Index":1, + "Size":9846720, + "Descriptor":{ + "cols":2104, + "rows":1560, + "step":6312, + "type":16 + }, + "Task":{ + "Index":1, + "Type":"DepthMap", + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + } + } + } + } + ``` + + > Texture binary data transfer from server [9846720 bytes]. + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"DepthMap" + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + }, + "Output":[2500,0,1052,0,2500,780,0,0,1], + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `DepthMap` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None): + # A unique identifier generated by the client. + self.Index = Index + # "DepthMap" + self.Type = Type + # Scan settings. + self.Input = Input + + class Response: + # Server response for the `DepthMap` task. + def __init__(self, Index: int, Type: str, Output: List[float], Input: MF_V3_Settings_Scan_Scan = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "DepthMap" + self.Type = Type + # The 9 values of the camera matrix corresponding to the depth map (row-major). + self.Output = Output + # Requested scan settings. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `DepthMap` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: MF_V3_Descriptors_Image_Image): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested DepthMap task. + self.Task = Task + # The image descriptor. + self.Descriptor = Descriptor + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/DetectCalibrationCard.py b/maf_three/MF/V3/Tasks/DetectCalibrationCard.py new file mode 100644 index 0000000..1127f4f --- /dev/null +++ b/maf_three/MF/V3/Tasks/DetectCalibrationCard.py @@ -0,0 +1,65 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class DetectCalibrationCard: + """* + Detect the calibration card on one or both cameras. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"DetectCalibrationCard", + "Input":3 + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Input":3, + "Type":"DetectCalibrationCard", + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `DetectCalibrationCard` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "DetectCalibrationCard" + self.Type = Type + """ + Flag specifying on which camera(s) to detect the calibration card. + [0: neither camera (disable), 1: left camera, 2: right camera, 3: both cameras] + """ + self.Input = Input + + class Response: + # Server response for the `DetectCalibrationCard` task. + def __init__(self, Index: int, Type: str, Input: int, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "DetectCalibrationCard" + self.Type = Type + """ + Flag sent in the request specifying on which camera(s) to detect the calibration card. + [0: neither camera (disable), 1: left camera, 2: right camera, 3: both cameras] + """ + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/DownloadProject.py b/maf_three/MF/V3/Tasks/DownloadProject.py new file mode 100644 index 0000000..eb34bd1 --- /dev/null +++ b/maf_three/MF/V3/Tasks/DownloadProject.py @@ -0,0 +1,89 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class DownloadProject: + """* + Download a project from the scanner. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"DownloadProject", + "Input":5 + } + } + ``` + + > Buffer message from server. + + ```json + { + "Buffer":{ + "Descriptor":"Project-5.zip", + "Index":0, + "Size":15682096, + "Task":{ + "Index":1, + "Type":"DownloadProject", + "Input":5 + } + } + } + ``` + + > Binary data transfer from server: The project zip file [15682096 bytes]. + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"DownloadProject" + "Input":5, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `DownloadProject` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "DownloadProject" + self.Type = Type + # Index of the project to download. + self.Input = Input + + class Response: + # Server response for the `DownloadProject` task. + def __init__(self, Index: int, Type: str, Input: int, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "DownloadProject" + self.Type = Type + # Requested index of the project to download. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `DownloadProject` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: str): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested DownloadProject task. + self.Task = Task + # The downloaded project filename. + self.Descriptor = Descriptor + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/Export.py b/maf_three/MF/V3/Tasks/Export.py new file mode 100644 index 0000000..36209cc --- /dev/null +++ b/maf_three/MF/V3/Tasks/Export.py @@ -0,0 +1,103 @@ +from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class Export: + """* + Export a group of scans. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Export", + "Input":{ + "selection":{"mode":"visible"}, + "format":"obj", + "texture":true, + "merge":false + } + } + } + ``` + + > Export file buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":8413737, + "Task":{ + "Index":1, + "Type":"Export", + "Input":{ + "selection":{"mode":"visible"}, + "format":"obj", + "texture":true, + "merge":false + } + } + } + } + ``` + + > Export file binary data transfer from server [8413737 bytes]. + + > Response from server: + + ```json + { + "Task":{ + "Index":1, + "Type":"Export" + "Input":{ + "selection":{"mode":"visible"}, + "format":"obj", + "texture":true, + "merge":false + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `Export` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export): + # A unique identifier generated by the client. + self.Index = Index + # "Export" + self.Type = Type + # Export settings. + self.Input = Input + + class Response: + # Server response for the `Export` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "Export" + self.Type = Type + # Requested export settings. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `Export` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested Export task. + self.Task = Task + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ExportLogs.py b/maf_three/MF/V3/Tasks/ExportLogs.py new file mode 100644 index 0000000..bb933f6 --- /dev/null +++ b/maf_three/MF/V3/Tasks/ExportLogs.py @@ -0,0 +1,87 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class ExportLogs: + """* + Export scanner logs. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ExportLogs", + "Input":true + } + } + ``` + + > Export file buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":41337, + "Task":{ + "Index":1, + "Type":"ExportLogs", + "Input":true + } + } + } + ``` + + > Export file binary data transfer from server [41337 bytes]. + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ExportLogs" + "Input":true, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ExportLogs` task. + def __init__(self, Index: int, Type: str, Input: bool = None): + # A unique identifier generated by the client. + self.Index = Index + # "ExportLogs" + self.Type = Type + # Export log images. If unspecified, log images are not exported. + self.Input = Input + + class Response: + # Server response for the `ExportLogs` task. + def __init__(self, Index: int, Type: str, Input: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ExportLogs" + self.Type = Type + # Requested export log images. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `ExportLogs` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested ExportLogs task. + self.Task = Task + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ExportMerge.py b/maf_three/MF/V3/Tasks/ExportMerge.py new file mode 100644 index 0000000..78a1e45 --- /dev/null +++ b/maf_three/MF/V3/Tasks/ExportMerge.py @@ -0,0 +1,97 @@ +from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class ExportMerge: + """* + Export a merged scan. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ExportMerge", + "Input":{ + "format":"obj", + "texture":true + } + } + } + ``` + + > Export file buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":8413737, + "Task":{ + "Index":1, + "Type":"ExportMerge", + "Input":{ + "format":"obj", + "texture":true + } + } + } + } + ``` + + > Export file binary data transfer from server [8413737 bytes]. + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ExportMerge" + "Input":{ + "format":"obj", + "texture":true + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ExportMerge` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export): + # A unique identifier generated by the client. + self.Index = Index + # "ExportMerge" + self.Type = Type + # Export settings. + self.Input = Input + + class Response: + # Server response for the `ExportMerge` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ExportMerge" + self.Type = Type + # Requested export settings. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `ExportMerge` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested ExportMerge task. + self.Task = Task + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/FlattenGroup.py b/maf_three/MF/V3/Tasks/FlattenGroup.py new file mode 100644 index 0000000..c772c6a --- /dev/null +++ b/maf_three/MF/V3/Tasks/FlattenGroup.py @@ -0,0 +1,72 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class FlattenGroup: + """* + Flatten a scan group such that it only consists of single scans. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"FlattenGroup", + "Input":0 + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"FlattenGroup", + "Input":0, + "Output":{ + "groups":[{ + "index":2, + "name":"Group 2", + "groups":[{ + "index":1, + "name":"Group 1" + }] + }], + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `FlattenGroup` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "FlattenGroup" + self.Type = Type + # The index of the group to flatten. + self.Input = Input + + class Response: + # Server response for the `FlattenGroup` task. + def __init__(self, Index: int, Type: str, Input: int, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "FlattenGroup" + self.Type = Type + # The requested index of the group to flatten. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ForgetWifi.py b/maf_three/MF/V3/Tasks/ForgetWifi.py new file mode 100644 index 0000000..7b192ed --- /dev/null +++ b/maf_three/MF/V3/Tasks/ForgetWifi.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ForgetWifi: + """* + Forget all wifi connections. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ForgetWifi" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ForgetWifi" + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ForgetWifi` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ForgetWifi" + self.Type = Type + + class Response: + # Server response for the `ForgetWifi` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ForgetWifi" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/HasCameras.py b/maf_three/MF/V3/Tasks/HasCameras.py new file mode 100644 index 0000000..0bf9c8d --- /dev/null +++ b/maf_three/MF/V3/Tasks/HasCameras.py @@ -0,0 +1,56 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class HasCameras: + """* + Check if the scanner has working cameras. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasCameras" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasCameras", + "Output":true, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `HasCameras` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "HasCameras" + self.Type = Type + + class Response: + # Server response for the `HasCameras` task. + def __init__(self, Index: int, Type: str, Output: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "HasCameras" + self.Type = Type + # The working state of the cameras. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/HasProjector.py b/maf_three/MF/V3/Tasks/HasProjector.py new file mode 100644 index 0000000..9b40f11 --- /dev/null +++ b/maf_three/MF/V3/Tasks/HasProjector.py @@ -0,0 +1,56 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class HasProjector: + """* + Check if the scanner has a working projector. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasProjector" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasProjector", + "Output":true, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `HasProjector` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "HasProjector" + self.Type = Type + + class Response: + # Server response for the `HasProjector` task. + def __init__(self, Index: int, Type: str, Output: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "HasProjector" + self.Type = Type + # The working state of the projector. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/HasTurntable.py b/maf_three/MF/V3/Tasks/HasTurntable.py new file mode 100644 index 0000000..d56fc1a --- /dev/null +++ b/maf_three/MF/V3/Tasks/HasTurntable.py @@ -0,0 +1,56 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class HasTurntable: + """* + Check if the scanner is connected to a working turntable. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasTurntable" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasTurntable", + "Output":true, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `HasTurntable` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "HasTurntable" + self.Type = Type + + class Response: + # Server response for the `HasTurntable` task. + def __init__(self, Index: int, Type: str, Output: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "HasTurntable" + self.Type = Type + # The working start of the connected turntable. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ListExportFormats.py b/maf_three/MF/V3/Tasks/ListExportFormats.py new file mode 100644 index 0000000..ec2b30b --- /dev/null +++ b/maf_three/MF/V3/Tasks/ListExportFormats.py @@ -0,0 +1,86 @@ +from MF.V3.Descriptors.Export import Export as MF_V3_Descriptors_Export_Export +from MF.V3.Task import TaskState as MF_V3_Task_TaskState +from typing import List + + +class ListExportFormats: + """* + List all export formats and the geometry elements they support. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListExportFormats" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListExportFormats", + "Output":{[ + { + "format": "ply", + "colors": true, + "description": "Polygon format", + "extension": ".ply", + "faces": ["Point","Triangle","Quad"], + "normals": true, + "textures": "Single" + }, + { + "format": "obj", + "colors": true, + "description": "Wavefront format", + "extension": ".obj", + "faces": ["Point","Triangle","Quad"], + "normals": true, + "textures": "Multiple" + }, + { + "format": "stl", + "colors": false, + "description": "Stereolithography format", + "extension": ".stl", + "faces": ["Point","Triangle"], + "normals": true, + "textures": "None" + } + ]}, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListExportFormats` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListExportFormats" + self.Type = Type + + class Response: + # Server response for the `ListExportFormats` task. + def __init__(self, Index: int, Type: str, Output: List[MF_V3_Descriptors_Export_Export], State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListExportFormats" + self.Type = Type + # The list of export format descriptors. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ListGroups.py b/maf_three/MF/V3/Tasks/ListGroups.py new file mode 100644 index 0000000..10ba504 --- /dev/null +++ b/maf_three/MF/V3/Tasks/ListGroups.py @@ -0,0 +1,85 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ListGroups: + """* + List the scan groups in the current open project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListGroups" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListGroups", + "Output":{ + "groups":[ + { + "index":1, + "scan":1, + "name":"Scan-1", + "color":[0.75,0.5,0.2,1.0], + "rotation":[0.03,0.1,-0.01], + "translation":[-101,67,-561], + "visible":true + }, + { + "index":2, + "scan":2, + "name":"Scan-2", + "color":[0.7,0.9,0.6,1.0], + "rotation":[0.1,0.2,0.5], + "translation":[-90,64,-553], + "visible":true + }, + { + "index":3, + "scan":3, + "name":"Scan-3", + "color":[0.6,0.8,0.9,1.0], + "visible":true + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListGroups` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListGroups" + self.Type = Type + + class Response: + # Server response for the `ListGroups` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListGroups" + self.Type = Type + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ListNetworkInterfaces.py b/maf_three/MF/V3/Tasks/ListNetworkInterfaces.py new file mode 100644 index 0000000..763cb9d --- /dev/null +++ b/maf_three/MF/V3/Tasks/ListNetworkInterfaces.py @@ -0,0 +1,61 @@ +from MF.V3.Descriptors.Network import Interface as MF_V3_Descriptors_Network_Interface +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ListNetworkInterfaces: + """* + List network interfaces. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListNetworkInterfaces" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListNetworkInterfaces", + "Output":[ + {"ip":"192.168.1.234","name":"eth0","ssid":""}, + {"ip":"127.0.0.1","name":"lo","ssid":""} + {"ip":"192.168.2.345","name":"wlan0","ssid":"Network1"} + ], + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListNetworkInterfaces` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListNetworkInterfaces" + self.Type = Type + + class Response: + # Server response for the `ListNetworkInterfaces` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Network_Interface = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListNetworkInterfaces" + self.Type = Type + # Network interface descriptors. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ListProjects.py b/maf_three/MF/V3/Tasks/ListProjects.py new file mode 100644 index 0000000..6216681 --- /dev/null +++ b/maf_three/MF/V3/Tasks/ListProjects.py @@ -0,0 +1,61 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ListProjects: + """* + List all projects. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListProjects" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListProjects", + "Output":[ + {"index":1,"modified":[2024,5,12,11,23,17],"name":"Project 1","size":35409834}, + {"index":2,"modified":[2024,5,12,11,2,37],"name":"Project 2","size":175025367}, + {"index":3,"modified":[2024,5,6,17,15,53],"name":"Project 3","size":24314083} + ], + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListProjects` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListProjects" + self.Type = Type + + class Response: + # Server response for the `ListProjects` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Brief = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListProjects" + self.Type = Type + # Brief project descriptors. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ListScans.py b/maf_three/MF/V3/Tasks/ListScans.py new file mode 100644 index 0000000..a6047f7 --- /dev/null +++ b/maf_three/MF/V3/Tasks/ListScans.py @@ -0,0 +1,77 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState +from typing import List + + +class ListScans: + """* + List the scans in the current open project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListScans" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListScans", + "Output":{[ + { + "color":[0.8,0.5,0.6,1.0], + "index":1, + "name":"Scan-1", + "scan":1, + "rotation":[0.2,0.8,-0.1], + "translation":[-275,-32,-134], + "visible":true + }, + { + "color":[0.5,0.7,0.2,1.0], + "index":2, + "name":"Scan-2", + "scan":2, + "rotation":[0.7,-0.5,0.3], + "translation":[75,-62,38], + "visible":true + }, + ]}, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListScans` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListScans" + self.Type = Type + + class Response: + # Server response for the `ListScans` task. + def __init__(self, Index: int, Type: str, Output: List[MF_V3_Descriptors_Project_Project.Group], State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListScans" + self.Type = Type + # The list of scans in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ListSettings.py b/maf_three/MF/V3/Tasks/ListSettings.py new file mode 100644 index 0000000..238935c --- /dev/null +++ b/maf_three/MF/V3/Tasks/ListSettings.py @@ -0,0 +1,86 @@ +from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ListSettings: + """* + Get scanner settings. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListSettings" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListSettings", + "Output":{ + "camera":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "autoExposure":{"default":false,"value":false}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "projector":{ + "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, + "on":{"default":false,"value":true} + }, + "turntable":{ + "scans":{"default":8,"max":24,"min":1,"value":3}, + "sweep":{"default":360,"max":360,"min":5,"value":90}, + "use":{"default":true,"value":true} + }, + "capture":{ + "quality":{"default":"Medium","value":"Medium"}, + "texture":{"default":true,"value":true} + }, + "i18n":{ + "language":{"default":"en","value":"en"} + }, + "style":{ + "theme":{"default":"Dark","value":"Dark"} + }, + "viewer":{ + "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} + } + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListSettings` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListSettings" + self.Type = Type + + class Response: + # Server response for the `ListSettings` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListSettings" + self.Type = Type + # The scanner settings descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ListWifi.py b/maf_three/MF/V3/Tasks/ListWifi.py new file mode 100644 index 0000000..223010e --- /dev/null +++ b/maf_three/MF/V3/Tasks/ListWifi.py @@ -0,0 +1,64 @@ +from MF.V3.Descriptors.Wifi import Wifi as MF_V3_Descriptors_Wifi_Wifi +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ListWifi: + """* + List available wifi networks. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListWifi" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListWifi", + "Output":{ + "networks":[ + {"ssid":"Network1","isActive":true,"isPublic":false,"quality":90}, + {"ssid":"Network2","isActive":true,"isPublic":true,"quality":50}, + {"ssid":"Network3","isActive":true,"isPublic":true,"quality":75} + ], + "ssid":"Network1" + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListWifi` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListWifi" + self.Type = Type + + class Response: + # Server response for the `ListWifi` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Wifi_Wifi = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListWifi" + self.Type = Type + # The wifi descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/Merge.py b/maf_three/MF/V3/Tasks/Merge.py new file mode 100644 index 0000000..0b6af3e --- /dev/null +++ b/maf_three/MF/V3/Tasks/Merge.py @@ -0,0 +1,104 @@ +from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge +from MF.V3.Descriptors.Merge import Merge as MF_V3_Descriptors_Merge_Merge +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class Merge: + """* + Merge two or more scan groups. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Merge", + "Input":{ + "selection":{"mode":"visible"}, + "remesh":{ + "method": "FlowTriangles", + "quality": "Medium" + }, + "simplify":{"triangleCount": 20000 } + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Merge", + "Input":{ + "selection":{"mode":"visible"}, + "remesh":{ + "method": "FlowTriangles", + "quality": "Medium" + }, + "simplify":{"triangleCount": 20000 } + }, + "Output":{ + "meshes":[ + { + "name":"Combined", + "positions":237757, + "normals":237757, + "triangles":459622, + "size":11221632 + }, + { + "name":"Remeshed", + "positions":34311, + "normals":0, + "triangles":29738, + "size":945540 + }, + { + "name":"Simplified", + "positions":32415, + "normals":0, + "triangles":20000, + "size":628980 + } + ], + "scans":3, + "textures":3 + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `Merge` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Merge_Merge): + # A unique identifier generated by the client. + self.Index = Index + # "Merge" + self.Type = Type + # The merge settings. + self.Input = Input + + class Response: + # Server response for the `Merge` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Merge_Merge, Output: MF_V3_Descriptors_Merge_Merge, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "Merge" + self.Type = Type + # The requested merge settings. + self.Input = Input + # The merge descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/MergeData.py b/maf_three/MF/V3/Tasks/MergeData.py new file mode 100644 index 0000000..b9c0d68 --- /dev/null +++ b/maf_three/MF/V3/Tasks/MergeData.py @@ -0,0 +1,239 @@ +from MF.V3.Descriptors.ScanData import ScanData as MF_V3_Descriptors_ScanData_ScanData +from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class MergeData: + """* + Download the raw scan data for the current merge process. + + > Request example: + + ``` + { + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":-1, + "buffers":["All"] + } + } + } + ``` + + > Vertex position buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":1558188, + "Descriptor":{ + "components":[{ + "type":"Position" + "size":3, + "offset":0, + "normalized":false, + }], + "stride":3 + }, + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex position binary data transfer from server [1558188 bytes]. + + > Vertex normal buffer message from server. + + ```json + { + "Buffer":{ + "Index":1, + "Size":1558188, + "Descriptor":{ + "components":[{ + "type":"Normal" + "size":3, + "offset":0, + "normalized":false, + }], + "stride":3 + }, + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex normal binary data transfer from server [1558188 bytes]. + + > Vertex texture coordinate buffer message from server. + + ```json + { + "Buffer":{ + "Index":2, + "Size":1038792, + "Descriptor":{ + "components":[{ + "type":"UV" + "size":2, + "offset":0, + "normalized":false, + }], + "stride":2 + }, + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex texture coordinate binary data transfer from server [1038792 bytes]. + + > Texture image buffer message from server. + + ```json + { + "Buffer":{ + "Index":3, + "Size":3504494, + "Descriptor":{ + "components":[{ + "type":"Texture" + "size":0, + "offset":0, + "normalized":false, + }], + "stride":0 + }, + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Texture binary data transfer from server [3504494 bytes]. + + > Triangle index buffer message from server. + + ```json + { + "Buffer":{ + "Index":4, + "Size":1996356, + "Descriptor":{ + "components":[{ + "type":"Triangle" + "size":1, + "offset":0, + "normalized":false, + }], + "stride":1 + }, + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Triangle index binary data transfer from server [1996356 bytes]. + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"MergeData" + "Input":{"index":-1,"buffers":["All"]}, + "Output":{ + "buffers":[ + {"components":[{"normalized":false,"offset":0,"size":3,"type":"Position"}],"stride":3}, + {"components":[{"normalized":false,"offset":0,"size":3,"type":"Normal"}],"stride":3}, + {"components":[{"normalized":false,"offset":0,"size":2,"type":"UV"}],"stride":2}, + {"components":[{"normalized":false,"offset":0,"size":0,"type":"Texture"}],"stride":0}, + {"components":[{"normalized":false,"offset":0,"size":1,"type":"Triangle"}],"stride":1} + ], + "index":1, + "name":"Scan-1" + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `MergeData` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData): + # A unique identifier generated by the client. + self.Index = Index + # "MergeData" + self.Type = Type + # Requested scan data. + self.Input = Input + + class Response: + # Server response for the `MergeData` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData, Output: MF_V3_Descriptors_ScanData_ScanData, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "MergeData" + self.Type = Type + # The scan data requested by the client. + self.Input = Input + # The scan data sent from the server. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `MergeData` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: MF_V3_Descriptors_ScanData_ScanData.Buffer): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested MergeData task. + self.Task = Task + # The scan data buffer descriptor. + self.Descriptor = Descriptor + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/MoveGroup.py b/maf_three/MF/V3/Tasks/MoveGroup.py new file mode 100644 index 0000000..3897331 --- /dev/null +++ b/maf_three/MF/V3/Tasks/MoveGroup.py @@ -0,0 +1,79 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState +from typing import List + + +class MoveGroup: + """* + Move a scan group. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"MoveGroup", + "Input":[1,2,0] + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"MoveGroup", + "Input":[1,2,0], + "Output":{ + "groups":[{ + "index":2, + "name":"Group 2", + "groups":[{ + "index":1, + "name":"Group 1" + }] + }], + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `MoveGroup` task. + def __init__(self, Index: int, Type: str, Input: List[int]): + # A unique identifier generated by the client. + self.Index = Index + # "MoveGroup" + self.Type = Type + """ + The requested source and destination move indices. + An Array of group indexes where + 1. The first is the index of the _source group_: the group to be moved. + 2. The second is the index of the _parent group_: the group into which the source group is moved. + 3. (Optional) The third is the zero-based order in which the source group is placed the other children of the parent group. Use `0` to insert the source group at the beginning of the parent group's children. If omitted, the source group is inserted at the end of the parent group's children. + """ + self.Input = Input + + class Response: + # Server response for the `MoveGroup` task. + def __init__(self, Index: int, Type: str, Input: List[int], Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "MoveGroup" + self.Type = Type + # The requested source and destination move indices. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/NewGroup.py b/maf_three/MF/V3/Tasks/NewGroup.py new file mode 100644 index 0000000..dad64aa --- /dev/null +++ b/maf_three/MF/V3/Tasks/NewGroup.py @@ -0,0 +1,77 @@ +from MF.V3.Settings.NewGroup import NewGroup as MF_V3_Settings_NewGroup_NewGroup +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class NewGroup: + """* + Create a new scan group. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewGroup", + "Input":{ + "parentIndex":0, + "baseName":"Group" + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewGroup", + "Input":{ + "parentIndex":0, + "baseName":"Group" + }, + "Output":{ + "groups":[ + { + "index":1, + "name":"Group 1" + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `NewGroup` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_NewGroup_NewGroup = None): + # A unique identifier generated by the client. + self.Index = Index + # "NewGroup" + self.Type = Type + # The requested new group settings. + self.Input = Input + + class Response: + # Server response for the `NewGroup` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, Input: MF_V3_Settings_NewGroup_NewGroup = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "NewGroup" + self.Type = Type + # The root scan group in the current open project. + self.Output = Output + # The requested new group settings. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/NewProject.py b/maf_three/MF/V3/Tasks/NewProject.py new file mode 100644 index 0000000..0feef65 --- /dev/null +++ b/maf_three/MF/V3/Tasks/NewProject.py @@ -0,0 +1,69 @@ +from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class NewProject: + """* + Create a new project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewProject", + "Input":"New Project Name" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewProject", + "Input":{ + "name":"New Project Name" + }, + "Output":{ + "index":5, + "name":"New Project Name" + } + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `NewProject` task. + def __init__(self, Index: int, Type: str, Input: str = None): + # A unique identifier generated by the client. + self.Index = Index + # "NewProject" + self.Type = Type + # Optional new project name. + self.Input = Input + + class Response: + # Server response for the `NewProject` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Project_Project = None, Output: MF_V3_Descriptors_Project_Project = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "NewProject" + self.Type = Type + # Requested new project name. + self.Input = Input + # The new project descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/NewScan.py b/maf_three/MF/V3/Tasks/NewScan.py new file mode 100644 index 0000000..5e412b9 --- /dev/null +++ b/maf_three/MF/V3/Tasks/NewScan.py @@ -0,0 +1,82 @@ +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class NewScan: + """* + Capture a new scan. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewScan" + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + }, + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewScan" + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + }, + "Output":{ + "groups":[{ + "color":[0.8,0.5,0.6,1.0], + "index":1, + "name":"Scan-1", + "scan":1, + "rotation":[0.2,0.8,-0.1], + "translation":[-275,-32,-134], + "visible":true + }], + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `NewScan` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None): + # A unique identifier generated by the client. + self.Index = Index + # "NewScan" + self.Type = Type + # Scan settings. + self.Input = Input + + class Response: + # Server response for the `NewScan` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None, Output: MF_V3_Descriptors_Project_Project.Group = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "NewScan" + self.Type = Type + # Requested scan settings. + self.Input = Input + # Project group descriptor with the updated list of scans. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/OpenProject.py b/maf_three/MF/V3/Tasks/OpenProject.py new file mode 100644 index 0000000..06c6fa2 --- /dev/null +++ b/maf_three/MF/V3/Tasks/OpenProject.py @@ -0,0 +1,66 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class OpenProject: + """* + Create a new project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"OpenProject", + "Input":5 + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"OpenProject", + "Input":5, + "Output":{ + "index":5, + "name":"Project 5" + } + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `OpenProject` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "OpenProject" + self.Type = Type + # The index of the project to open. Project indices can be obtained from the `ListProjects` task. + self.Input = Input + + class Response: + # Server response for the `OpenProject` task. + def __init__(self, Index: int, Type: str, Input: int, Output: MF_V3_Descriptors_Project_Project = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "OpenProject" + self.Type = Type + # The index of the project requested to open. + self.Input = Input + # The open project descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/PopSettings.py b/maf_three/MF/V3/Tasks/PopSettings.py new file mode 100644 index 0000000..80916e5 --- /dev/null +++ b/maf_three/MF/V3/Tasks/PopSettings.py @@ -0,0 +1,92 @@ +from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class PopSettings: + """* + Pop and restore scanner settings from the stack and optionally apply the popped settings. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"PopSettings", + "Input":true + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"PopSettings", + "Input":true, + "Output":{ + "camera":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "autoExposure":{"default":false,"value":false}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "projector":{ + "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, + "on":{"default":false,"value":true} + }, + "turntable":{ + "scans":{"default":8,"max":24,"min":1,"value":3}, + "sweep":{"default":360,"max":360,"min":5,"value":90}, + "use":{"default":true,"value":true} + }, + "capture":{ + "quality":{"default":"Medium","value":"Medium"}, + "texture":{"default":true,"value":true} + }, + "i18n":{ + "language":{"default":"en","value":"en"} + }, + "style":{ + "theme":{"default":"Dark","value":"Dark"} + }, + "viewer":{ + "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} + } + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `PopSettings` task. + def __init__(self, Index: int, Type: str, Input: bool = None): + # A unique identifier generated by the client. + self.Index = Index + # "PopSettings" + self.Type = Type + # Apply the popped settings. If unspecified popped settings are not applied. + self.Input = Input + + class Response: + # Server response for the `PopSettings` task. + def __init__(self, Index: int, Type: str, Input: bool = None, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "PopSettings" + self.Type = Type + # Request to apply the popped settings. + self.Input = Input + # The scanner settings descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/PushSettings.py b/maf_three/MF/V3/Tasks/PushSettings.py new file mode 100644 index 0000000..feaf6b0 --- /dev/null +++ b/maf_three/MF/V3/Tasks/PushSettings.py @@ -0,0 +1,86 @@ +from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class PushSettings: + """* + Push the current scanner settings to a stack so they can be restored with PopSettings. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"PushSettings" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"PushSettings", + "Output":{ + "camera":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "autoExposure":{"default":false,"value":false}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "projector":{ + "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, + "on":{"default":false,"value":true} + }, + "turntable":{ + "scans":{"default":8,"max":24,"min":1,"value":3}, + "sweep":{"default":360,"max":360,"min":5,"value":90}, + "use":{"default":true,"value":true} + }, + "capture":{ + "quality":{"default":"Medium","value":"Medium"}, + "texture":{"default":true,"value":true} + }, + "i18n":{ + "language":{"default":"en","value":"en"} + }, + "style":{ + "theme":{"default":"Dark","value":"Dark"} + }, + "viewer":{ + "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} + } + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `PushSettings` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "PushSettings" + self.Type = Type + + class Response: + # Server response for the `PushSettings` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "PushSettings" + self.Type = Type + # The scanner settings descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/Reboot.py b/maf_three/MF/V3/Tasks/Reboot.py new file mode 100644 index 0000000..c954807 --- /dev/null +++ b/maf_three/MF/V3/Tasks/Reboot.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class Reboot: + """* + Reboot the scanner. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Reboot" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Reboot" + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `Reboot` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "Reboot" + self.Type = Type + + class Response: + # Server response for the `Reboot` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "Reboot" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/RemoveGroups.py b/maf_three/MF/V3/Tasks/RemoveGroups.py new file mode 100644 index 0000000..bf2a77d --- /dev/null +++ b/maf_three/MF/V3/Tasks/RemoveGroups.py @@ -0,0 +1,64 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState +from typing import List + + +class RemoveGroups: + """* + Remove selected scan groups. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RemoveGroups", + "Input":[1,2] + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RemoveGroups", + "Input":[1,2], + "Output":{"groups":[]}, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `RemoveGroups` task. + def __init__(self, Index: int, Type: str, Input: List[int]): + # A unique identifier generated by the client. + self.Index = Index + # "RemoveGroups" + self.Type = Type + # The list of indices of the scan groups to remove. + self.Input = Input + + class Response: + # Server response for the `RemoveGroups` task. + def __init__(self, Index: int, Type: str, Input: List[int], Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "RemoveGroups" + self.Type = Type + # The requested of indices of the scan groups to remove. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/RemoveProjects.py b/maf_three/MF/V3/Tasks/RemoveProjects.py new file mode 100644 index 0000000..78f7815 --- /dev/null +++ b/maf_three/MF/V3/Tasks/RemoveProjects.py @@ -0,0 +1,68 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState +from typing import List + + +class RemoveProjects: + """* + Remove selected projects. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RemoveProjects", + "Input":[1,3,6] + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RemoveProjects", + "Input":[1,3,6], + "Output":[ + {"index":2,"modified":[2024,5,12,11,23,17],"name":"Project 2","size":35409834}, + {"index":4,"modified":[2024,5,12,11,2,37],"name":"Project 4","size":175025367}, + {"index":5,"modified":[2024,5,6,17,15,53],"name":"Project 5","size":24314083} + ], + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `RemoveProjects` task. + def __init__(self, Index: int, Type: str, Input: List[int]): + # A unique identifier generated by the client. + self.Index = Index + # "RemoveProjects" + self.Type = Type + # The list of indices of the projects to remove. + self.Input = Input + + class Response: + # Server response for the `RemoveProjects` task. + def __init__(self, Index: int, Type: str, Input: List[int], Output: MF_V3_Descriptors_Project_Project.Brief = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "RemoveProjects" + self.Type = Type + # The list of indices of the requested projects to remove. + self.Input = Input + # Brief descriptors of the remaining projects. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/RestoreFactoryCalibration.py b/maf_three/MF/V3/Tasks/RestoreFactoryCalibration.py new file mode 100644 index 0000000..4caea88 --- /dev/null +++ b/maf_three/MF/V3/Tasks/RestoreFactoryCalibration.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class RestoreFactoryCalibration: + """* + Restore factory calibration. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RestoreFactoryCalibration" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RestoreFactoryCalibration", + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `RestoreFactoryCalibration` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "RestoreFactoryCalibration" + self.Type = Type + + class Response: + # Server response for the `RestoreFactoryCalibration` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "RestoreFactoryCalibration" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/RotateTurntable.py b/maf_three/MF/V3/Tasks/RotateTurntable.py new file mode 100644 index 0000000..219c752 --- /dev/null +++ b/maf_three/MF/V3/Tasks/RotateTurntable.py @@ -0,0 +1,59 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class RotateTurntable: + """* + Rotate the turntable. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RotateTurntable", + "Input":15 + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RotateTurntable", + "Input":15, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `RotateTurntable` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "RotateTurntable" + self.Type = Type + # The rotation angle in degrees. + self.Input = Input + + class Response: + # Server response for the `RotateTurntable` task. + def __init__(self, Index: int, Type: str, Input: int, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "RotateTurntable" + self.Type = Type + # The requested rotation angle in degrees. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/ScanData.py b/maf_three/MF/V3/Tasks/ScanData.py new file mode 100644 index 0000000..c5ecab3 --- /dev/null +++ b/maf_three/MF/V3/Tasks/ScanData.py @@ -0,0 +1,239 @@ +from MF.V3.Descriptors.ScanData import ScanData as MF_V3_Descriptors_ScanData_ScanData +from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class ScanData: + """* + Download the raw scan data for a scan in the current open project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + ``` + + > Vertex position buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":1558188, + "Descriptor":{ + "components":[{ + "type":"Position" + "size":3, + "offset":0, + "normalized":false, + }], + "stride":3 + }, + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex position binary data transfer from server [1558188 bytes]. + + > Vertex normal buffer message from server. + + ```json + { + "Buffer":{ + "Index":1, + "Size":1558188, + "Descriptor":{ + "components":[{ + "type":"Normal" + "size":3, + "offset":0, + "normalized":false, + }], + "stride":3 + }, + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex normal binary data transfer from server [1558188 bytes]. + + > Vertex texture coordinate buffer message from server. + + ```json + { + "Buffer":{ + "Index":2, + "Size":1038792, + "Descriptor":{ + "components":[{ + "type":"UV" + "size":2, + "offset":0, + "normalized":false, + }], + "stride":2 + }, + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex texture coordinate binary data transfer from server [1038792 bytes]. + + > Texture image buffer message from server. + + ```json + { + "Buffer":{ + "Index":3, + "Size":3504494, + "Descriptor":{ + "components":[{ + "type":"Texture" + "size":0, + "offset":0, + "normalized":false, + }], + "stride":0 + }, + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Texture binary data transfer from server [3504494 bytes]. + + > Triangle index buffer message from server. + + ```json + { + "Buffer":{ + "Index":4, + "Size":1996356, + "Descriptor":{ + "components":[{ + "type":"Triangle" + "size":1, + "offset":0, + "normalized":false, + }], + "stride":1 + }, + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Triangle index binary data transfer from server [1996356 bytes]. + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{"buffers":["All"],"index":1}, + "Output":{ + "buffers":[ + {"components":[{"normalized":false,"offset":0,"size":3,"type":"Position"}],"stride":3}, + {"components":[{"normalized":false,"offset":0,"size":3,"type":"Normal"}],"stride":3}, + {"components":[{"normalized":false,"offset":0,"size":2,"type":"UV"}],"stride":2}, + {"components":[{"normalized":false,"offset":0,"size":0,"type":"Texture"}],"stride":0}, + {"components":[{"normalized":false,"offset":0,"size":1,"type":"Triangle"}],"stride":1} + ], + "index":1, + "name":"Scan-1" + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ScanData` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData): + # A unique identifier generated by the client. + self.Index = Index + # "ScanData" + self.Type = Type + # Requested scan data. + self.Input = Input + + class Response: + # Server response for the `ScanData` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData, Output: MF_V3_Descriptors_ScanData_ScanData, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ScanData" + self.Type = Type + # The scan data requested by the client. + self.Input = Input + # The scan data sent from the server. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `ScanData` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: MF_V3_Descriptors_ScanData_ScanData.Buffer): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested ScanData task. + self.Task = Task + # The scan data buffer descriptor. + self.Descriptor = Descriptor + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/SetCameras.py b/maf_three/MF/V3/Tasks/SetCameras.py new file mode 100644 index 0000000..5de94b6 --- /dev/null +++ b/maf_three/MF/V3/Tasks/SetCameras.py @@ -0,0 +1,76 @@ +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera +from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SetCameras: + """* + Apply camera settings to one or both cameras. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetCameras", + "Input":{ + "analogGain":256, + "digitalGain":128, + "exposure":18000 + }, + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetCameras" + "Input":{ + "analogGain":256, + "digitalGain":512, + "exposure":18000 + }, + "Output":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":512}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SetCameras` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Camera_Camera = None): + # A unique identifier generated by the client. + self.Index = Index + # "SetCameras" + self.Type = Type + # Camera settings. + self.Input = Input + + class Response: + # Server response for the `SetCameras` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Camera_Camera = None, Output: MF_V3_Descriptors_Settings_Camera_Camera = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SetCameras" + self.Type = Type + # Requested camera settings. + self.Input = Input + # Actual camera settings after applying the requested settings. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/SetGroup.py b/maf_three/MF/V3/Tasks/SetGroup.py new file mode 100644 index 0000000..ab4933c --- /dev/null +++ b/maf_three/MF/V3/Tasks/SetGroup.py @@ -0,0 +1,104 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.Group import Group as MF_V3_Settings_Group_Group +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SetGroup: + """* + Set scan group properties. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetGroup", + "Input":{ + "index":2, + "name":"Amazing Scan" + "color":[1,0,0,1], + "rotation":[0,3.14,0], + "translation":[0,10,25] + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetGroup", + "Input":{ + "index":2, + "name":"Amazing Scan" + "color":[1,0,0,1], + "rotation":[0,3.14,0], + "translation":[0,10,25] + } + "Output":{ + "groups":[ + { + "index":1, + "scan":1, + "name":"Scan-1", + "color":[0.75,0.5,0.2,1.0], + "rotation":[0.03,0.1,-0.01], + "translation":[-101,67,-561], + "visible":true + }, + { + "index":2, + "scan":2, + "name":"Amazing Scan", + "color":[1,0,0,1], + "rotation":[0,3.14,0], + "translation":[0,10,25], + "visible":true + }, + { + "index":3, + "scan":3, + "name":"Scan-3", + "color":[0.6,0.8,0.9,1.0], + "visible":true + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SetGroup` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group): + # A unique identifier generated by the client. + self.Index = Index + # "SetGroup" + self.Type = Type + # The requested group settings. + self.Input = Input + + class Response: + # Server response for the `SetGroup` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SetGroup" + self.Type = Type + # The requested group settings. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/SetProject.py b/maf_three/MF/V3/Tasks/SetProject.py new file mode 100644 index 0000000..147e781 --- /dev/null +++ b/maf_three/MF/V3/Tasks/SetProject.py @@ -0,0 +1,80 @@ +from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SetProject: + """* + Apply settings to the current open project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetProject", + "Input":{ + "name":"My Project" + }, + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetProject", + "Input":{ + "name":"My Project" + }, + "Output":{ + "index":5, + "name":"My Project", + "groups":[{ + "color":[0.8,0.5,0.6,1.0], + "index":1, + "name":"Scan-1", + "scan":1, + "rotation":[0.2,0.8,-0.1], + "translation":[-275,-32,-134], + "visible":true + }], + } + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SetProject` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Project_Project = None): + # A unique identifier generated by the client. + self.Index = Index + # "SetProject" + self.Type = Type + # Project settings. + self.Input = Input + + class Response: + # Server response for the `SetProject` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Project_Project = None, Output: MF_V3_Descriptors_Project_Project = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SetProject" + self.Type = Type + # Requested project settings. + self.Input = Input + # Actual project settings after applying the requested settings. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/SetProjector.py b/maf_three/MF/V3/Tasks/SetProjector.py new file mode 100644 index 0000000..2fe887c --- /dev/null +++ b/maf_three/MF/V3/Tasks/SetProjector.py @@ -0,0 +1,75 @@ +from MF.V3.Descriptors.Settings.Projector import Projector as MF_V3_Descriptors_Settings_Projector_Projector +from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SetProjector: + """* + Apply projector settings. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetProjector" + "Input":{ + "on":true, + "brightness":0.75, + "color":[1.0, 1.0, 1.0] + }, + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetProjector" + "Input":{ + "on":true, + "brightness":0.75, + "color":[1.0, 1.0, 1.0] + }, + "Output":{ + "on":{"default":false,"value":true}, + "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.75} + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SetProjector` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Projector_Projector = None): + # A unique identifier generated by the client. + self.Index = Index + # "SetProjector" + self.Type = Type + # Projector settings. + self.Input = Input + + class Response: + # Server response for the `SetProjector` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Projector_Projector = None, Output: MF_V3_Descriptors_Settings_Projector_Projector = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SetProjector" + self.Type = Type + # Requested projector settings. + self.Input = Input + # Actual projector settings after applying the requested settings. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/Shutdown.py b/maf_three/MF/V3/Tasks/Shutdown.py new file mode 100644 index 0000000..c6928ef --- /dev/null +++ b/maf_three/MF/V3/Tasks/Shutdown.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class Shutdown: + """* + Shutdown the scanner. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Shutdown" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Shutdown" + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `Shutdown` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "Shutdown" + self.Type = Type + + class Response: + # Server response for the `Shutdown` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "Shutdown" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/SplitGroup.py b/maf_three/MF/V3/Tasks/SplitGroup.py new file mode 100644 index 0000000..7efbce8 --- /dev/null +++ b/maf_three/MF/V3/Tasks/SplitGroup.py @@ -0,0 +1,74 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SplitGroup: + """* + Split a scan group (ie. move its subgroups to its parent group). + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SplitGroup", + "Input":0 + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SplitGroup", + "Input":0, + "Output":{ + "groups":[ + { + "index":1, + "name":"Group 1", + }, + { + "index":2, + "name":"Group 2" + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SplitGroup` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "SplitGroup" + self.Type = Type + # The index of the group to split. + self.Input = Input + + class Response: + # Server response for the `SplitGroup` task. + def __init__(self, Index: int, Type: str, Input: int, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SplitGroup" + self.Type = Type + # The requested index of the group to split. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/StartVideo.py b/maf_three/MF/V3/Tasks/StartVideo.py new file mode 100644 index 0000000..da7f6b2 --- /dev/null +++ b/maf_three/MF/V3/Tasks/StartVideo.py @@ -0,0 +1,64 @@ +from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class StartVideo: + """* + Start the video stream. + + The video frames are sent as task buffers associated with the reserved video task index -1. The left and right camera frames are sent in buffer 0 and 1, respectively. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"StartVideo" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"StartVideo", + "Output":{ + "codec":"JPEG", + "format":"YUV420", + "width":510, + "height":380 + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `StartVideo` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "StartVideo" + self.Type = Type + + class Response: + # Server response for the `StartVideo` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Settings_Video_Video = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "StartVideo" + self.Type = Type + # The video settings. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/StopVideo.py b/maf_three/MF/V3/Tasks/StopVideo.py new file mode 100644 index 0000000..68662b0 --- /dev/null +++ b/maf_three/MF/V3/Tasks/StopVideo.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class StopVideo: + """* + Stop the video stream. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"StopVideo" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"StopVideo", + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `StopVideo` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "StopVideo" + self.Type = Type + + class Response: + # Server response for the `StopVideo` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "StopVideo" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/SystemInfo.py b/maf_three/MF/V3/Tasks/SystemInfo.py new file mode 100644 index 0000000..15338ba --- /dev/null +++ b/maf_three/MF/V3/Tasks/SystemInfo.py @@ -0,0 +1,92 @@ +from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software +from MF.V3.Descriptors.System import System as MF_V3_Descriptors_System_System +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SystemInfo: + """* + Get system information including the serial number, disk space and installed and available software versions. + + Request example: + ``` + { + "Task":{ + "Index":1, + "Type":"SystemInfo", + "Input":{ + "installed":["server","frontend"], + "available":["server","frontend"] + } + } + } + ``` + Response example: + ``` + { + "Task":{ + "Index":1, + "Type":"SystemInfo" + "Input":{ + "installed":["server","frontend"], + "available":["server","frontend"] + } + "Output":{ + "serialNumber":"1000000012345678", + "diskSpace":{"available":8523210752,"capacity":15082610688}, + "software:{ + "installed":[ + { + "name":"server", + "version":{ + "major":2, + "minor":21, + "patch":119, + "string":"2.21.119" + } + }, + { + "name":"frontend", + "version":{ + "major":2, + "minor":14, + "patch":39, + "string":"2.14.39" + } + } + }, + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SystemInfo` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Software_Software = None): + # A unique identifier generated by the client. + self.Index = Index + # "SystemInfo" + self.Type = Type + # Software settings. + self.Input = Input + + class Response: + # Server response for the `SystemInfo` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_System_System, Input: MF_V3_Settings_Software_Software = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SystemInfo" + self.Type = Type + # The system descriptor. + self.Output = Output + # The requested software settings. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/TransformGroup.py b/maf_three/MF/V3/Tasks/TransformGroup.py new file mode 100644 index 0000000..f706e6b --- /dev/null +++ b/maf_three/MF/V3/Tasks/TransformGroup.py @@ -0,0 +1,81 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.Group import Group as MF_V3_Settings_Group_Group +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class TransformGroup: + """* + Apply a rigid transformation to a group. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"TransformGroup", + "Input":{ + "index":1, + "rotation":[0.5, 1.0, 1.5], + "translation":[10, 20, 30] + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"TransformGroup", + "Input":{ + "index":1, + "rotation":[0.5, 1.0, 1.5], + "translation":[10, 20, 30] + }, + "Output":{ + "groups":[ + { + "index":1, + "name":"Group 1", + "rotation":[0.5, 1.0, 1.5], + "translation":[10, 20, 30] + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `TransformGroup` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group): + # A unique identifier generated by the client. + self.Index = Index + # "TransformGroup" + self.Type = Type + # The group settings containing the requested rotation and translation. + self.Input = Input + + class Response: + # Server response for the `TransformGroup` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "TransformGroup" + self.Type = Type + # The group settings containing the requested rotation and translation. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/TurntableCalibration.py b/maf_three/MF/V3/Tasks/TurntableCalibration.py new file mode 100644 index 0000000..67308a8 --- /dev/null +++ b/maf_three/MF/V3/Tasks/TurntableCalibration.py @@ -0,0 +1,61 @@ +from MF.V3.Descriptors.Calibration import Turntable as MF_V3_Descriptors_Calibration_Turntable +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class TurntableCalibration: + """* + Get the turntable calibration descriptor. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"TurntableCalibration" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"TurntableCalibration", + "Output":{ + "date":[2024,4,27,16,57,35], + "quality":"Excellent", + "focus":[300,320] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `TurntableCalibration` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "TurntableCalibration" + self.Type = Type + + class Response: + # Server response for the `TurntableCalibration` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_Turntable = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "TurntableCalibration" + self.Type = Type + # The turntable calibration descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/UpdateSettings.py b/maf_three/MF/V3/Tasks/UpdateSettings.py new file mode 100644 index 0000000..26818f7 --- /dev/null +++ b/maf_three/MF/V3/Tasks/UpdateSettings.py @@ -0,0 +1,105 @@ +from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner +from MF.V3.Settings.Scanner import Scanner as MF_V3_Settings_Scanner_Scanner +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class UpdateSettings: + """* + Update scanner settings. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"UpdateSettings", + "Input":{ + "camera":{ + "analogGain":256, + "digitalGain":320, + "exposure":18000 + } + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"UpdateSettings", + "Input":{ + "camera":{ + "analogGain":256, + "digitalGain":320, + "exposure":18000 + } + }, + "Output":{ + "camera":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "autoExposure":{"default":false,"value":false}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "projector":{ + "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, + "on":{"default":false,"value":true} + }, + "turntable":{ + "scans":{"default":8,"max":24,"min":1,"value":3}, + "sweep":{"default":360,"max":360,"min":5,"value":90}, + "use":{"default":true,"value":true} + }, + "capture":{ + "quality":{"default":"Medium","value":"Medium"}, + "texture":{"default":true,"value":true} + }, + "i18n":{ + "language":{"default":"en","value":"en"} + }, + "style":{ + "theme":{"default":"Dark","value":"Dark"} + }, + "viewer":{ + "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} + } + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `UpdateSettings` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scanner_Scanner): + # A unique identifier generated by the client. + self.Index = Index + # "UpdateSettings" + self.Type = Type + # Scanner settings. + self.Input = Input + + class Response: + # Server response for the `UpdateSettings` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scanner_Scanner, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "UpdateSettings" + self.Type = Type + # The requested scanner settings. + self.Input = Input + # The scanner settings descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/UploadProject.py b/maf_three/MF/V3/Tasks/UploadProject.py new file mode 100644 index 0000000..8314523 --- /dev/null +++ b/maf_three/MF/V3/Tasks/UploadProject.py @@ -0,0 +1,79 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class UploadProject: + """* + Upload a project to the scanner. The project must be archived in a ZIP file. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"UploadProject" + } + } + ``` + + > Buffer message from client. + + ```json + { + "Buffer":{ + "Index":0, + "Size":15682096, + "Task":{ + "Index":1, + "Type":"UploadProject" + } + } + } + ``` + + > Binary data transfer from client: The project zip file [15682096 bytes]. + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"UploadProject" + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `UploadProject` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "UploadProject" + self.Type = Type + + class Response: + # Server response for the `UploadProject` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "UploadProject" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Client buffer message for the `UploadProject` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested UploadProject task. + self.Task = Task + + def __init__(self): + pass + diff --git a/maf_three/MF/V3/Tasks/__init__.py b/maf_three/MF/V3/Tasks/__init__.py new file mode 100644 index 0000000..87ea1f4 --- /dev/null +++ b/maf_three/MF/V3/Tasks/__init__.py @@ -0,0 +1,56 @@ +from MF.V3.Tasks.StartVideo import * +from MF.V3.Tasks.CloseProject import * +from MF.V3.Tasks.UploadProject import * +from MF.V3.Tasks.ExportMerge import * +from MF.V3.Tasks.ListGroups import * +from MF.V3.Tasks.MoveGroup import * +from MF.V3.Tasks.AddMergeToProject import * +from MF.V3.Tasks.Shutdown import * +from MF.V3.Tasks.SetGroup import * +from MF.V3.Tasks.ScanData import * +from MF.V3.Tasks.Merge import * +from MF.V3.Tasks.SetProject import * +from MF.V3.Tasks.CalibrateCameras import * +from MF.V3.Tasks.CameraCalibration import * +from MF.V3.Tasks.ListExportFormats import * +from MF.V3.Tasks.TransformGroup import * +from MF.V3.Tasks.ExportLogs import * +from MF.V3.Tasks.NewScan import * +from MF.V3.Tasks.DetectCalibrationCard import * +from MF.V3.Tasks.CalibrationCaptureTargets import * +from MF.V3.Tasks.AutoFocus import * +from MF.V3.Tasks.FlattenGroup import * +from MF.V3.Tasks.ListWifi import * +from MF.V3.Tasks.RemoveProjects import * +from MF.V3.Tasks.SetCameras import * +from MF.V3.Tasks.NewProject import * +from MF.V3.Tasks.SplitGroup import * +from MF.V3.Tasks.Reboot import * +from MF.V3.Tasks.DepthMap import * +from MF.V3.Tasks.RotateTurntable import * +from MF.V3.Tasks.RestoreFactoryCalibration import * +from MF.V3.Tasks.ListNetworkInterfaces import * +from MF.V3.Tasks.SystemInfo import * +from MF.V3.Tasks.ListSettings import * +from MF.V3.Tasks.HasProjector import * +from MF.V3.Tasks.ListProjects import * +from MF.V3.Tasks.ListScans import * +from MF.V3.Tasks.DownloadProject import * +from MF.V3.Tasks.Align import * +from MF.V3.Tasks.ConnectWifi import * +from MF.V3.Tasks.SetProjector import * +from MF.V3.Tasks.UpdateSettings import * +from MF.V3.Tasks.Export import * +from MF.V3.Tasks.NewGroup import * +from MF.V3.Tasks.TurntableCalibration import * +from MF.V3.Tasks.OpenProject import * +from MF.V3.Tasks.CalibrateTurntable import * +from MF.V3.Tasks.HasTurntable import * +from MF.V3.Tasks.BoundingBox import * +from MF.V3.Tasks.PopSettings import * +from MF.V3.Tasks.StopVideo import * +from MF.V3.Tasks.RemoveGroups import * +from MF.V3.Tasks.PushSettings import * +from MF.V3.Tasks.HasCameras import * +from MF.V3.Tasks.ForgetWifi import * +from MF.V3.Tasks.MergeData import * diff --git a/maf_three/MF/V3/Three.py b/maf_three/MF/V3/Three.py new file mode 100644 index 0000000..989acd7 --- /dev/null +++ b/maf_three/MF/V3/Three.py @@ -0,0 +1,1111 @@ +from MF.V3.Tasks.NewProject import NewProject as MF_V3_Tasks_NewProject +from MF.V3.Tasks.Reboot import Reboot as MF_V3_Tasks_Reboot +from MF.V3.Tasks.SetGroup import SetGroup as MF_V3_Tasks_SetGroup +from MF.V3.Tasks.RemoveProjects import RemoveProjects as MF_V3_Tasks_RemoveProjects +from MF.V3.Tasks.RemoveGroups import RemoveGroups as MF_V3_Tasks_RemoveGroups +from MF.V3.Tasks.CalibrationCaptureTargets import CalibrationCaptureTargets as MF_V3_Tasks_CalibrationCaptureTargets +from MF.V3.Tasks.Shutdown import Shutdown as MF_V3_Tasks_Shutdown +from MF.V3.Tasks.NewScan import NewScan as MF_V3_Tasks_NewScan +from MF.V3.Tasks.ExportMerge import ExportMerge as MF_V3_Tasks_ExportMerge +from MF.V3.Tasks.UpdateSettings import UpdateSettings as MF_V3_Tasks_UpdateSettings +from MF.V3.Tasks.CameraCalibration import CameraCalibration as MF_V3_Tasks_CameraCalibration +from MF.V3.Tasks.StopVideo import StopVideo as MF_V3_Tasks_StopVideo +from MF.V3.Tasks.AddMergeToProject import AddMergeToProject as MF_V3_Tasks_AddMergeToProject +from MF.V3.Tasks.NewGroup import NewGroup as MF_V3_Tasks_NewGroup +from MF.V3.Tasks.Align import Align as MF_V3_Tasks_Align +from MF.V3.Tasks.CalibrateTurntable import CalibrateTurntable as MF_V3_Tasks_CalibrateTurntable +from MF.V3.Tasks.DetectCalibrationCard import DetectCalibrationCard as MF_V3_Tasks_DetectCalibrationCard +from MF.V3.Tasks.OpenProject import OpenProject as MF_V3_Tasks_OpenProject +from MF.V3.Tasks.PushSettings import PushSettings as MF_V3_Tasks_PushSettings +from MF.V3.Tasks.SplitGroup import SplitGroup as MF_V3_Tasks_SplitGroup +from MF.V3.Tasks.UploadProject import UploadProject as MF_V3_Tasks_UploadProject +from MF.V3.Tasks.RotateTurntable import RotateTurntable as MF_V3_Tasks_RotateTurntable +from MF.V3.Tasks.ListExportFormats import ListExportFormats as MF_V3_Tasks_ListExportFormats +from MF.V3.Tasks.ListWifi import ListWifi as MF_V3_Tasks_ListWifi +from MF.V3.Tasks.ExportLogs import ExportLogs as MF_V3_Tasks_ExportLogs +from MF.V3.Tasks.FlattenGroup import FlattenGroup as MF_V3_Tasks_FlattenGroup +from MF.V3.Tasks.MergeData import MergeData as MF_V3_Tasks_MergeData +from MF.V3.Tasks.StartVideo import StartVideo as MF_V3_Tasks_StartVideo +from MF.V3.Tasks.ConnectWifi import ConnectWifi as MF_V3_Tasks_ConnectWifi +from MF.V3.Tasks.BoundingBox import BoundingBox as MF_V3_Tasks_BoundingBox +from MF.V3.Tasks.ListNetworkInterfaces import ListNetworkInterfaces as MF_V3_Tasks_ListNetworkInterfaces +from MF.V3.Tasks.ListProjects import ListProjects as MF_V3_Tasks_ListProjects +from MF.V3.Tasks.AutoFocus import AutoFocus as MF_V3_Tasks_AutoFocus +from MF.V3.Tasks.CalibrateCameras import CalibrateCameras as MF_V3_Tasks_CalibrateCameras +from MF.V3.Tasks.SetProject import SetProject as MF_V3_Tasks_SetProject +from MF.V3.Tasks.DepthMap import DepthMap as MF_V3_Tasks_DepthMap +from MF.V3.Tasks.PopSettings import PopSettings as MF_V3_Tasks_PopSettings +from MF.V3.Tasks.SetProjector import SetProjector as MF_V3_Tasks_SetProjector +from MF.V3.Tasks.HasProjector import HasProjector as MF_V3_Tasks_HasProjector +from MF.V3.Tasks.Export import Export as MF_V3_Tasks_Export +from MF.V3.Tasks.ListGroups import ListGroups as MF_V3_Tasks_ListGroups +from MF.V3.Tasks.DownloadProject import DownloadProject as MF_V3_Tasks_DownloadProject +from MF.V3.Tasks.SystemInfo import SystemInfo as MF_V3_Tasks_SystemInfo +from MF.V3.Tasks.MoveGroup import MoveGroup as MF_V3_Tasks_MoveGroup +from MF.V3.Tasks.HasCameras import HasCameras as MF_V3_Tasks_HasCameras +from MF.V3.Tasks.TurntableCalibration import TurntableCalibration as MF_V3_Tasks_TurntableCalibration +from MF.V3.Tasks.ListSettings import ListSettings as MF_V3_Tasks_ListSettings +from MF.V3.Tasks.CloseProject import CloseProject as MF_V3_Tasks_CloseProject +from MF.V3.Tasks.TransformGroup import TransformGroup as MF_V3_Tasks_TransformGroup +from MF.V3.Tasks.RestoreFactoryCalibration import RestoreFactoryCalibration as MF_V3_Tasks_RestoreFactoryCalibration +from MF.V3.Tasks.ScanData import ScanData as MF_V3_Tasks_ScanData +from MF.V3.Tasks.Merge import Merge as MF_V3_Tasks_Merge +from MF.V3.Tasks.HasTurntable import HasTurntable as MF_V3_Tasks_HasTurntable +from MF.V3.Tasks.SetCameras import SetCameras as MF_V3_Tasks_SetCameras +from MF.V3.Tasks.ForgetWifi import ForgetWifi as MF_V3_Tasks_ForgetWifi +from MF.V3.Tasks.ListScans import ListScans as MF_V3_Tasks_ListScans +from MF.V3 import Task +from MF.V3.Settings.Wifi import Wifi as MF_V3_Settings_Wifi_Wifi +from MF.V3.Settings.Scanner import Scanner as MF_V3_Settings_Scanner_Scanner +from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera +from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture +from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n +from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector +from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style +from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable +from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials +from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer +from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software +from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData +from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project +from MF.V3.Settings.Group import Group as MF_V3_Settings_Group_Group +from MF.V3.Settings.NewGroup import NewGroup as MF_V3_Settings_NewGroup_NewGroup +from MF.V3.Settings.BoundingBox import BoundingBox as MF_V3_Settings_BoundingBox_BoundingBox +from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection +from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align +from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge +from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export +from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan + + +class Three: + # Three scanner API. + def __init__(self): + pass + + def list_network_interfaces(scanner) -> Task: + # List available wifi networks. + list_network_interfaces_request = MF_V3_Tasks_ListNetworkInterfaces.Request( + Index=0, + Type="ListNetworkInterfaces" + ) + list_network_interfaces_response = MF_V3_Tasks_ListNetworkInterfaces.Response( + Index=0, + Type="ListNetworkInterfaces" + ) + task = Task(Index=0, Type="ListNetworkInterfaces", Input=list_network_interfaces_request, Output=list_network_interfaces_response) + scanner.SendTask(task) + return task + + def list_wifi(scanner) -> Task: + # List available wifi networks. + list_wifi_request = MF_V3_Tasks_ListWifi.Request( + Index=0, + Type="ListWifi" + ) + list_wifi_response = MF_V3_Tasks_ListWifi.Response( + Index=0, + Type="ListWifi" + ) + task = Task(Index=0, Type="ListWifi", Input=list_wifi_request, Output=list_wifi_response) + scanner.SendTask(task) + return task + + def connect_wifi(scanner, ssid: str, password: str) -> Task: + # Connect to a wifi network. + connect_wifi_request = MF_V3_Tasks_ConnectWifi.Request( + Index=0, + Type="ConnectWifi", + Input=MF_V3_Settings_Wifi_Wifi( + ssid=ssid, + password=password, + ) + ) + connect_wifi_response = MF_V3_Tasks_ConnectWifi.Response( + Index=0, + Type="ConnectWifi", + Input=MF_V3_Settings_Wifi_Wifi( + ssid=ssid, + password=password, + ) + ) + task = Task(Index=0, Type="ConnectWifi", Input=connect_wifi_request, Output=connect_wifi_response) + scanner.SendTask(task) + return task + + def forget_wifi(scanner) -> Task: + # Forget all wifi connections. + forget_wifi_request = MF_V3_Tasks_ForgetWifi.Request( + Index=0, + Type="ForgetWifi" + ) + forget_wifi_response = MF_V3_Tasks_ForgetWifi.Response( + Index=0, + Type="ForgetWifi" + ) + task = Task(Index=0, Type="ForgetWifi", Input=forget_wifi_request, Output=forget_wifi_response) + scanner.SendTask(task) + return task + + def list_settings(scanner) -> Task: + # Get scanner settings. + list_settings_request = MF_V3_Tasks_ListSettings.Request( + Index=0, + Type="ListSettings" + ) + list_settings_response = MF_V3_Tasks_ListSettings.Response( + Index=0, + Type="ListSettings" + ) + task = Task(Index=0, Type="ListSettings", Input=list_settings_request, Output=list_settings_response) + scanner.SendTask(task) + return task + + def push_settings(scanner) -> Task: + # Push the current scanner settings to the settings stack. + push_settings_request = MF_V3_Tasks_PushSettings.Request( + Index=0, + Type="PushSettings" + ) + push_settings_response = MF_V3_Tasks_PushSettings.Response( + Index=0, + Type="PushSettings" + ) + task = Task(Index=0, Type="PushSettings", Input=push_settings_request, Output=push_settings_response) + scanner.SendTask(task) + return task + + def pop_settings(scanner, Input: bool = None) -> Task: + # Pop and restore scanner settings from the settings stack. + pop_settings_request = MF_V3_Tasks_PopSettings.Request( + Index=0, + Type="PopSettings", + Input=Input + ) + pop_settings_response = MF_V3_Tasks_PopSettings.Response( + Index=0, + Type="PopSettings" + ) + task = Task(Index=0, Type="PopSettings", Input=pop_settings_request, Output=pop_settings_response) + scanner.SendTask(task) + return task + + def update_settings(scanner, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None) -> Task: + # Update scanner settings. + update_settings_request = MF_V3_Tasks_UpdateSettings.Request( + Index=0, + Type="UpdateSettings", + Input=MF_V3_Settings_Scanner_Scanner( + advanced=advanced, + camera=camera, + capture=capture, + i18n=i18n, + projector=projector, + style=style, + turntable=turntable, + tutorials=tutorials, + viewer=viewer, + software=software, + ) + ) + update_settings_response = MF_V3_Tasks_UpdateSettings.Response( + Index=0, + Type="UpdateSettings", + Input=MF_V3_Settings_Scanner_Scanner( + advanced=advanced, + camera=camera, + capture=capture, + i18n=i18n, + projector=projector, + style=style, + turntable=turntable, + tutorials=tutorials, + viewer=viewer, + software=software, + ) + ) + task = Task(Index=0, Type="UpdateSettings", Input=update_settings_request, Output=update_settings_response) + scanner.SendTask(task) + return task + + def list_projects(scanner) -> Task: + # List all projects. + list_projects_request = MF_V3_Tasks_ListProjects.Request( + Index=0, + Type="ListProjects" + ) + list_projects_response = MF_V3_Tasks_ListProjects.Response( + Index=0, + Type="ListProjects" + ) + task = Task(Index=0, Type="ListProjects", Input=list_projects_request, Output=list_projects_response) + scanner.SendTask(task) + return task + + def download_project(scanner, Input: int) -> Task: + # Download a project from the scanner. + download_project_request = MF_V3_Tasks_DownloadProject.Request( + Index=0, + Type="DownloadProject", + Input=Input + ) + download_project_response = MF_V3_Tasks_DownloadProject.Response( + Index=0, + Type="DownloadProject", + Input=Input + ) + task = Task(Index=0, Type="DownloadProject", Input=download_project_request, Output=download_project_response) + scanner.SendTask(task) + return task + + def upload_project(scanner) -> Task: + # Upload a project to the scanner. + upload_project_request = MF_V3_Tasks_UploadProject.Request( + Index=0, + Type="UploadProject" + ) + upload_project_response = MF_V3_Tasks_UploadProject.Response( + Index=0, + Type="UploadProject" + ) + task = Task(Index=0, Type="UploadProject", Input=upload_project_request, Output=upload_project_response) + scanner.SendTask(task) + return task + + def new_project(scanner, Input: str = None) -> Task: + # Create a new project. + new_project_request = MF_V3_Tasks_NewProject.Request( + Index=0, + Type="NewProject", + Input=Input + ) + new_project_response = MF_V3_Tasks_NewProject.Response( + Index=0, + Type="NewProject" + ) + task = Task(Index=0, Type="NewProject", Input=new_project_request, Output=new_project_response) + scanner.SendTask(task) + return task + + def open_project(scanner, Input: int) -> Task: + # Open an existing project. + open_project_request = MF_V3_Tasks_OpenProject.Request( + Index=0, + Type="OpenProject", + Input=Input + ) + open_project_response = MF_V3_Tasks_OpenProject.Response( + Index=0, + Type="OpenProject", + Input=Input + ) + task = Task(Index=0, Type="OpenProject", Input=open_project_request, Output=open_project_response) + scanner.SendTask(task) + return task + + def close_project(scanner) -> Task: + # Close the current open project. + close_project_request = MF_V3_Tasks_CloseProject.Request( + Index=0, + Type="CloseProject" + ) + close_project_response = MF_V3_Tasks_CloseProject.Response( + Index=0, + Type="CloseProject" + ) + task = Task(Index=0, Type="CloseProject", Input=close_project_request, Output=close_project_response) + scanner.SendTask(task) + return task + + def remove_projects(scanner, Input: int) -> Task: + # Remove selected projects. + remove_projects_request = MF_V3_Tasks_RemoveProjects.Request( + Index=0, + Type="RemoveProjects", + Input=Input + ) + remove_projects_response = MF_V3_Tasks_RemoveProjects.Response( + Index=0, + Type="RemoveProjects", + Input=Input + ) + task = Task(Index=0, Type="RemoveProjects", Input=remove_projects_request, Output=remove_projects_response) + scanner.SendTask(task) + return task + + def list_groups(scanner) -> Task: + # List the scan groups in the current open project. + list_groups_request = MF_V3_Tasks_ListGroups.Request( + Index=0, + Type="ListGroups" + ) + list_groups_response = MF_V3_Tasks_ListGroups.Response( + Index=0, + Type="ListGroups", + Output=None + ) + task = Task(Index=0, Type="ListGroups", Input=list_groups_request, Output=list_groups_response) + scanner.SendTask(task) + return task + + def list_scans(scanner) -> Task: + # List the scans in the current open project. + list_scans_request = MF_V3_Tasks_ListScans.Request( + Index=0, + Type="ListScans" + ) + list_scans_response = MF_V3_Tasks_ListScans.Response( + Index=0, + Type="ListScans", + Output=None + ) + task = Task(Index=0, Type="ListScans", Input=list_scans_request, Output=list_scans_response) + scanner.SendTask(task) + return task + + def scan_data(scanner, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: + # Download the raw scan data for a scan in the current open project. + scan_data_request = MF_V3_Tasks_ScanData.Request( + Index=0, + Type="ScanData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + buffers=buffers, + metadata=metadata, + mergeStep=mergeStep, + ) + ) + scan_data_response = MF_V3_Tasks_ScanData.Response( + Index=0, + Type="ScanData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + buffers=buffers, + metadata=metadata, + mergeStep=mergeStep, + ), + Output=None + ) + task = Task(Index=0, Type="ScanData", Input=scan_data_request, Output=scan_data_response) + scanner.SendTask(task) + return task + + def set_project(scanner, index: int = None, name: str = None) -> Task: + # Apply settings to the current open project. + set_project_request = MF_V3_Tasks_SetProject.Request( + Index=0, + Type="SetProject", + Input=MF_V3_Settings_Project_Project( + index=index, + name=name, + ) + ) + set_project_response = MF_V3_Tasks_SetProject.Response( + Index=0, + Type="SetProject" + ) + task = Task(Index=0, Type="SetProject", Input=set_project_request, Output=set_project_response) + scanner.SendTask(task) + return task + + def set_group(scanner, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: + # Set scan group properties. + set_group_request = MF_V3_Tasks_SetGroup.Request( + Index=0, + Type="SetGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + color=color, + rotation=rotation, + translation=translation, + name=name, + visible=visible, + collapsed=collapsed, + ) + ) + set_group_response = MF_V3_Tasks_SetGroup.Response( + Index=0, + Type="SetGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + color=color, + rotation=rotation, + translation=translation, + name=name, + visible=visible, + collapsed=collapsed, + ), + Output=None + ) + task = Task(Index=0, Type="SetGroup", Input=set_group_request, Output=set_group_response) + scanner.SendTask(task) + return task + + def new_group(scanner, color: float, rotation: float, translation: float, parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None) -> Task: + # Create a new scan group. + new_group_request = MF_V3_Tasks_NewGroup.Request( + Index=0, + Type="NewGroup", + Input=MF_V3_Settings_NewGroup_NewGroup( + color=color, + rotation=rotation, + translation=translation, + parentIndex=parentIndex, + baseName=baseName, + visible=visible, + collapsed=collapsed, + ) + ) + new_group_response = MF_V3_Tasks_NewGroup.Response( + Index=0, + Type="NewGroup", + Output=None + ) + task = Task(Index=0, Type="NewGroup", Input=new_group_request, Output=new_group_response) + scanner.SendTask(task) + return task + + def move_group(scanner, Input: int) -> Task: + # Move a scan group. + move_group_request = MF_V3_Tasks_MoveGroup.Request( + Index=0, + Type="MoveGroup", + Input=Input + ) + move_group_response = MF_V3_Tasks_MoveGroup.Response( + Index=0, + Type="MoveGroup", + Input=Input, + Output=None + ) + task = Task(Index=0, Type="MoveGroup", Input=move_group_request, Output=move_group_response) + scanner.SendTask(task) + return task + + def flatten_group(scanner, Input: int) -> Task: + # Flatten a scan group such that it only consists of single scans. + flatten_group_request = MF_V3_Tasks_FlattenGroup.Request( + Index=0, + Type="FlattenGroup", + Input=Input + ) + flatten_group_response = MF_V3_Tasks_FlattenGroup.Response( + Index=0, + Type="FlattenGroup", + Input=Input, + Output=None + ) + task = Task(Index=0, Type="FlattenGroup", Input=flatten_group_request, Output=flatten_group_response) + scanner.SendTask(task) + return task + + def split_group(scanner, Input: int) -> Task: + # Split a scan group (ie. move its subgroups to its parent group). + split_group_request = MF_V3_Tasks_SplitGroup.Request( + Index=0, + Type="SplitGroup", + Input=Input + ) + split_group_response = MF_V3_Tasks_SplitGroup.Response( + Index=0, + Type="SplitGroup", + Input=Input, + Output=None + ) + task = Task(Index=0, Type="SplitGroup", Input=split_group_request, Output=split_group_response) + scanner.SendTask(task) + return task + + def transform_group(scanner, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: + # Apply a rigid transformation to a group. + transform_group_request = MF_V3_Tasks_TransformGroup.Request( + Index=0, + Type="TransformGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + color=color, + rotation=rotation, + translation=translation, + name=name, + visible=visible, + collapsed=collapsed, + ) + ) + transform_group_response = MF_V3_Tasks_TransformGroup.Response( + Index=0, + Type="TransformGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + color=color, + rotation=rotation, + translation=translation, + name=name, + visible=visible, + collapsed=collapsed, + ), + Output=None + ) + task = Task(Index=0, Type="TransformGroup", Input=transform_group_request, Output=transform_group_response) + scanner.SendTask(task) + return task + + def remove_groups(scanner, Input: int) -> Task: + # Remove selected scan groups. + remove_groups_request = MF_V3_Tasks_RemoveGroups.Request( + Index=0, + Type="RemoveGroups", + Input=Input + ) + remove_groups_response = MF_V3_Tasks_RemoveGroups.Response( + Index=0, + Type="RemoveGroups", + Input=Input, + Output=None + ) + task = Task(Index=0, Type="RemoveGroups", Input=remove_groups_request, Output=remove_groups_response) + scanner.SendTask(task) + return task + + def bounding_box(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool) -> Task: + # Get the bounding box of a set of scan groups. + bounding_box_request = MF_V3_Tasks_BoundingBox.Request( + Index=0, + Type="BoundingBox", + Input=MF_V3_Settings_BoundingBox_BoundingBox( + selection=selection, + axisAligned=axisAligned, + ) + ) + bounding_box_response = MF_V3_Tasks_BoundingBox.Response( + Index=0, + Type="BoundingBox", + Input=MF_V3_Settings_BoundingBox_BoundingBox( + selection=selection, + axisAligned=axisAligned, + ), + Output=None + ) + task = Task(Index=0, Type="BoundingBox", Input=bounding_box_request, Output=bounding_box_response) + scanner.SendTask(task) + return task + + def align(scanner, source: int, target: int, rough: MF_V3_Settings_Align_Align.Rough = None, fine: MF_V3_Settings_Align_Align.Fine = None) -> Task: + # Align two scan groups. + align_request = MF_V3_Tasks_Align.Request( + Index=0, + Type="Align", + Input=MF_V3_Settings_Align_Align( + source=source, + target=target, + rough=rough, + fine=fine, + ) + ) + align_response = MF_V3_Tasks_Align.Response( + Index=0, + Type="Align", + Input=MF_V3_Settings_Align_Align( + source=source, + target=target, + rough=rough, + fine=fine, + ), + Output=None + ) + task = Task(Index=0, Type="Align", Input=align_request, Output=align_response) + scanner.SendTask(task) + return task + + def merge(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: MF_V3_Settings_Merge_Merge.Remesh = None, simplify: MF_V3_Settings_Merge_Merge.Simplify = None, texturize: bool = None) -> Task: + # Merge two or more scan groups. + merge_request = MF_V3_Tasks_Merge.Request( + Index=0, + Type="Merge", + Input=MF_V3_Settings_Merge_Merge( + selection=selection, + remesh=remesh, + simplify=simplify, + texturize=texturize, + ) + ) + merge_response = MF_V3_Tasks_Merge.Response( + Index=0, + Type="Merge", + Input=MF_V3_Settings_Merge_Merge( + selection=selection, + remesh=remesh, + simplify=simplify, + texturize=texturize, + ), + Output=None + ) + task = Task(Index=0, Type="Merge", Input=merge_request, Output=merge_response) + scanner.SendTask(task) + return task + + def merge_data(scanner, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: + # Download the raw scan data for the current merge process. + merge_data_request = MF_V3_Tasks_MergeData.Request( + Index=0, + Type="MergeData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + buffers=buffers, + metadata=metadata, + mergeStep=mergeStep, + ) + ) + merge_data_response = MF_V3_Tasks_MergeData.Response( + Index=0, + Type="MergeData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + buffers=buffers, + metadata=metadata, + mergeStep=mergeStep, + ), + Output=None + ) + task = Task(Index=0, Type="MergeData", Input=merge_data_request, Output=merge_data_response) + scanner.SendTask(task) + return task + + def add_merge_to_project(scanner) -> Task: + # Add a merged scan to the current project. + add_merge_to_project_request = MF_V3_Tasks_AddMergeToProject.Request( + Index=0, + Type="AddMergeToProject" + ) + add_merge_to_project_response = MF_V3_Tasks_AddMergeToProject.Response( + Index=0, + Type="AddMergeToProject", + Output=None + ) + task = Task(Index=0, Type="AddMergeToProject", Input=add_merge_to_project_request, Output=add_merge_to_project_response) + scanner.SendTask(task) + return task + + def list_export_formats(scanner) -> Task: + # List all export formats. + list_export_formats_request = MF_V3_Tasks_ListExportFormats.Request( + Index=0, + Type="ListExportFormats" + ) + list_export_formats_response = MF_V3_Tasks_ListExportFormats.Response( + Index=0, + Type="ListExportFormats", + Output=None + ) + task = Task(Index=0, Type="ListExportFormats", Input=list_export_formats_request, Output=list_export_formats_response) + scanner.SendTask(task) + return task + + def export(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: + # Export a group of scans. + export_request = MF_V3_Tasks_Export.Request( + Index=0, + Type="Export", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + ) + ) + export_response = MF_V3_Tasks_Export.Response( + Index=0, + Type="Export", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + ) + ) + task = Task(Index=0, Type="Export", Input=export_request, Output=export_response) + scanner.SendTask(task) + return task + + def export_merge(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: + # Export a merged scan. + export_merge_request = MF_V3_Tasks_ExportMerge.Request( + Index=0, + Type="ExportMerge", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + ) + ) + export_merge_response = MF_V3_Tasks_ExportMerge.Response( + Index=0, + Type="ExportMerge", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + ) + ) + task = Task(Index=0, Type="ExportMerge", Input=export_merge_request, Output=export_merge_response) + scanner.SendTask(task) + return task + + def export_logs(scanner, Input: bool = None) -> Task: + # Export scanner logs. + export_logs_request = MF_V3_Tasks_ExportLogs.Request( + Index=0, + Type="ExportLogs", + Input=Input + ) + export_logs_response = MF_V3_Tasks_ExportLogs.Response( + Index=0, + Type="ExportLogs" + ) + task = Task(Index=0, Type="ExportLogs", Input=export_logs_request, Output=export_logs_response) + scanner.SendTask(task) + return task + + def has_cameras(scanner) -> Task: + # Check if the scanner has working cameras. + has_cameras_request = MF_V3_Tasks_HasCameras.Request( + Index=0, + Type="HasCameras" + ) + has_cameras_response = MF_V3_Tasks_HasCameras.Response( + Index=0, + Type="HasCameras" + ) + task = Task(Index=0, Type="HasCameras", Input=has_cameras_request, Output=has_cameras_response) + scanner.SendTask(task) + return task + + def has_projector(scanner) -> Task: + # Check if the scanner has a working projector. + has_projector_request = MF_V3_Tasks_HasProjector.Request( + Index=0, + Type="HasProjector" + ) + has_projector_response = MF_V3_Tasks_HasProjector.Response( + Index=0, + Type="HasProjector" + ) + task = Task(Index=0, Type="HasProjector", Input=has_projector_request, Output=has_projector_response) + scanner.SendTask(task) + return task + + def has_turntable(scanner) -> Task: + # Check if the scanner is connected to a working turntable. + has_turntable_request = MF_V3_Tasks_HasTurntable.Request( + Index=0, + Type="HasTurntable" + ) + has_turntable_response = MF_V3_Tasks_HasTurntable.Response( + Index=0, + Type="HasTurntable" + ) + task = Task(Index=0, Type="HasTurntable", Input=has_turntable_request, Output=has_turntable_response) + scanner.SendTask(task) + return task + + def system_info(scanner, installed: MF_V3_Settings_Software_Software.Package, available: MF_V3_Settings_Software_Software.Package, nightlyIncluded: bool = None) -> Task: + # Get system information. + system_info_request = MF_V3_Tasks_SystemInfo.Request( + Index=0, + Type="SystemInfo", + Input=MF_V3_Settings_Software_Software( + installed=installed, + available=available, + nightlyIncluded=nightlyIncluded, + ) + ) + system_info_response = MF_V3_Tasks_SystemInfo.Response( + Index=0, + Type="SystemInfo", + Output=None + ) + task = Task(Index=0, Type="SystemInfo", Input=system_info_request, Output=system_info_response) + scanner.SendTask(task) + return task + + def camera_calibration(scanner) -> Task: + # Get the camera calibration descriptor. + camera_calibration_request = MF_V3_Tasks_CameraCalibration.Request( + Index=0, + Type="CameraCalibration" + ) + camera_calibration_response = MF_V3_Tasks_CameraCalibration.Response( + Index=0, + Type="CameraCalibration" + ) + task = Task(Index=0, Type="CameraCalibration", Input=camera_calibration_request, Output=camera_calibration_response) + scanner.SendTask(task) + return task + + def turntable_calibration(scanner) -> Task: + # Get the turntable calibration descriptor. + turntable_calibration_request = MF_V3_Tasks_TurntableCalibration.Request( + Index=0, + Type="TurntableCalibration" + ) + turntable_calibration_response = MF_V3_Tasks_TurntableCalibration.Response( + Index=0, + Type="TurntableCalibration" + ) + task = Task(Index=0, Type="TurntableCalibration", Input=turntable_calibration_request, Output=turntable_calibration_response) + scanner.SendTask(task) + return task + + def calibration_capture_targets(scanner) -> Task: + # Get the calibration capture target for each camera calibration capture. + calibration_capture_targets_request = MF_V3_Tasks_CalibrationCaptureTargets.Request( + Index=0, + Type="CalibrationCaptureTargets" + ) + calibration_capture_targets_response = MF_V3_Tasks_CalibrationCaptureTargets.Response( + Index=0, + Type="CalibrationCaptureTargets" + ) + task = Task(Index=0, Type="CalibrationCaptureTargets", Input=calibration_capture_targets_request, Output=calibration_capture_targets_response) + scanner.SendTask(task) + return task + + def calibrate_cameras(scanner) -> Task: + # Calibrate the cameras. + calibrate_cameras_request = MF_V3_Tasks_CalibrateCameras.Request( + Index=0, + Type="CalibrateCameras" + ) + calibrate_cameras_response = MF_V3_Tasks_CalibrateCameras.Response( + Index=0, + Type="CalibrateCameras" + ) + task = Task(Index=0, Type="CalibrateCameras", Input=calibrate_cameras_request, Output=calibrate_cameras_response) + scanner.SendTask(task) + return task + + def calibrate_turntable(scanner) -> Task: + # Calibrate the turntable. + calibrate_turntable_request = MF_V3_Tasks_CalibrateTurntable.Request( + Index=0, + Type="CalibrateTurntable" + ) + calibrate_turntable_response = MF_V3_Tasks_CalibrateTurntable.Response( + Index=0, + Type="CalibrateTurntable" + ) + task = Task(Index=0, Type="CalibrateTurntable", Input=calibrate_turntable_request, Output=calibrate_turntable_response) + scanner.SendTask(task) + return task + + def detect_calibration_card(scanner, Input: int) -> Task: + # Detect the calibration card on one or both cameras. + detect_calibration_card_request = MF_V3_Tasks_DetectCalibrationCard.Request( + Index=0, + Type="DetectCalibrationCard", + Input=Input + ) + detect_calibration_card_response = MF_V3_Tasks_DetectCalibrationCard.Response( + Index=0, + Type="DetectCalibrationCard", + Input=Input + ) + task = Task(Index=0, Type="DetectCalibrationCard", Input=detect_calibration_card_request, Output=detect_calibration_card_response) + scanner.SendTask(task) + return task + + def restore_factory_calibration(scanner) -> Task: + # Restore factory calibration. + restore_factory_calibration_request = MF_V3_Tasks_RestoreFactoryCalibration.Request( + Index=0, + Type="RestoreFactoryCalibration" + ) + restore_factory_calibration_response = MF_V3_Tasks_RestoreFactoryCalibration.Response( + Index=0, + Type="RestoreFactoryCalibration" + ) + task = Task(Index=0, Type="RestoreFactoryCalibration", Input=restore_factory_calibration_request, Output=restore_factory_calibration_response) + scanner.SendTask(task) + return task + + def start_video(scanner) -> Task: + # Start the video stream. + start_video_request = MF_V3_Tasks_StartVideo.Request( + Index=0, + Type="StartVideo" + ) + start_video_response = MF_V3_Tasks_StartVideo.Response( + Index=0, + Type="StartVideo" + ) + task = Task(Index=0, Type="StartVideo", Input=start_video_request, Output=start_video_response) + scanner.SendTask(task) + return task + + def stop_video(scanner) -> Task: + # Stop the video stream. + stop_video_request = MF_V3_Tasks_StopVideo.Request( + Index=0, + Type="StopVideo" + ) + stop_video_response = MF_V3_Tasks_StopVideo.Response( + Index=0, + Type="StopVideo" + ) + task = Task(Index=0, Type="StopVideo", Input=stop_video_request, Output=stop_video_response) + scanner.SendTask(task) + return task + + def set_cameras(scanner, selection: int, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> Task: + # Apply camera settings to one or both cameras. + set_cameras_request = MF_V3_Tasks_SetCameras.Request( + Index=0, + Type="SetCameras", + Input=MF_V3_Settings_Camera_Camera( + selection=selection, + autoExposure=autoExposure, + exposure=exposure, + analogGain=analogGain, + digitalGain=digitalGain, + focus=focus, + ) + ) + set_cameras_response = MF_V3_Tasks_SetCameras.Response( + Index=0, + Type="SetCameras" + ) + task = Task(Index=0, Type="SetCameras", Input=set_cameras_request, Output=set_cameras_response) + scanner.SendTask(task) + return task + + def set_projector(scanner, color: float, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None) -> Task: + # Apply projector settings. + set_projector_request = MF_V3_Tasks_SetProjector.Request( + Index=0, + Type="SetProjector", + Input=MF_V3_Settings_Projector_Projector( + color=color, + on=on, + brightness=brightness, + pattern=pattern, + image=image, + ) + ) + set_projector_response = MF_V3_Tasks_SetProjector.Response( + Index=0, + Type="SetProjector" + ) + task = Task(Index=0, Type="SetProjector", Input=set_projector_request, Output=set_projector_response) + scanner.SendTask(task) + return task + + def auto_focus(scanner, cameras: MF_V3_Settings_AutoFocus_AutoFocus.Camera, applyAll: bool) -> Task: + # Auto focus one or both cameras. + auto_focus_request = MF_V3_Tasks_AutoFocus.Request( + Index=0, + Type="AutoFocus", + Input=MF_V3_Settings_AutoFocus_AutoFocus( + cameras=cameras, + applyAll=applyAll, + ) + ) + auto_focus_response = MF_V3_Tasks_AutoFocus.Response( + Index=0, + Type="AutoFocus" + ) + task = Task(Index=0, Type="AutoFocus", Input=auto_focus_request, Output=auto_focus_response) + scanner.SendTask(task) + return task + + def rotate_turntable(scanner, Input: int) -> Task: + # Rotate the turntable. + rotate_turntable_request = MF_V3_Tasks_RotateTurntable.Request( + Index=0, + Type="RotateTurntable", + Input=Input + ) + rotate_turntable_response = MF_V3_Tasks_RotateTurntable.Response( + Index=0, + Type="RotateTurntable", + Input=Input + ) + task = Task(Index=0, Type="RotateTurntable", Input=rotate_turntable_request, Output=rotate_turntable_response) + scanner.SendTask(task) + return task + + def new_scan(scanner, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: + # Capture a new scan. + new_scan_request = MF_V3_Tasks_NewScan.Request( + Index=0, + Type="NewScan", + Input=MF_V3_Settings_Scan_Scan( + camera=camera, + projector=projector, + turntable=turntable, + capture=capture, + processing=processing, + ) + ) + new_scan_response = MF_V3_Tasks_NewScan.Response( + Index=0, + Type="NewScan" + ) + task = Task(Index=0, Type="NewScan", Input=new_scan_request, Output=new_scan_response) + scanner.SendTask(task) + return task + + def depth_map(scanner, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: + # Capture a depth map. + depth_map_request = MF_V3_Tasks_DepthMap.Request( + Index=0, + Type="DepthMap", + Input=MF_V3_Settings_Scan_Scan( + camera=camera, + projector=projector, + turntable=turntable, + capture=capture, + processing=processing, + ) + ) + depth_map_response = MF_V3_Tasks_DepthMap.Response( + Index=0, + Type="DepthMap", + Output=None + ) + task = Task(Index=0, Type="DepthMap", Input=depth_map_request, Output=depth_map_response) + scanner.SendTask(task) + return task + + def reboot(scanner) -> Task: + # Reboot the scanner. + reboot_request = MF_V3_Tasks_Reboot.Request( + Index=0, + Type="Reboot" + ) + reboot_response = MF_V3_Tasks_Reboot.Response( + Index=0, + Type="Reboot" + ) + task = Task(Index=0, Type="Reboot", Input=reboot_request, Output=reboot_response) + scanner.SendTask(task) + return task + + def shutdown(scanner) -> Task: + # Shutdown the scanner. + shutdown_request = MF_V3_Tasks_Shutdown.Request( + Index=0, + Type="Shutdown" + ) + shutdown_response = MF_V3_Tasks_Shutdown.Response( + Index=0, + Type="Shutdown" + ) + task = Task(Index=0, Type="Shutdown", Input=shutdown_request, Output=shutdown_response) + scanner.SendTask(task) + return task + + + diff --git a/maf_three/MF/V3/__init__.py b/maf_three/MF/V3/__init__.py new file mode 100644 index 0000000..69fcf73 --- /dev/null +++ b/maf_three/MF/V3/__init__.py @@ -0,0 +1,3 @@ +from MF.V3.Three import * +from MF.V3.Task import * +from MF.V3.Buffer import * diff --git a/maf_three/V3Task.py b/maf_three/V3Task.py deleted file mode 100644 index 1a17c58..0000000 --- a/maf_three/V3Task.py +++ /dev/null @@ -1,212 +0,0 @@ - - -from enum import Enum - -class V3Task(str, Enum): - - """Create a new test scan""" - NewTestScan = 'NewTestScan', - - """Download a file from the server workspace""" - DownloadFile = 'DownloadFile', - - - - - """Get filesystem capacity and availability""" - DiskSpace = 'DiskSpace', - - """Software installed version.""" - SoftwareVersionInstalled = 'SoftwareVersionInstalled', - - """Software available version""" - SoftwareVersionAvailable = 'SoftwareVersionAvailable', - - """Get a still image from each camera""" - StillImage = 'StillImage', - - """Get a stream image from each camera""" - StreamImage = 'StreamImage', - - """Get the camera calibration descriptor for the current focus values""" - CameraCalibration = 'CameraCalibration', - - """Get the turntable calibration descriptor""" - TurntableCalibration = 'TurntableCalibration', - - """Get the camera calibration capture targets""" - CalibrationCaptureTargets = 'CalibrationCaptureTargets', - - """Calibrate cameras""" - CalibrateCameras = 'CalibrateCameras', - - """Calibrate turntable""" - CalibrateTurntable = 'CalibrateTurntable', - - """Start video stream""" - StartVideo = 'StartVideo', - - """Stop video stream""" - StopVideo = 'StopVideo', - - """Apply camera settings cameras""" - SetCameras = 'SetCameras', - - """Apply projector settings""" - SetProjector = 'SetProjector', - - """Check if the server can connect to cameras""" - HasCameras = 'HasCameras', - - """Check if the server can connect to a projector""" - HasProjector = 'HasProjector', - - """Check if the server can connect to a turntable""" - HasTurntable = 'HasTurntable', - - """Auto focus the cameras""" - AutoFocus = 'AutoFocus', - - """Rotate the turntable""" - RotateTurntable = 'RotateTurntable', - - """Detect the calibration card""" - DetectCalibrationCard = 'DetectCalibrationCard', - - """Get the set of projects in the workspace""" - ListProjects = 'ListProjects', - - """Download a project from the scanner""" - DownloadProject = 'DownloadProject', - - """Upload a project to the scanner""" - UploadProject = 'UploadProject', - - """Set project properties""" - SetProject = 'SetProject', - - """Create a new project""" - NewProject = 'NewProject', - - """Open an existing project""" - OpenProject = 'OpenProject', - - """Close an opened project""" - CloseProject = 'CloseProject', - - """Remove selected projects from the workspace""" - RemoveProjects = 'RemoveProjects', - - """Clear the available project undo and redo actions""" - ClearProjectActions = 'ClearProjectActions', - - """List the available project undo and redo actions""" - ListProjectActions = 'ListProjectActions', - - """Undo a number of project actions""" - UndoProjectActions = 'UndoProjectActions', - - """Redo a number of project actions""" - RedoProjectActions = 'RedoProjectActions', - - """List the scans in the current project""" - ListScans = 'ListScans', - - """Get geometry data for a selected scan""" - ScanData = 'ScanData', - - """Capture and process a new scan""" - NewScan = 'NewScan', - - """List the groups in the current project.""" - ListGroups = 'ListGroups', - - """Set scan group properties.""" - SetGroup = 'SetGroup', - - """Create a scan group.""" - NewGroup = 'NewGroup', - - """Move a scan group.""" - MoveGroup = 'MoveGroup', - - """Flatten a scan group such that it only consists of single scans.""" - FlattenGroup = 'FlattenGroup', - - """Split a scan group (ie move its subgroups to its parent group).""" - SplitGroup = 'SplitGroup', - - """Remove scan groups.""" - RemoveGroups = 'RemoveGroups', - - """Apply a rigid transformation to a group.""" - TransformGroup = 'TransformGroup', - - """Get the bounding box of a set of scan groups.""" - BoundingBox = 'BoundingBox', - - """Align two scan groups.""" - Align = 'Align', - - """Align two scan groups.""" - Merge = 'Merge', - - """Get geometry data for a the current merged scan.""" - MergeData = 'MergeData', - - """Add a merged scan to the current project.""" - AddMergeToProject = 'AddMergeToProject', - - """List export formats and their supported geometry elements.""" - ListExportFormats = 'ListExportFormats', - - """Export a group of scan.""" - Export = 'Export', - - """Export a merged scan.""" - ExportMerge = 'ExportMerge', - - """Export a backend logs.""" - ExportLogs = 'ExportLogs', - - """Get the global settings.""" - ListSettings = 'ListSettings', - - """Get the global settings.""" - PushSettings = 'PushSettings', - - """Get the global settings.""" - PopSettings = 'PopSettings', - - """Save the global settings.""" - UpdateSettings = 'UpdateSettings', - - """Reboot the scanner.""" - Reboot = 'Reboot', - - """Shutdown the scanner.""" - Shutdown = 'Shutdown', - - """List the available Wifi networks.""" - ListWifi = 'ListWifi', - - """Connect to a specific Wifi network.""" - ConnectWifi = 'ConnectWifi', - - """Query the access point status.""" - AccessPointStatus = 'AccessPointStatus', - - """List the network interfaces.""" - ListNetworkInterfaces = 'ListNetworkInterfaces', - - """Remove Vertices.""" - RemoveVertices = 'RemoveVertices', - - """Disable ethernet connection.""" - DisableEthernet = 'DisableEthernet', - - """Disable wifi connection.""" - DisableWifi = 'DisableWifi', - - """Forget wifi connection.""" - ForgetWifi = 'ForgetWifi' diff --git a/maf_three/buffer.py b/maf_three/buffer.py deleted file mode 100644 index 58069e6..0000000 --- a/maf_three/buffer.py +++ /dev/null @@ -1,23 +0,0 @@ -# buffer.py - - -from MF.V3 import Task - - -class Buffer: - """Class representing a buffer.""" - - Index: int - """The index of the buffer.""" - - totalBufferSize: int - """The total size of the buffer that will be sent.""" - - task:Task - """The related task.""" - - - def __init__(self, bufferIndex:int, totalBufferSize:int, task:Task): - self.Index = bufferIndex - self.totalBufferSize = totalBufferSize - self.Task = task diff --git a/maf_three/scanner.py b/maf_three/scanner.py index ec00290..7fa49f4 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -15,9 +15,9 @@ from maf_three import __version__ from maf_three.serialization import TO_JSON -from maf_three.buffer import Buffer +from maf_three.MF.V3.Buffer import Buffer -from scanner_functions import set_projector +from maf_three.MF.V3.Three import Three as MF3 class Scanner: """ @@ -61,7 +61,7 @@ def __init__(self, def bind_functions(self): # SetProjector - self.set_projector = lambda on, brightness, color: set_projector(self, on, brightness, color) + self.set_projector = lambda on, brightness, color: MF3.set_projector(self, on=on, brightness=brightness, color=color) def Connect(self, URI:str, timeoutSec=5) -> bool: """ @@ -326,22 +326,16 @@ def __FindTaskWithIndex(self, index:int) -> Task: # Main function to run the code if __name__ == "__main__": - # def on_task(task): - # print(f"Task received: {task}") - - # def on_message(message): - # print(f"Message received: {message}") - - # def on_buffer(buffer, data): - # print(f"Buffer received: {data}") scanner = Scanner()#OnTask=on_task, OnMessage=on_message, OnBuffer=on_buffer) scanner.Connect("ws://matterandform.local:8081") # Set the projector settings for debugging - scanner.set_projector(on=True, brightness=1.0, color=[1, 1, 1]) - time.sleep(1) - scanner.set_projector(on=False, brightness=1.0, color=[1, 1, 1]) - time.sleep(1) + # scanner.set_projector(on=True, brightness=1.0, color=[1, 1, 1]) + # time.sleep(1) + # scanner.set_projector(on=False, brightness=1.0, color=[1, 1, 1]) + # time.sleep(1) + project_tasks = MF3.list_projects(scanner) + print(project_tasks.Output) scanner.Disconnect() \ No newline at end of file diff --git a/maf_three/scanner_functions.py b/maf_three/scanner_functions.py deleted file mode 100644 index 38bde5a..0000000 --- a/maf_three/scanner_functions.py +++ /dev/null @@ -1,32 +0,0 @@ -from MF.V3.Tasks.SetProjector import SetProjector -from MF.V3.Settings.Projector import Projector -from MF.V3 import Task -from typing import List - -def set_projector(scanner, on: bool, brightness: float, color: list) -> Task: - """ - Sets the projector settings. - - Args: - * on (bool): True to turn the projector on, False to turn it off. - * brightness (float): The brightness of the projector, between 0.0 and 1.0. - * color ([float]): The RGB color of the projector, as a list of three floats between 0.0 and 1.0. - - Returns: - Task: The task object that was sent. - """ - set_projector_request = SetProjector.Request( - Index=0, - Type="SetProjector", - Input=Projector(on=on, brightness=brightness, color=color) - ) - set_projector_response = SetProjector.Response( - Index=0, - Type="SetProjector" - ) - - task = Task(Index=0, Type="SetProjector", Input=set_projector_request, Output=set_projector_response) - - scanner.SendTask(task) - - return task \ No newline at end of file diff --git a/maf_three/task.py b/maf_three/task.py deleted file mode 100644 index fb3ded5..0000000 --- a/maf_three/task.py +++ /dev/null @@ -1,83 +0,0 @@ - - -from enum import Enum - -from maf_three.V3Task import V3Task - - -class TaskState(str, Enum): - - - Sent = 'Sent', - """The task has been sent by the client.""" - - Received = 'Received', - """The task has been received by the server.""" - - Started = 'Started', - """The task started by the server.""" - - Completed = 'Completed', - """The task is completed by the server.""" - - Cancelled = 'Cancelled', - """The task has been cancelled by the client.""" - - Failed = 'Failed', - """The task has failed, A string describing the error is returned with the task.""" - - Dropped = 'Dropped', - """The task has not been received by the server, or task IDs were sent out of sequence.""" - - Disconnected = 'Disconnected' - """The client has been disconnected from the server before the task could finish.""" - -class Task: - """ - Class representing a task. - - The typical lifecycle is : - - - Client creates the task. - - Client sends it to the Server. - - Server starts processing the task. - - Server notifies the Client that the processing has started. - - Server finishes processing the task. - - Server notifies the Client that the processing is done. - - Client handles an optional output associated with the task. - """ - - Index: int - """The index of the task. Set by the client only.""" - - Type:V3Task - """The type of the task. Set by the client only.""" - - Input = None - """The input of the task. Set by the client only.""" - - Output = None - """The output of the task. Set by the server only.""" - - State: TaskState | None - """The state of the task. Set by the server only.""" - - Progress: None - """The progress of the task. Set by the server only.""" - - Error: None - """Error related to the task. Set by the server only.""" - - def __init__(self, Index:int, Type:V3Task, Input=None, Output=None, State=None, Progress=None, Error=None ): - self.Index = Index - self.Type = Type - - self.Input = Input - self.Output = Output - - self.State = State - self.Progress = Progress - self.Error = Error - - def __str__(self): - return f'"{self.Index} - {self.Type}" State: {self.State}; Input: {self.Input}; Output: {self.Output}' \ No newline at end of file diff --git a/scripts/build-proto.py b/scripts/build-proto.py index 22aa154..977b830 100644 --- a/scripts/build-proto.py +++ b/scripts/build-proto.py @@ -1,88 +1,17 @@ -# Build proto files - -import os import subprocess -import glob - - -# Paths -scriptPath = os.path.dirname(os.path.realpath(__file__)) -protoInputPath = scriptPath + "/../V3Schema" -protoOutputPath = scriptPath + "/../maf_three" - -print("*****************") -print("Building Proto files from: " + protoInputPath) -print("Output directory: " + protoOutputPath) -print("*****************") - -def BuildProtoFile(protoFile, inputDir, outputDir): - print("---> Building: " + file) - - # Build the proto file - status = subprocess.run([ - 'python3', - 'transpileProto.py', - f'{inputDir}', - f'{outputDir}' - ], capture_output=True) - - return status - - -GREEN = '\033[92m' -RED = '\033[91m' -ENDC = '\033[0m' - -# Find and build all the proto files -fileError = 0 -fileCount = 0 - -# Delete previously compiled directory -previousProtoOutputPath = protoOutputPath + "/MF" - -if os.path.exists(previousProtoOutputPath): - print("Deleting previously compiled directory: " + previousProtoOutputPath) - os.system("rm -rf " + previousProtoOutputPath) - -files = glob.glob(protoInputPath+"/**/*.proto", recursive=True) - -status = subprocess.run([ - 'python3', - f'{scriptPath}/transpileProto.py', - f'{protoInputPath}', - f'{protoOutputPath}' - ], capture_output=True) - -# Print results -if (status.returncode != 0): - print("*****************") - print(RED + 'Error ' + str(status.returncode) + ENDC) - print(status.stderr) - print("*****************") -else: - print("*****************") - print(GREEN + 'Complete ' + str(status.returncode) + ENDC) - print("*****************") - -# Let the caller know if everything was built -if fileError > 0: - exit(1) - -# Remove the _pb2 at the end of the generated files -generatedFiles = glob.glob(protoOutputPath+"/MF/**/*_pb2.*", recursive=True) -for file in generatedFiles: - print('Updating generated file:', file) +import os - # Get the content - with open(file, "r") as f: - lines = f.readlines() +# Build proto files - # Remove '_pb2' - with open(file, "w") as f: - for line in lines: - if "MF.V3" in line: - line = line.replace('_pb2', '') - f.write(line) - - # Rename the file - os.rename(file, file.replace('_pb2', '')) +def run_transpile_proto(): + script_path = os.path.join(os.path.dirname(__file__), 'transpileProto.py') + input_dir = './V3Schema' + output_dir = './maf_three/' + result = subprocess.run(['python', script_path, input_dir, output_dir], capture_output=True, text=True) + if result.returncode != 0: + print(f"Error: {result.stderr}") + else: + print(f"Output: {result.stdout}") + +if __name__ == "__main__": + run_transpile_proto() \ No newline at end of file From d29ea066711b48317a06a780709a97e88f68f0a6 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Mon, 30 Sep 2024 13:09:14 -0400 Subject: [PATCH 55/86] Sorting of imports. --- maf_three/MF/V3/Buffer.py | 2 +- maf_three/MF/V3/Descriptors/Export.py | 2 +- .../MF/V3/Descriptors/Settings/Scanner.py | 10 +- .../MF/V3/Descriptors/Settings/__init__.py | 14 +- maf_three/MF/V3/Descriptors/VideoFrame.py | 2 +- maf_three/MF/V3/Descriptors/__init__.py | 14 +- maf_three/MF/V3/Settings/Merge.py | 2 +- maf_three/MF/V3/Settings/Projector.py | 2 +- maf_three/MF/V3/Settings/Scan.py | 4 +- maf_three/MF/V3/Settings/Scanner.py | 12 +- maf_three/MF/V3/Settings/__init__.py | 42 +- maf_three/MF/V3/Tasks/Align.py | 2 +- maf_three/MF/V3/Tasks/AutoFocus.py | 2 +- maf_three/MF/V3/Tasks/BoundingBox.py | 2 +- maf_three/MF/V3/Tasks/DepthMap.py | 2 +- maf_three/MF/V3/Tasks/Merge.py | 2 +- maf_three/MF/V3/Tasks/NewGroup.py | 2 +- maf_three/MF/V3/Tasks/NewProject.py | 2 +- maf_three/MF/V3/Tasks/NewScan.py | 2 +- maf_three/MF/V3/Tasks/SetCameras.py | 2 +- maf_three/MF/V3/Tasks/SetProject.py | 2 +- maf_three/MF/V3/Tasks/SystemInfo.py | 2 +- maf_three/MF/V3/Tasks/__init__.py | 88 ++--- maf_three/MF/V3/Three.py | 360 +++++++++--------- maf_three/MF/V3/__init__.py | 2 +- maf_three/__init__.py | 2 +- maf_three/examples/projector.py | 8 +- maf_three/scanner.py | 35 +- out/maf_three/MF/V3/Three.pyi | 77 ++++ scripts/transpileProto.py | 6 +- 30 files changed, 385 insertions(+), 321 deletions(-) create mode 100644 out/maf_three/MF/V3/Three.pyi diff --git a/maf_three/MF/V3/Buffer.py b/maf_three/MF/V3/Buffer.py index ae224b1..9927532 100644 --- a/maf_three/MF/V3/Buffer.py +++ b/maf_three/MF/V3/Buffer.py @@ -1,5 +1,5 @@ -from google.protobuf import any_pb2 as _any_pb2 from MF.V3.Task import Task as MF_V3_Task_Task +from google.protobuf import any_pb2 as _any_pb2 class Buffer: diff --git a/maf_three/MF/V3/Descriptors/Export.py b/maf_three/MF/V3/Descriptors/Export.py index 42edae9..5796427 100644 --- a/maf_three/MF/V3/Descriptors/Export.py +++ b/maf_three/MF/V3/Descriptors/Export.py @@ -1,5 +1,5 @@ -from enum import Enum from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export +from enum import Enum from typing import List diff --git a/maf_three/MF/V3/Descriptors/Settings/Scanner.py b/maf_three/MF/V3/Descriptors/Settings/Scanner.py index 1e987c6..faa0f0d 100644 --- a/maf_three/MF/V3/Descriptors/Settings/Scanner.py +++ b/maf_three/MF/V3/Descriptors/Settings/Scanner.py @@ -1,12 +1,12 @@ -from MF.V3.Descriptors.Settings.Style import Style as MF_V3_Descriptors_Settings_Style_Style -from MF.V3.Descriptors.Settings.Turntable import Turntable as MF_V3_Descriptors_Settings_Turntable_Turntable from MF.V3.Descriptors.Settings.Advanced import Advanced as MF_V3_Descriptors_Settings_Advanced_Advanced -from MF.V3.Descriptors.Settings.I18n import I18n as MF_V3_Descriptors_Settings_I18n_I18n -from MF.V3.Descriptors.Settings.Tutorials import Tutorials as MF_V3_Descriptors_Settings_Tutorials_Tutorials -from MF.V3.Descriptors.Settings.Capture import Capture as MF_V3_Descriptors_Settings_Capture_Capture from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera +from MF.V3.Descriptors.Settings.Capture import Capture as MF_V3_Descriptors_Settings_Capture_Capture +from MF.V3.Descriptors.Settings.I18n import I18n as MF_V3_Descriptors_Settings_I18n_I18n from MF.V3.Descriptors.Settings.Projector import Projector as MF_V3_Descriptors_Settings_Projector_Projector from MF.V3.Descriptors.Settings.Software import Software as MF_V3_Descriptors_Settings_Software_Software +from MF.V3.Descriptors.Settings.Style import Style as MF_V3_Descriptors_Settings_Style_Style +from MF.V3.Descriptors.Settings.Turntable import Turntable as MF_V3_Descriptors_Settings_Turntable_Turntable +from MF.V3.Descriptors.Settings.Tutorials import Tutorials as MF_V3_Descriptors_Settings_Tutorials_Tutorials from MF.V3.Descriptors.Settings.Viewer import Viewer as MF_V3_Descriptors_Settings_Viewer_Viewer diff --git a/maf_three/MF/V3/Descriptors/Settings/__init__.py b/maf_three/MF/V3/Descriptors/Settings/__init__.py index 50bc7c1..fceebd7 100644 --- a/maf_three/MF/V3/Descriptors/Settings/__init__.py +++ b/maf_three/MF/V3/Descriptors/Settings/__init__.py @@ -1,11 +1,11 @@ -from MF.V3.Descriptors.Settings.Software import * -from MF.V3.Descriptors.Settings.I18n import * -from MF.V3.Descriptors.Settings.Scanner import * -from MF.V3.Descriptors.Settings.Viewer import * from MF.V3.Descriptors.Settings.Style import * -from MF.V3.Descriptors.Settings.Tutorials import * -from MF.V3.Descriptors.Settings.Projector import * from MF.V3.Descriptors.Settings.Turntable import * +from MF.V3.Descriptors.Settings.Viewer import * +from MF.V3.Descriptors.Settings.Projector import * +from MF.V3.Descriptors.Settings.Tutorials import * +from MF.V3.Descriptors.Settings.I18n import * from MF.V3.Descriptors.Settings.Advanced import * -from MF.V3.Descriptors.Settings.Camera import * +from MF.V3.Descriptors.Settings.Scanner import * from MF.V3.Descriptors.Settings.Capture import * +from MF.V3.Descriptors.Settings.Camera import * +from MF.V3.Descriptors.Settings.Software import * diff --git a/maf_three/MF/V3/Descriptors/VideoFrame.py b/maf_three/MF/V3/Descriptors/VideoFrame.py index 2147fa3..286925c 100644 --- a/maf_three/MF/V3/Descriptors/VideoFrame.py +++ b/maf_three/MF/V3/Descriptors/VideoFrame.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video from MF.V3.Descriptors.Calibration import DetectedCard as MF_V3_Descriptors_Calibration_DetectedCard +from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video class VideoFrame: diff --git a/maf_three/MF/V3/Descriptors/__init__.py b/maf_three/MF/V3/Descriptors/__init__.py index 7e7658b..92fcd1e 100644 --- a/maf_three/MF/V3/Descriptors/__init__.py +++ b/maf_three/MF/V3/Descriptors/__init__.py @@ -1,12 +1,12 @@ -from MF.V3.Descriptors.ScanData import * -from MF.V3.Descriptors.ProjectActions import * -from MF.V3.Descriptors.Transform import * -from MF.V3.Descriptors.Wifi import * from MF.V3.Descriptors.BoundingBox import * -from MF.V3.Descriptors.Project import * -from MF.V3.Descriptors.VideoFrame import * -from MF.V3.Descriptors.RemoveVertices import * from MF.V3.Descriptors.Image import * from MF.V3.Descriptors.Export import * from MF.V3.Descriptors.Merge import * from MF.V3.Descriptors.System import * +from MF.V3.Descriptors.Project import * +from MF.V3.Descriptors.ProjectActions import * +from MF.V3.Descriptors.Transform import * +from MF.V3.Descriptors.VideoFrame import * +from MF.V3.Descriptors.Wifi import * +from MF.V3.Descriptors.ScanData import * +from MF.V3.Descriptors.RemoveVertices import * diff --git a/maf_three/MF/V3/Settings/Merge.py b/maf_three/MF/V3/Settings/Merge.py index 21807fb..1772137 100644 --- a/maf_three/MF/V3/Settings/Merge.py +++ b/maf_three/MF/V3/Settings/Merge.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality +from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection from enum import Enum diff --git a/maf_three/MF/V3/Settings/Projector.py b/maf_three/MF/V3/Settings/Projector.py index ecf88ae..c0592fa 100644 --- a/maf_three/MF/V3/Settings/Projector.py +++ b/maf_three/MF/V3/Settings/Projector.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video from MF.V3.Settings.Rectangle import Rectangle as MF_V3_Settings_Rectangle_Rectangle +from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video from enum import Enum from typing import List diff --git a/maf_three/MF/V3/Settings/Scan.py b/maf_three/MF/V3/Settings/Scan.py index a0c8adb..8b72fa0 100644 --- a/maf_three/MF/V3/Settings/Scan.py +++ b/maf_three/MF/V3/Settings/Scan.py @@ -1,8 +1,8 @@ -from enum import Enum +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable -from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera +from enum import Enum from typing import List diff --git a/maf_three/MF/V3/Settings/Scanner.py b/maf_three/MF/V3/Settings/Scanner.py index f21e0ca..b6d4a73 100644 --- a/maf_three/MF/V3/Settings/Scanner.py +++ b/maf_three/MF/V3/Settings/Scanner.py @@ -1,13 +1,13 @@ -from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials -from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n -from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer +from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture +from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector -from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software +from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable -from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera -from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced +from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials +from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer class Scanner: diff --git a/maf_three/MF/V3/Settings/__init__.py b/maf_three/MF/V3/Settings/__init__.py index c49d345..2ec545c 100644 --- a/maf_three/MF/V3/Settings/__init__.py +++ b/maf_three/MF/V3/Settings/__init__.py @@ -1,29 +1,29 @@ +from MF.V3.Settings.ScanData import * +from MF.V3.Settings.Capture import * +from MF.V3.Settings.I18n import * +from MF.V3.Settings.Style import * +from MF.V3.Settings.Remesh import * from MF.V3.Settings.Turntable import * -from MF.V3.Settings.AutoFocus import * +from MF.V3.Settings.Camera import * +from MF.V3.Settings.Group import * +from MF.V3.Settings.BoundingBox import * +from MF.V3.Settings.Scan import * +from MF.V3.Settings.Viewer import * +from MF.V3.Settings.Tutorials import * from MF.V3.Settings.NewGroup import * -from MF.V3.Settings.Scanner import * +from MF.V3.Settings.Rectangle import * +from MF.V3.Settings.AutoFocus import * +from MF.V3.Settings.Export import * +from MF.V3.Settings.Project import * from MF.V3.Settings.RemoveVertices import * +from MF.V3.Settings.Advanced import * from MF.V3.Settings.Wifi import * -from MF.V3.Settings.I18n import * from MF.V3.Settings.Video import * -from MF.V3.Settings.ScanSelection import * -from MF.V3.Settings.Remesh import * -from MF.V3.Settings.Rectangle import * -from MF.V3.Settings.Viewer import * -from MF.V3.Settings.Quality import * -from MF.V3.Settings.Export import * -from MF.V3.Settings.Style import * from MF.V3.Settings.Software import * -from MF.V3.Settings.Capture import * -from MF.V3.Settings.Tutorials import * -from MF.V3.Settings.BoundingBox import * -from MF.V3.Settings.Merge import * from MF.V3.Settings.Align import * -from MF.V3.Settings.Camera import * -from MF.V3.Settings.Upgrade import * +from MF.V3.Settings.Quality import * +from MF.V3.Settings.ScanSelection import * +from MF.V3.Settings.Scanner import * from MF.V3.Settings.Projector import * -from MF.V3.Settings.Project import * -from MF.V3.Settings.ScanData import * -from MF.V3.Settings.Group import * -from MF.V3.Settings.Advanced import * -from MF.V3.Settings.Scan import * +from MF.V3.Settings.Merge import * +from MF.V3.Settings.Upgrade import * diff --git a/maf_three/MF/V3/Tasks/Align.py b/maf_three/MF/V3/Tasks/Align.py index 64c10f6..ba8fe37 100644 --- a/maf_three/MF/V3/Tasks/Align.py +++ b/maf_three/MF/V3/Tasks/Align.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align from MF.V3.Descriptors.Transform import Transform as MF_V3_Descriptors_Transform_Transform +from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align from MF.V3.Task import TaskState as MF_V3_Task_TaskState diff --git a/maf_three/MF/V3/Tasks/AutoFocus.py b/maf_three/MF/V3/Tasks/AutoFocus.py index 899ce35..d21722d 100644 --- a/maf_three/MF/V3/Tasks/AutoFocus.py +++ b/maf_three/MF/V3/Tasks/AutoFocus.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera +from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus from MF.V3.Task import TaskState as MF_V3_Task_TaskState diff --git a/maf_three/MF/V3/Tasks/BoundingBox.py b/maf_three/MF/V3/Tasks/BoundingBox.py index bdff7bc..4a92fd2 100644 --- a/maf_three/MF/V3/Tasks/BoundingBox.py +++ b/maf_three/MF/V3/Tasks/BoundingBox.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.BoundingBox import BoundingBox as MF_V3_Settings_BoundingBox_BoundingBox from MF.V3.Descriptors.BoundingBox import BoundingBox as MF_V3_Descriptors_BoundingBox_BoundingBox +from MF.V3.Settings.BoundingBox import BoundingBox as MF_V3_Settings_BoundingBox_BoundingBox from MF.V3.Task import TaskState as MF_V3_Task_TaskState diff --git a/maf_three/MF/V3/Tasks/DepthMap.py b/maf_three/MF/V3/Tasks/DepthMap.py index d8da23d..47c3cfd 100644 --- a/maf_three/MF/V3/Tasks/DepthMap.py +++ b/maf_three/MF/V3/Tasks/DepthMap.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan from MF.V3.Descriptors.Image import Image as MF_V3_Descriptors_Image_Image +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task from typing import List diff --git a/maf_three/MF/V3/Tasks/Merge.py b/maf_three/MF/V3/Tasks/Merge.py index 0b6af3e..70ab574 100644 --- a/maf_three/MF/V3/Tasks/Merge.py +++ b/maf_three/MF/V3/Tasks/Merge.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge from MF.V3.Descriptors.Merge import Merge as MF_V3_Descriptors_Merge_Merge +from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge from MF.V3.Task import TaskState as MF_V3_Task_TaskState diff --git a/maf_three/MF/V3/Tasks/NewGroup.py b/maf_three/MF/V3/Tasks/NewGroup.py index dad64aa..93db660 100644 --- a/maf_three/MF/V3/Tasks/NewGroup.py +++ b/maf_three/MF/V3/Tasks/NewGroup.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.NewGroup import NewGroup as MF_V3_Settings_NewGroup_NewGroup from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.NewGroup import NewGroup as MF_V3_Settings_NewGroup_NewGroup from MF.V3.Task import TaskState as MF_V3_Task_TaskState diff --git a/maf_three/MF/V3/Tasks/NewProject.py b/maf_three/MF/V3/Tasks/NewProject.py index 0feef65..28ebce7 100644 --- a/maf_three/MF/V3/Tasks/NewProject.py +++ b/maf_three/MF/V3/Tasks/NewProject.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project from MF.V3.Task import TaskState as MF_V3_Task_TaskState diff --git a/maf_three/MF/V3/Tasks/NewScan.py b/maf_three/MF/V3/Tasks/NewScan.py index 5e412b9..2107534 100644 --- a/maf_three/MF/V3/Tasks/NewScan.py +++ b/maf_three/MF/V3/Tasks/NewScan.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan from MF.V3.Task import TaskState as MF_V3_Task_TaskState diff --git a/maf_three/MF/V3/Tasks/SetCameras.py b/maf_three/MF/V3/Tasks/SetCameras.py index 5de94b6..188e93c 100644 --- a/maf_three/MF/V3/Tasks/SetCameras.py +++ b/maf_three/MF/V3/Tasks/SetCameras.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera from MF.V3.Task import TaskState as MF_V3_Task_TaskState diff --git a/maf_three/MF/V3/Tasks/SetProject.py b/maf_three/MF/V3/Tasks/SetProject.py index 147e781..c2d785f 100644 --- a/maf_three/MF/V3/Tasks/SetProject.py +++ b/maf_three/MF/V3/Tasks/SetProject.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project from MF.V3.Task import TaskState as MF_V3_Task_TaskState diff --git a/maf_three/MF/V3/Tasks/SystemInfo.py b/maf_three/MF/V3/Tasks/SystemInfo.py index 15338ba..59d8d4e 100644 --- a/maf_three/MF/V3/Tasks/SystemInfo.py +++ b/maf_three/MF/V3/Tasks/SystemInfo.py @@ -1,5 +1,5 @@ -from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software from MF.V3.Descriptors.System import System as MF_V3_Descriptors_System_System +from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software from MF.V3.Task import TaskState as MF_V3_Task_TaskState diff --git a/maf_three/MF/V3/Tasks/__init__.py b/maf_three/MF/V3/Tasks/__init__.py index 87ea1f4..8d8a903 100644 --- a/maf_three/MF/V3/Tasks/__init__.py +++ b/maf_three/MF/V3/Tasks/__init__.py @@ -1,56 +1,56 @@ -from MF.V3.Tasks.StartVideo import * +from MF.V3.Tasks.DownloadProject import * +from MF.V3.Tasks.ConnectWifi import * from MF.V3.Tasks.CloseProject import * -from MF.V3.Tasks.UploadProject import * -from MF.V3.Tasks.ExportMerge import * -from MF.V3.Tasks.ListGroups import * -from MF.V3.Tasks.MoveGroup import * +from MF.V3.Tasks.FlattenGroup import * +from MF.V3.Tasks.CalibrateCameras import * +from MF.V3.Tasks.MergeData import * from MF.V3.Tasks.AddMergeToProject import * -from MF.V3.Tasks.Shutdown import * -from MF.V3.Tasks.SetGroup import * -from MF.V3.Tasks.ScanData import * +from MF.V3.Tasks.PushSettings import * +from MF.V3.Tasks.RestoreFactoryCalibration import * +from MF.V3.Tasks.PopSettings import * +from MF.V3.Tasks.RemoveGroups import * +from MF.V3.Tasks.OpenProject import * from MF.V3.Tasks.Merge import * -from MF.V3.Tasks.SetProject import * -from MF.V3.Tasks.CalibrateCameras import * -from MF.V3.Tasks.CameraCalibration import * -from MF.V3.Tasks.ListExportFormats import * -from MF.V3.Tasks.TransformGroup import * +from MF.V3.Tasks.SetGroup import * +from MF.V3.Tasks.Reboot import * +from MF.V3.Tasks.ListSettings import * from MF.V3.Tasks.ExportLogs import * -from MF.V3.Tasks.NewScan import * -from MF.V3.Tasks.DetectCalibrationCard import * -from MF.V3.Tasks.CalibrationCaptureTargets import * -from MF.V3.Tasks.AutoFocus import * -from MF.V3.Tasks.FlattenGroup import * -from MF.V3.Tasks.ListWifi import * from MF.V3.Tasks.RemoveProjects import * -from MF.V3.Tasks.SetCameras import * -from MF.V3.Tasks.NewProject import * +from MF.V3.Tasks.TransformGroup import * +from MF.V3.Tasks.ForgetWifi import * +from MF.V3.Tasks.MoveGroup import * +from MF.V3.Tasks.ListExportFormats import * +from MF.V3.Tasks.Align import * from MF.V3.Tasks.SplitGroup import * -from MF.V3.Tasks.Reboot import * -from MF.V3.Tasks.DepthMap import * -from MF.V3.Tasks.RotateTurntable import * -from MF.V3.Tasks.RestoreFactoryCalibration import * +from MF.V3.Tasks.ListProjects import * +from MF.V3.Tasks.CameraCalibration import * +from MF.V3.Tasks.ListGroups import * +from MF.V3.Tasks.CalibrationCaptureTargets import * +from MF.V3.Tasks.NewScan import * from MF.V3.Tasks.ListNetworkInterfaces import * -from MF.V3.Tasks.SystemInfo import * -from MF.V3.Tasks.ListSettings import * from MF.V3.Tasks.HasProjector import * -from MF.V3.Tasks.ListProjects import * -from MF.V3.Tasks.ListScans import * -from MF.V3.Tasks.DownloadProject import * -from MF.V3.Tasks.Align import * -from MF.V3.Tasks.ConnectWifi import * -from MF.V3.Tasks.SetProjector import * -from MF.V3.Tasks.UpdateSettings import * from MF.V3.Tasks.Export import * -from MF.V3.Tasks.NewGroup import * -from MF.V3.Tasks.TurntableCalibration import * -from MF.V3.Tasks.OpenProject import * -from MF.V3.Tasks.CalibrateTurntable import * -from MF.V3.Tasks.HasTurntable import * from MF.V3.Tasks.BoundingBox import * -from MF.V3.Tasks.PopSettings import * +from MF.V3.Tasks.DepthMap import * +from MF.V3.Tasks.SetCameras import * +from MF.V3.Tasks.DetectCalibrationCard import * +from MF.V3.Tasks.SetProjector import * from MF.V3.Tasks.StopVideo import * -from MF.V3.Tasks.RemoveGroups import * -from MF.V3.Tasks.PushSettings import * +from MF.V3.Tasks.StartVideo import * +from MF.V3.Tasks.HasTurntable import * +from MF.V3.Tasks.SystemInfo import * +from MF.V3.Tasks.RotateTurntable import * +from MF.V3.Tasks.ScanData import * +from MF.V3.Tasks.Shutdown import * +from MF.V3.Tasks.CalibrateTurntable import * +from MF.V3.Tasks.UpdateSettings import * from MF.V3.Tasks.HasCameras import * -from MF.V3.Tasks.ForgetWifi import * -from MF.V3.Tasks.MergeData import * +from MF.V3.Tasks.SetProject import * +from MF.V3.Tasks.ExportMerge import * +from MF.V3.Tasks.TurntableCalibration import * +from MF.V3.Tasks.NewProject import * +from MF.V3.Tasks.ListScans import * +from MF.V3.Tasks.UploadProject import * +from MF.V3.Tasks.ListWifi import * +from MF.V3.Tasks.NewGroup import * +from MF.V3.Tasks.AutoFocus import * diff --git a/maf_three/MF/V3/Three.py b/maf_three/MF/V3/Three.py index 989acd7..be7396e 100644 --- a/maf_three/MF/V3/Three.py +++ b/maf_three/MF/V3/Three.py @@ -1,83 +1,83 @@ -from MF.V3.Tasks.NewProject import NewProject as MF_V3_Tasks_NewProject -from MF.V3.Tasks.Reboot import Reboot as MF_V3_Tasks_Reboot -from MF.V3.Tasks.SetGroup import SetGroup as MF_V3_Tasks_SetGroup -from MF.V3.Tasks.RemoveProjects import RemoveProjects as MF_V3_Tasks_RemoveProjects -from MF.V3.Tasks.RemoveGroups import RemoveGroups as MF_V3_Tasks_RemoveGroups -from MF.V3.Tasks.CalibrationCaptureTargets import CalibrationCaptureTargets as MF_V3_Tasks_CalibrationCaptureTargets -from MF.V3.Tasks.Shutdown import Shutdown as MF_V3_Tasks_Shutdown -from MF.V3.Tasks.NewScan import NewScan as MF_V3_Tasks_NewScan -from MF.V3.Tasks.ExportMerge import ExportMerge as MF_V3_Tasks_ExportMerge -from MF.V3.Tasks.UpdateSettings import UpdateSettings as MF_V3_Tasks_UpdateSettings -from MF.V3.Tasks.CameraCalibration import CameraCalibration as MF_V3_Tasks_CameraCalibration -from MF.V3.Tasks.StopVideo import StopVideo as MF_V3_Tasks_StopVideo +from MF.V3 import Task +from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced +from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align +from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus +from MF.V3.Settings.BoundingBox import BoundingBox as MF_V3_Settings_BoundingBox_BoundingBox +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera +from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture +from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export +from MF.V3.Settings.Group import Group as MF_V3_Settings_Group_Group +from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n +from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge +from MF.V3.Settings.NewGroup import NewGroup as MF_V3_Settings_NewGroup_NewGroup +from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project +from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData +from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection +from MF.V3.Settings.Scanner import Scanner as MF_V3_Settings_Scanner_Scanner +from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software +from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style +from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable +from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials +from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer +from MF.V3.Settings.Wifi import Wifi as MF_V3_Settings_Wifi_Wifi from MF.V3.Tasks.AddMergeToProject import AddMergeToProject as MF_V3_Tasks_AddMergeToProject -from MF.V3.Tasks.NewGroup import NewGroup as MF_V3_Tasks_NewGroup from MF.V3.Tasks.Align import Align as MF_V3_Tasks_Align +from MF.V3.Tasks.AutoFocus import AutoFocus as MF_V3_Tasks_AutoFocus +from MF.V3.Tasks.BoundingBox import BoundingBox as MF_V3_Tasks_BoundingBox +from MF.V3.Tasks.CalibrateCameras import CalibrateCameras as MF_V3_Tasks_CalibrateCameras from MF.V3.Tasks.CalibrateTurntable import CalibrateTurntable as MF_V3_Tasks_CalibrateTurntable +from MF.V3.Tasks.CalibrationCaptureTargets import CalibrationCaptureTargets as MF_V3_Tasks_CalibrationCaptureTargets +from MF.V3.Tasks.CameraCalibration import CameraCalibration as MF_V3_Tasks_CameraCalibration +from MF.V3.Tasks.CloseProject import CloseProject as MF_V3_Tasks_CloseProject +from MF.V3.Tasks.ConnectWifi import ConnectWifi as MF_V3_Tasks_ConnectWifi +from MF.V3.Tasks.DepthMap import DepthMap as MF_V3_Tasks_DepthMap from MF.V3.Tasks.DetectCalibrationCard import DetectCalibrationCard as MF_V3_Tasks_DetectCalibrationCard -from MF.V3.Tasks.OpenProject import OpenProject as MF_V3_Tasks_OpenProject -from MF.V3.Tasks.PushSettings import PushSettings as MF_V3_Tasks_PushSettings -from MF.V3.Tasks.SplitGroup import SplitGroup as MF_V3_Tasks_SplitGroup -from MF.V3.Tasks.UploadProject import UploadProject as MF_V3_Tasks_UploadProject -from MF.V3.Tasks.RotateTurntable import RotateTurntable as MF_V3_Tasks_RotateTurntable -from MF.V3.Tasks.ListExportFormats import ListExportFormats as MF_V3_Tasks_ListExportFormats -from MF.V3.Tasks.ListWifi import ListWifi as MF_V3_Tasks_ListWifi +from MF.V3.Tasks.DownloadProject import DownloadProject as MF_V3_Tasks_DownloadProject +from MF.V3.Tasks.Export import Export as MF_V3_Tasks_Export from MF.V3.Tasks.ExportLogs import ExportLogs as MF_V3_Tasks_ExportLogs +from MF.V3.Tasks.ExportMerge import ExportMerge as MF_V3_Tasks_ExportMerge from MF.V3.Tasks.FlattenGroup import FlattenGroup as MF_V3_Tasks_FlattenGroup -from MF.V3.Tasks.MergeData import MergeData as MF_V3_Tasks_MergeData -from MF.V3.Tasks.StartVideo import StartVideo as MF_V3_Tasks_StartVideo -from MF.V3.Tasks.ConnectWifi import ConnectWifi as MF_V3_Tasks_ConnectWifi -from MF.V3.Tasks.BoundingBox import BoundingBox as MF_V3_Tasks_BoundingBox -from MF.V3.Tasks.ListNetworkInterfaces import ListNetworkInterfaces as MF_V3_Tasks_ListNetworkInterfaces -from MF.V3.Tasks.ListProjects import ListProjects as MF_V3_Tasks_ListProjects -from MF.V3.Tasks.AutoFocus import AutoFocus as MF_V3_Tasks_AutoFocus -from MF.V3.Tasks.CalibrateCameras import CalibrateCameras as MF_V3_Tasks_CalibrateCameras -from MF.V3.Tasks.SetProject import SetProject as MF_V3_Tasks_SetProject -from MF.V3.Tasks.DepthMap import DepthMap as MF_V3_Tasks_DepthMap -from MF.V3.Tasks.PopSettings import PopSettings as MF_V3_Tasks_PopSettings -from MF.V3.Tasks.SetProjector import SetProjector as MF_V3_Tasks_SetProjector +from MF.V3.Tasks.ForgetWifi import ForgetWifi as MF_V3_Tasks_ForgetWifi +from MF.V3.Tasks.HasCameras import HasCameras as MF_V3_Tasks_HasCameras from MF.V3.Tasks.HasProjector import HasProjector as MF_V3_Tasks_HasProjector -from MF.V3.Tasks.Export import Export as MF_V3_Tasks_Export +from MF.V3.Tasks.HasTurntable import HasTurntable as MF_V3_Tasks_HasTurntable +from MF.V3.Tasks.ListExportFormats import ListExportFormats as MF_V3_Tasks_ListExportFormats from MF.V3.Tasks.ListGroups import ListGroups as MF_V3_Tasks_ListGroups -from MF.V3.Tasks.DownloadProject import DownloadProject as MF_V3_Tasks_DownloadProject -from MF.V3.Tasks.SystemInfo import SystemInfo as MF_V3_Tasks_SystemInfo -from MF.V3.Tasks.MoveGroup import MoveGroup as MF_V3_Tasks_MoveGroup -from MF.V3.Tasks.HasCameras import HasCameras as MF_V3_Tasks_HasCameras -from MF.V3.Tasks.TurntableCalibration import TurntableCalibration as MF_V3_Tasks_TurntableCalibration +from MF.V3.Tasks.ListNetworkInterfaces import ListNetworkInterfaces as MF_V3_Tasks_ListNetworkInterfaces +from MF.V3.Tasks.ListProjects import ListProjects as MF_V3_Tasks_ListProjects +from MF.V3.Tasks.ListScans import ListScans as MF_V3_Tasks_ListScans from MF.V3.Tasks.ListSettings import ListSettings as MF_V3_Tasks_ListSettings -from MF.V3.Tasks.CloseProject import CloseProject as MF_V3_Tasks_CloseProject -from MF.V3.Tasks.TransformGroup import TransformGroup as MF_V3_Tasks_TransformGroup +from MF.V3.Tasks.ListWifi import ListWifi as MF_V3_Tasks_ListWifi +from MF.V3.Tasks.Merge import Merge as MF_V3_Tasks_Merge +from MF.V3.Tasks.MergeData import MergeData as MF_V3_Tasks_MergeData +from MF.V3.Tasks.MoveGroup import MoveGroup as MF_V3_Tasks_MoveGroup +from MF.V3.Tasks.NewGroup import NewGroup as MF_V3_Tasks_NewGroup +from MF.V3.Tasks.NewProject import NewProject as MF_V3_Tasks_NewProject +from MF.V3.Tasks.NewScan import NewScan as MF_V3_Tasks_NewScan +from MF.V3.Tasks.OpenProject import OpenProject as MF_V3_Tasks_OpenProject +from MF.V3.Tasks.PopSettings import PopSettings as MF_V3_Tasks_PopSettings +from MF.V3.Tasks.PushSettings import PushSettings as MF_V3_Tasks_PushSettings +from MF.V3.Tasks.Reboot import Reboot as MF_V3_Tasks_Reboot +from MF.V3.Tasks.RemoveGroups import RemoveGroups as MF_V3_Tasks_RemoveGroups +from MF.V3.Tasks.RemoveProjects import RemoveProjects as MF_V3_Tasks_RemoveProjects from MF.V3.Tasks.RestoreFactoryCalibration import RestoreFactoryCalibration as MF_V3_Tasks_RestoreFactoryCalibration +from MF.V3.Tasks.RotateTurntable import RotateTurntable as MF_V3_Tasks_RotateTurntable from MF.V3.Tasks.ScanData import ScanData as MF_V3_Tasks_ScanData -from MF.V3.Tasks.Merge import Merge as MF_V3_Tasks_Merge -from MF.V3.Tasks.HasTurntable import HasTurntable as MF_V3_Tasks_HasTurntable from MF.V3.Tasks.SetCameras import SetCameras as MF_V3_Tasks_SetCameras -from MF.V3.Tasks.ForgetWifi import ForgetWifi as MF_V3_Tasks_ForgetWifi -from MF.V3.Tasks.ListScans import ListScans as MF_V3_Tasks_ListScans -from MF.V3 import Task -from MF.V3.Settings.Wifi import Wifi as MF_V3_Settings_Wifi_Wifi -from MF.V3.Settings.Scanner import Scanner as MF_V3_Settings_Scanner_Scanner -from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced -from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera -from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture -from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n -from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector -from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style -from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable -from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials -from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer -from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software -from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData -from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project -from MF.V3.Settings.Group import Group as MF_V3_Settings_Group_Group -from MF.V3.Settings.NewGroup import NewGroup as MF_V3_Settings_NewGroup_NewGroup -from MF.V3.Settings.BoundingBox import BoundingBox as MF_V3_Settings_BoundingBox_BoundingBox -from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection -from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align -from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge -from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export -from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus -from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from MF.V3.Tasks.SetGroup import SetGroup as MF_V3_Tasks_SetGroup +from MF.V3.Tasks.SetProject import SetProject as MF_V3_Tasks_SetProject +from MF.V3.Tasks.SetProjector import SetProjector as MF_V3_Tasks_SetProjector +from MF.V3.Tasks.Shutdown import Shutdown as MF_V3_Tasks_Shutdown +from MF.V3.Tasks.SplitGroup import SplitGroup as MF_V3_Tasks_SplitGroup +from MF.V3.Tasks.StartVideo import StartVideo as MF_V3_Tasks_StartVideo +from MF.V3.Tasks.StopVideo import StopVideo as MF_V3_Tasks_StopVideo +from MF.V3.Tasks.SystemInfo import SystemInfo as MF_V3_Tasks_SystemInfo +from MF.V3.Tasks.TransformGroup import TransformGroup as MF_V3_Tasks_TransformGroup +from MF.V3.Tasks.TurntableCalibration import TurntableCalibration as MF_V3_Tasks_TurntableCalibration +from MF.V3.Tasks.UpdateSettings import UpdateSettings as MF_V3_Tasks_UpdateSettings +from MF.V3.Tasks.UploadProject import UploadProject as MF_V3_Tasks_UploadProject class Three: @@ -85,7 +85,7 @@ class Three: def __init__(self): pass - def list_network_interfaces(scanner) -> Task: + def list_network_interfaces(self) -> Task: # List available wifi networks. list_network_interfaces_request = MF_V3_Tasks_ListNetworkInterfaces.Request( Index=0, @@ -96,10 +96,10 @@ def list_network_interfaces(scanner) -> Task: Type="ListNetworkInterfaces" ) task = Task(Index=0, Type="ListNetworkInterfaces", Input=list_network_interfaces_request, Output=list_network_interfaces_response) - scanner.SendTask(task) + self.SendTask(task) return task - def list_wifi(scanner) -> Task: + def list_wifi(self) -> Task: # List available wifi networks. list_wifi_request = MF_V3_Tasks_ListWifi.Request( Index=0, @@ -110,10 +110,10 @@ def list_wifi(scanner) -> Task: Type="ListWifi" ) task = Task(Index=0, Type="ListWifi", Input=list_wifi_request, Output=list_wifi_response) - scanner.SendTask(task) + self.SendTask(task) return task - def connect_wifi(scanner, ssid: str, password: str) -> Task: + def connect_wifi(self, ssid: str, password: str) -> Task: # Connect to a wifi network. connect_wifi_request = MF_V3_Tasks_ConnectWifi.Request( Index=0, @@ -132,10 +132,10 @@ def connect_wifi(scanner, ssid: str, password: str) -> Task: ) ) task = Task(Index=0, Type="ConnectWifi", Input=connect_wifi_request, Output=connect_wifi_response) - scanner.SendTask(task) + self.SendTask(task) return task - def forget_wifi(scanner) -> Task: + def forget_wifi(self) -> Task: # Forget all wifi connections. forget_wifi_request = MF_V3_Tasks_ForgetWifi.Request( Index=0, @@ -146,10 +146,10 @@ def forget_wifi(scanner) -> Task: Type="ForgetWifi" ) task = Task(Index=0, Type="ForgetWifi", Input=forget_wifi_request, Output=forget_wifi_response) - scanner.SendTask(task) + self.SendTask(task) return task - def list_settings(scanner) -> Task: + def list_settings(self) -> Task: # Get scanner settings. list_settings_request = MF_V3_Tasks_ListSettings.Request( Index=0, @@ -160,10 +160,10 @@ def list_settings(scanner) -> Task: Type="ListSettings" ) task = Task(Index=0, Type="ListSettings", Input=list_settings_request, Output=list_settings_response) - scanner.SendTask(task) + self.SendTask(task) return task - def push_settings(scanner) -> Task: + def push_settings(self) -> Task: # Push the current scanner settings to the settings stack. push_settings_request = MF_V3_Tasks_PushSettings.Request( Index=0, @@ -174,10 +174,10 @@ def push_settings(scanner) -> Task: Type="PushSettings" ) task = Task(Index=0, Type="PushSettings", Input=push_settings_request, Output=push_settings_response) - scanner.SendTask(task) + self.SendTask(task) return task - def pop_settings(scanner, Input: bool = None) -> Task: + def pop_settings(self, Input: bool = None) -> Task: # Pop and restore scanner settings from the settings stack. pop_settings_request = MF_V3_Tasks_PopSettings.Request( Index=0, @@ -189,10 +189,10 @@ def pop_settings(scanner, Input: bool = None) -> Task: Type="PopSettings" ) task = Task(Index=0, Type="PopSettings", Input=pop_settings_request, Output=pop_settings_response) - scanner.SendTask(task) + self.SendTask(task) return task - def update_settings(scanner, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None) -> Task: + def update_settings(self, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None) -> Task: # Update scanner settings. update_settings_request = MF_V3_Tasks_UpdateSettings.Request( Index=0, @@ -227,10 +227,10 @@ def update_settings(scanner, advanced: MF_V3_Settings_Advanced_Advanced = None, ) ) task = Task(Index=0, Type="UpdateSettings", Input=update_settings_request, Output=update_settings_response) - scanner.SendTask(task) + self.SendTask(task) return task - def list_projects(scanner) -> Task: + def list_projects(self) -> Task: # List all projects. list_projects_request = MF_V3_Tasks_ListProjects.Request( Index=0, @@ -241,10 +241,10 @@ def list_projects(scanner) -> Task: Type="ListProjects" ) task = Task(Index=0, Type="ListProjects", Input=list_projects_request, Output=list_projects_response) - scanner.SendTask(task) + self.SendTask(task) return task - def download_project(scanner, Input: int) -> Task: + def download_project(self, Input: int) -> Task: # Download a project from the scanner. download_project_request = MF_V3_Tasks_DownloadProject.Request( Index=0, @@ -257,10 +257,10 @@ def download_project(scanner, Input: int) -> Task: Input=Input ) task = Task(Index=0, Type="DownloadProject", Input=download_project_request, Output=download_project_response) - scanner.SendTask(task) + self.SendTask(task) return task - def upload_project(scanner) -> Task: + def upload_project(self) -> Task: # Upload a project to the scanner. upload_project_request = MF_V3_Tasks_UploadProject.Request( Index=0, @@ -271,10 +271,10 @@ def upload_project(scanner) -> Task: Type="UploadProject" ) task = Task(Index=0, Type="UploadProject", Input=upload_project_request, Output=upload_project_response) - scanner.SendTask(task) + self.SendTask(task) return task - def new_project(scanner, Input: str = None) -> Task: + def new_project(self, Input: str = None) -> Task: # Create a new project. new_project_request = MF_V3_Tasks_NewProject.Request( Index=0, @@ -286,10 +286,10 @@ def new_project(scanner, Input: str = None) -> Task: Type="NewProject" ) task = Task(Index=0, Type="NewProject", Input=new_project_request, Output=new_project_response) - scanner.SendTask(task) + self.SendTask(task) return task - def open_project(scanner, Input: int) -> Task: + def open_project(self, Input: int) -> Task: # Open an existing project. open_project_request = MF_V3_Tasks_OpenProject.Request( Index=0, @@ -302,10 +302,10 @@ def open_project(scanner, Input: int) -> Task: Input=Input ) task = Task(Index=0, Type="OpenProject", Input=open_project_request, Output=open_project_response) - scanner.SendTask(task) + self.SendTask(task) return task - def close_project(scanner) -> Task: + def close_project(self) -> Task: # Close the current open project. close_project_request = MF_V3_Tasks_CloseProject.Request( Index=0, @@ -316,10 +316,10 @@ def close_project(scanner) -> Task: Type="CloseProject" ) task = Task(Index=0, Type="CloseProject", Input=close_project_request, Output=close_project_response) - scanner.SendTask(task) + self.SendTask(task) return task - def remove_projects(scanner, Input: int) -> Task: + def remove_projects(self, Input: int) -> Task: # Remove selected projects. remove_projects_request = MF_V3_Tasks_RemoveProjects.Request( Index=0, @@ -332,10 +332,10 @@ def remove_projects(scanner, Input: int) -> Task: Input=Input ) task = Task(Index=0, Type="RemoveProjects", Input=remove_projects_request, Output=remove_projects_response) - scanner.SendTask(task) + self.SendTask(task) return task - def list_groups(scanner) -> Task: + def list_groups(self) -> Task: # List the scan groups in the current open project. list_groups_request = MF_V3_Tasks_ListGroups.Request( Index=0, @@ -347,10 +347,10 @@ def list_groups(scanner) -> Task: Output=None ) task = Task(Index=0, Type="ListGroups", Input=list_groups_request, Output=list_groups_response) - scanner.SendTask(task) + self.SendTask(task) return task - def list_scans(scanner) -> Task: + def list_scans(self) -> Task: # List the scans in the current open project. list_scans_request = MF_V3_Tasks_ListScans.Request( Index=0, @@ -362,10 +362,10 @@ def list_scans(scanner) -> Task: Output=None ) task = Task(Index=0, Type="ListScans", Input=list_scans_request, Output=list_scans_response) - scanner.SendTask(task) + self.SendTask(task) return task - def scan_data(scanner, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: + def scan_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: # Download the raw scan data for a scan in the current open project. scan_data_request = MF_V3_Tasks_ScanData.Request( Index=0, @@ -389,10 +389,10 @@ def scan_data(scanner, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buf Output=None ) task = Task(Index=0, Type="ScanData", Input=scan_data_request, Output=scan_data_response) - scanner.SendTask(task) + self.SendTask(task) return task - def set_project(scanner, index: int = None, name: str = None) -> Task: + def set_project(self, index: int = None, name: str = None) -> Task: # Apply settings to the current open project. set_project_request = MF_V3_Tasks_SetProject.Request( Index=0, @@ -407,10 +407,10 @@ def set_project(scanner, index: int = None, name: str = None) -> Task: Type="SetProject" ) task = Task(Index=0, Type="SetProject", Input=set_project_request, Output=set_project_response) - scanner.SendTask(task) + self.SendTask(task) return task - def set_group(scanner, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: + def set_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: # Set scan group properties. set_group_request = MF_V3_Tasks_SetGroup.Request( Index=0, @@ -440,10 +440,10 @@ def set_group(scanner, index: int, color: float, rotation: float, translation: f Output=None ) task = Task(Index=0, Type="SetGroup", Input=set_group_request, Output=set_group_response) - scanner.SendTask(task) + self.SendTask(task) return task - def new_group(scanner, color: float, rotation: float, translation: float, parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None) -> Task: + def new_group(self, color: float, rotation: float, translation: float, parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None) -> Task: # Create a new scan group. new_group_request = MF_V3_Tasks_NewGroup.Request( Index=0, @@ -464,10 +464,10 @@ def new_group(scanner, color: float, rotation: float, translation: float, parent Output=None ) task = Task(Index=0, Type="NewGroup", Input=new_group_request, Output=new_group_response) - scanner.SendTask(task) + self.SendTask(task) return task - def move_group(scanner, Input: int) -> Task: + def move_group(self, Input: int) -> Task: # Move a scan group. move_group_request = MF_V3_Tasks_MoveGroup.Request( Index=0, @@ -481,10 +481,10 @@ def move_group(scanner, Input: int) -> Task: Output=None ) task = Task(Index=0, Type="MoveGroup", Input=move_group_request, Output=move_group_response) - scanner.SendTask(task) + self.SendTask(task) return task - def flatten_group(scanner, Input: int) -> Task: + def flatten_group(self, Input: int) -> Task: # Flatten a scan group such that it only consists of single scans. flatten_group_request = MF_V3_Tasks_FlattenGroup.Request( Index=0, @@ -498,10 +498,10 @@ def flatten_group(scanner, Input: int) -> Task: Output=None ) task = Task(Index=0, Type="FlattenGroup", Input=flatten_group_request, Output=flatten_group_response) - scanner.SendTask(task) + self.SendTask(task) return task - def split_group(scanner, Input: int) -> Task: + def split_group(self, Input: int) -> Task: # Split a scan group (ie. move its subgroups to its parent group). split_group_request = MF_V3_Tasks_SplitGroup.Request( Index=0, @@ -515,10 +515,10 @@ def split_group(scanner, Input: int) -> Task: Output=None ) task = Task(Index=0, Type="SplitGroup", Input=split_group_request, Output=split_group_response) - scanner.SendTask(task) + self.SendTask(task) return task - def transform_group(scanner, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: + def transform_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: # Apply a rigid transformation to a group. transform_group_request = MF_V3_Tasks_TransformGroup.Request( Index=0, @@ -548,10 +548,10 @@ def transform_group(scanner, index: int, color: float, rotation: float, translat Output=None ) task = Task(Index=0, Type="TransformGroup", Input=transform_group_request, Output=transform_group_response) - scanner.SendTask(task) + self.SendTask(task) return task - def remove_groups(scanner, Input: int) -> Task: + def remove_groups(self, Input: int) -> Task: # Remove selected scan groups. remove_groups_request = MF_V3_Tasks_RemoveGroups.Request( Index=0, @@ -565,10 +565,10 @@ def remove_groups(scanner, Input: int) -> Task: Output=None ) task = Task(Index=0, Type="RemoveGroups", Input=remove_groups_request, Output=remove_groups_response) - scanner.SendTask(task) + self.SendTask(task) return task - def bounding_box(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool) -> Task: + def bounding_box(self, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool) -> Task: # Get the bounding box of a set of scan groups. bounding_box_request = MF_V3_Tasks_BoundingBox.Request( Index=0, @@ -588,10 +588,10 @@ def bounding_box(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection, Output=None ) task = Task(Index=0, Type="BoundingBox", Input=bounding_box_request, Output=bounding_box_response) - scanner.SendTask(task) + self.SendTask(task) return task - def align(scanner, source: int, target: int, rough: MF_V3_Settings_Align_Align.Rough = None, fine: MF_V3_Settings_Align_Align.Fine = None) -> Task: + def align(self, source: int, target: int, rough: MF_V3_Settings_Align_Align.Rough = None, fine: MF_V3_Settings_Align_Align.Fine = None) -> Task: # Align two scan groups. align_request = MF_V3_Tasks_Align.Request( Index=0, @@ -615,10 +615,10 @@ def align(scanner, source: int, target: int, rough: MF_V3_Settings_Align_Align.R Output=None ) task = Task(Index=0, Type="Align", Input=align_request, Output=align_response) - scanner.SendTask(task) + self.SendTask(task) return task - def merge(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: MF_V3_Settings_Merge_Merge.Remesh = None, simplify: MF_V3_Settings_Merge_Merge.Simplify = None, texturize: bool = None) -> Task: + def merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: MF_V3_Settings_Merge_Merge.Remesh = None, simplify: MF_V3_Settings_Merge_Merge.Simplify = None, texturize: bool = None) -> Task: # Merge two or more scan groups. merge_request = MF_V3_Tasks_Merge.Request( Index=0, @@ -642,10 +642,10 @@ def merge(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, Output=None ) task = Task(Index=0, Type="Merge", Input=merge_request, Output=merge_response) - scanner.SendTask(task) + self.SendTask(task) return task - def merge_data(scanner, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: + def merge_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: # Download the raw scan data for the current merge process. merge_data_request = MF_V3_Tasks_MergeData.Request( Index=0, @@ -669,10 +669,10 @@ def merge_data(scanner, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Bu Output=None ) task = Task(Index=0, Type="MergeData", Input=merge_data_request, Output=merge_data_response) - scanner.SendTask(task) + self.SendTask(task) return task - def add_merge_to_project(scanner) -> Task: + def add_merge_to_project(self) -> Task: # Add a merged scan to the current project. add_merge_to_project_request = MF_V3_Tasks_AddMergeToProject.Request( Index=0, @@ -684,10 +684,10 @@ def add_merge_to_project(scanner) -> Task: Output=None ) task = Task(Index=0, Type="AddMergeToProject", Input=add_merge_to_project_request, Output=add_merge_to_project_response) - scanner.SendTask(task) + self.SendTask(task) return task - def list_export_formats(scanner) -> Task: + def list_export_formats(self) -> Task: # List all export formats. list_export_formats_request = MF_V3_Tasks_ListExportFormats.Request( Index=0, @@ -699,10 +699,10 @@ def list_export_formats(scanner) -> Task: Output=None ) task = Task(Index=0, Type="ListExportFormats", Input=list_export_formats_request, Output=list_export_formats_response) - scanner.SendTask(task) + self.SendTask(task) return task - def export(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: + def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: # Export a group of scans. export_request = MF_V3_Tasks_Export.Request( Index=0, @@ -725,10 +725,10 @@ def export(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection = None ) ) task = Task(Index=0, Type="Export", Input=export_request, Output=export_response) - scanner.SendTask(task) + self.SendTask(task) return task - def export_merge(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: + def export_merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: # Export a merged scan. export_merge_request = MF_V3_Tasks_ExportMerge.Request( Index=0, @@ -751,10 +751,10 @@ def export_merge(scanner, selection: MF_V3_Settings_ScanSelection_ScanSelection ) ) task = Task(Index=0, Type="ExportMerge", Input=export_merge_request, Output=export_merge_response) - scanner.SendTask(task) + self.SendTask(task) return task - def export_logs(scanner, Input: bool = None) -> Task: + def export_logs(self, Input: bool = None) -> Task: # Export scanner logs. export_logs_request = MF_V3_Tasks_ExportLogs.Request( Index=0, @@ -766,10 +766,10 @@ def export_logs(scanner, Input: bool = None) -> Task: Type="ExportLogs" ) task = Task(Index=0, Type="ExportLogs", Input=export_logs_request, Output=export_logs_response) - scanner.SendTask(task) + self.SendTask(task) return task - def has_cameras(scanner) -> Task: + def has_cameras(self) -> Task: # Check if the scanner has working cameras. has_cameras_request = MF_V3_Tasks_HasCameras.Request( Index=0, @@ -780,10 +780,10 @@ def has_cameras(scanner) -> Task: Type="HasCameras" ) task = Task(Index=0, Type="HasCameras", Input=has_cameras_request, Output=has_cameras_response) - scanner.SendTask(task) + self.SendTask(task) return task - def has_projector(scanner) -> Task: + def has_projector(self) -> Task: # Check if the scanner has a working projector. has_projector_request = MF_V3_Tasks_HasProjector.Request( Index=0, @@ -794,10 +794,10 @@ def has_projector(scanner) -> Task: Type="HasProjector" ) task = Task(Index=0, Type="HasProjector", Input=has_projector_request, Output=has_projector_response) - scanner.SendTask(task) + self.SendTask(task) return task - def has_turntable(scanner) -> Task: + def has_turntable(self) -> Task: # Check if the scanner is connected to a working turntable. has_turntable_request = MF_V3_Tasks_HasTurntable.Request( Index=0, @@ -808,10 +808,10 @@ def has_turntable(scanner) -> Task: Type="HasTurntable" ) task = Task(Index=0, Type="HasTurntable", Input=has_turntable_request, Output=has_turntable_response) - scanner.SendTask(task) + self.SendTask(task) return task - def system_info(scanner, installed: MF_V3_Settings_Software_Software.Package, available: MF_V3_Settings_Software_Software.Package, nightlyIncluded: bool = None) -> Task: + def system_info(self, installed: MF_V3_Settings_Software_Software.Package, available: MF_V3_Settings_Software_Software.Package, nightlyIncluded: bool = None) -> Task: # Get system information. system_info_request = MF_V3_Tasks_SystemInfo.Request( Index=0, @@ -828,10 +828,10 @@ def system_info(scanner, installed: MF_V3_Settings_Software_Software.Package, av Output=None ) task = Task(Index=0, Type="SystemInfo", Input=system_info_request, Output=system_info_response) - scanner.SendTask(task) + self.SendTask(task) return task - def camera_calibration(scanner) -> Task: + def camera_calibration(self) -> Task: # Get the camera calibration descriptor. camera_calibration_request = MF_V3_Tasks_CameraCalibration.Request( Index=0, @@ -842,10 +842,10 @@ def camera_calibration(scanner) -> Task: Type="CameraCalibration" ) task = Task(Index=0, Type="CameraCalibration", Input=camera_calibration_request, Output=camera_calibration_response) - scanner.SendTask(task) + self.SendTask(task) return task - def turntable_calibration(scanner) -> Task: + def turntable_calibration(self) -> Task: # Get the turntable calibration descriptor. turntable_calibration_request = MF_V3_Tasks_TurntableCalibration.Request( Index=0, @@ -856,10 +856,10 @@ def turntable_calibration(scanner) -> Task: Type="TurntableCalibration" ) task = Task(Index=0, Type="TurntableCalibration", Input=turntable_calibration_request, Output=turntable_calibration_response) - scanner.SendTask(task) + self.SendTask(task) return task - def calibration_capture_targets(scanner) -> Task: + def calibration_capture_targets(self) -> Task: # Get the calibration capture target for each camera calibration capture. calibration_capture_targets_request = MF_V3_Tasks_CalibrationCaptureTargets.Request( Index=0, @@ -870,10 +870,10 @@ def calibration_capture_targets(scanner) -> Task: Type="CalibrationCaptureTargets" ) task = Task(Index=0, Type="CalibrationCaptureTargets", Input=calibration_capture_targets_request, Output=calibration_capture_targets_response) - scanner.SendTask(task) + self.SendTask(task) return task - def calibrate_cameras(scanner) -> Task: + def calibrate_cameras(self) -> Task: # Calibrate the cameras. calibrate_cameras_request = MF_V3_Tasks_CalibrateCameras.Request( Index=0, @@ -884,10 +884,10 @@ def calibrate_cameras(scanner) -> Task: Type="CalibrateCameras" ) task = Task(Index=0, Type="CalibrateCameras", Input=calibrate_cameras_request, Output=calibrate_cameras_response) - scanner.SendTask(task) + self.SendTask(task) return task - def calibrate_turntable(scanner) -> Task: + def calibrate_turntable(self) -> Task: # Calibrate the turntable. calibrate_turntable_request = MF_V3_Tasks_CalibrateTurntable.Request( Index=0, @@ -898,10 +898,10 @@ def calibrate_turntable(scanner) -> Task: Type="CalibrateTurntable" ) task = Task(Index=0, Type="CalibrateTurntable", Input=calibrate_turntable_request, Output=calibrate_turntable_response) - scanner.SendTask(task) + self.SendTask(task) return task - def detect_calibration_card(scanner, Input: int) -> Task: + def detect_calibration_card(self, Input: int) -> Task: # Detect the calibration card on one or both cameras. detect_calibration_card_request = MF_V3_Tasks_DetectCalibrationCard.Request( Index=0, @@ -914,10 +914,10 @@ def detect_calibration_card(scanner, Input: int) -> Task: Input=Input ) task = Task(Index=0, Type="DetectCalibrationCard", Input=detect_calibration_card_request, Output=detect_calibration_card_response) - scanner.SendTask(task) + self.SendTask(task) return task - def restore_factory_calibration(scanner) -> Task: + def restore_factory_calibration(self) -> Task: # Restore factory calibration. restore_factory_calibration_request = MF_V3_Tasks_RestoreFactoryCalibration.Request( Index=0, @@ -928,10 +928,10 @@ def restore_factory_calibration(scanner) -> Task: Type="RestoreFactoryCalibration" ) task = Task(Index=0, Type="RestoreFactoryCalibration", Input=restore_factory_calibration_request, Output=restore_factory_calibration_response) - scanner.SendTask(task) + self.SendTask(task) return task - def start_video(scanner) -> Task: + def start_video(self) -> Task: # Start the video stream. start_video_request = MF_V3_Tasks_StartVideo.Request( Index=0, @@ -942,10 +942,10 @@ def start_video(scanner) -> Task: Type="StartVideo" ) task = Task(Index=0, Type="StartVideo", Input=start_video_request, Output=start_video_response) - scanner.SendTask(task) + self.SendTask(task) return task - def stop_video(scanner) -> Task: + def stop_video(self) -> Task: # Stop the video stream. stop_video_request = MF_V3_Tasks_StopVideo.Request( Index=0, @@ -956,10 +956,10 @@ def stop_video(scanner) -> Task: Type="StopVideo" ) task = Task(Index=0, Type="StopVideo", Input=stop_video_request, Output=stop_video_response) - scanner.SendTask(task) + self.SendTask(task) return task - def set_cameras(scanner, selection: int, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> Task: + def set_cameras(self, selection: int, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> Task: # Apply camera settings to one or both cameras. set_cameras_request = MF_V3_Tasks_SetCameras.Request( Index=0, @@ -978,10 +978,10 @@ def set_cameras(scanner, selection: int, autoExposure: bool = None, exposure: in Type="SetCameras" ) task = Task(Index=0, Type="SetCameras", Input=set_cameras_request, Output=set_cameras_response) - scanner.SendTask(task) + self.SendTask(task) return task - def set_projector(scanner, color: float, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None) -> Task: + def set_projector(self, color: float, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None) -> Task: # Apply projector settings. set_projector_request = MF_V3_Tasks_SetProjector.Request( Index=0, @@ -999,10 +999,10 @@ def set_projector(scanner, color: float, on: bool = None, brightness: float = No Type="SetProjector" ) task = Task(Index=0, Type="SetProjector", Input=set_projector_request, Output=set_projector_response) - scanner.SendTask(task) + self.SendTask(task) return task - def auto_focus(scanner, cameras: MF_V3_Settings_AutoFocus_AutoFocus.Camera, applyAll: bool) -> Task: + def auto_focus(self, cameras: MF_V3_Settings_AutoFocus_AutoFocus.Camera, applyAll: bool) -> Task: # Auto focus one or both cameras. auto_focus_request = MF_V3_Tasks_AutoFocus.Request( Index=0, @@ -1017,10 +1017,10 @@ def auto_focus(scanner, cameras: MF_V3_Settings_AutoFocus_AutoFocus.Camera, appl Type="AutoFocus" ) task = Task(Index=0, Type="AutoFocus", Input=auto_focus_request, Output=auto_focus_response) - scanner.SendTask(task) + self.SendTask(task) return task - def rotate_turntable(scanner, Input: int) -> Task: + def rotate_turntable(self, Input: int) -> Task: # Rotate the turntable. rotate_turntable_request = MF_V3_Tasks_RotateTurntable.Request( Index=0, @@ -1033,10 +1033,10 @@ def rotate_turntable(scanner, Input: int) -> Task: Input=Input ) task = Task(Index=0, Type="RotateTurntable", Input=rotate_turntable_request, Output=rotate_turntable_response) - scanner.SendTask(task) + self.SendTask(task) return task - def new_scan(scanner, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: + def new_scan(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: # Capture a new scan. new_scan_request = MF_V3_Tasks_NewScan.Request( Index=0, @@ -1054,10 +1054,10 @@ def new_scan(scanner, camera: MF_V3_Settings_Camera_Camera = None, projector: MF Type="NewScan" ) task = Task(Index=0, Type="NewScan", Input=new_scan_request, Output=new_scan_response) - scanner.SendTask(task) + self.SendTask(task) return task - def depth_map(scanner, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: + def depth_map(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: # Capture a depth map. depth_map_request = MF_V3_Tasks_DepthMap.Request( Index=0, @@ -1076,10 +1076,10 @@ def depth_map(scanner, camera: MF_V3_Settings_Camera_Camera = None, projector: M Output=None ) task = Task(Index=0, Type="DepthMap", Input=depth_map_request, Output=depth_map_response) - scanner.SendTask(task) + self.SendTask(task) return task - def reboot(scanner) -> Task: + def reboot(self) -> Task: # Reboot the scanner. reboot_request = MF_V3_Tasks_Reboot.Request( Index=0, @@ -1090,10 +1090,10 @@ def reboot(scanner) -> Task: Type="Reboot" ) task = Task(Index=0, Type="Reboot", Input=reboot_request, Output=reboot_response) - scanner.SendTask(task) + self.SendTask(task) return task - def shutdown(scanner) -> Task: + def shutdown(self) -> Task: # Shutdown the scanner. shutdown_request = MF_V3_Tasks_Shutdown.Request( Index=0, @@ -1104,7 +1104,7 @@ def shutdown(scanner) -> Task: Type="Shutdown" ) task = Task(Index=0, Type="Shutdown", Input=shutdown_request, Output=shutdown_response) - scanner.SendTask(task) + self.SendTask(task) return task diff --git a/maf_three/MF/V3/__init__.py b/maf_three/MF/V3/__init__.py index 69fcf73..2b3cccc 100644 --- a/maf_three/MF/V3/__init__.py +++ b/maf_three/MF/V3/__init__.py @@ -1,3 +1,3 @@ from MF.V3.Three import * -from MF.V3.Task import * from MF.V3.Buffer import * +from MF.V3.Task import * diff --git a/maf_three/__init__.py b/maf_three/__init__.py index 8c0d5d5..0f607a5 100644 --- a/maf_three/__init__.py +++ b/maf_three/__init__.py @@ -1 +1 @@ -__version__ = "2.0.0" +__version__ = "6.0.0" diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index 308ec34..2388ae9 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -8,9 +8,6 @@ # from maf_three.scanner import Scanner sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) -from MF.V3.Tasks import SetProjector, Settings_Projector as Projector -from MF.V3.Task import Task - from maf_three.scanner import Scanner @@ -21,9 +18,10 @@ def main(): scanner.Connect("ws://matterandform.local:8081") - scanner.SetProjector(on=True, brightness=1.0, color=[1,1,1]) + scanner.set_projector(on=True, brightness=1.0, color=[1,1,1]) # Sleep for 5 seconds - time.sleep(5) + time.sleep(1) + # task.Projector.CopyFrom(Projector(on=True, brightness=1.0, color=[1,1,1])) # print("test2") # print(task) diff --git a/maf_three/scanner.py b/maf_three/scanner.py index 7fa49f4..c07782f 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -10,6 +10,9 @@ import json import threading import time +import importlib +import inspect +import types from MF.V3 import Task, TaskState @@ -17,7 +20,7 @@ from maf_three.serialization import TO_JSON from maf_three.MF.V3.Buffer import Buffer -from maf_three.MF.V3.Three import Three as MF3 +from maf_three.MF.V3.Three import Three class Scanner: """ @@ -56,12 +59,13 @@ def __init__(self, self.__task_return_event = threading.Event() - # Bind functions - self.bind_functions() - - def bind_functions(self): - # SetProjector - self.set_projector = lambda on, brightness, color: MF3.set_projector(self, on=on, brightness=brightness, color=color) + # Dynamically import and add functions from Three.py + Three_module = importlib.import_module('.Three', package='maf_three.MF.V3') + for name, func in inspect.getmembers(Three_module.Three, inspect.isfunction): + bound_func = types.MethodType(func, self) + setattr(self, name, bound_func) + + def Connect(self, URI:str, timeoutSec=5) -> bool: """ @@ -322,20 +326,3 @@ def __FindTaskWithIndex(self, index:int) -> Task: return t break return None - - -# Main function to run the code -if __name__ == "__main__": - - scanner = Scanner()#OnTask=on_task, OnMessage=on_message, OnBuffer=on_buffer) - scanner.Connect("ws://matterandform.local:8081") - - # Set the projector settings for debugging - # scanner.set_projector(on=True, brightness=1.0, color=[1, 1, 1]) - # time.sleep(1) - # scanner.set_projector(on=False, brightness=1.0, color=[1, 1, 1]) - # time.sleep(1) - - project_tasks = MF3.list_projects(scanner) - print(project_tasks.Output) - scanner.Disconnect() \ No newline at end of file diff --git a/out/maf_three/MF/V3/Three.pyi b/out/maf_three/MF/V3/Three.pyi new file mode 100644 index 0000000..8f73f41 --- /dev/null +++ b/out/maf_three/MF/V3/Three.pyi @@ -0,0 +1,77 @@ +from MF.V3 import Task +from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced +from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align +from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera +from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture +from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export +from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n +from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge +from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData +from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection +from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software +from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style +from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable +from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials +from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer + +class Three: + def __init__(self) -> None: ... + def list_network_interfaces(self) -> Task: ... + def list_wifi(self) -> Task: ... + def connect_wifi(self, ssid: str, password: str) -> Task: ... + def forget_wifi(self) -> Task: ... + def list_settings(self) -> Task: ... + def push_settings(self) -> Task: ... + def pop_settings(self, Input: bool = None) -> Task: ... + def update_settings(self, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None) -> Task: ... + def list_projects(self) -> Task: ... + def download_project(self, Input: int) -> Task: ... + def upload_project(self) -> Task: ... + def new_project(self, Input: str = None) -> Task: ... + def open_project(self, Input: int) -> Task: ... + def close_project(self) -> Task: ... + def remove_projects(self, Input: int) -> Task: ... + def list_groups(self) -> Task: ... + def list_scans(self) -> Task: ... + def scan_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: ... + def set_project(self, index: int = None, name: str = None) -> Task: ... + def set_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: ... + def new_group(self, color: float, rotation: float, translation: float, parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None) -> Task: ... + def move_group(self, Input: int) -> Task: ... + def flatten_group(self, Input: int) -> Task: ... + def split_group(self, Input: int) -> Task: ... + def transform_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: ... + def remove_groups(self, Input: int) -> Task: ... + def bounding_box(self, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool) -> Task: ... + def align(self, source: int, target: int, rough: MF_V3_Settings_Align_Align.Rough = None, fine: MF_V3_Settings_Align_Align.Fine = None) -> Task: ... + def merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: MF_V3_Settings_Merge_Merge.Remesh = None, simplify: MF_V3_Settings_Merge_Merge.Simplify = None, texturize: bool = None) -> Task: ... + def merge_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: ... + def add_merge_to_project(self) -> Task: ... + def list_export_formats(self) -> Task: ... + def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: ... + def export_merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: ... + def export_logs(self, Input: bool = None) -> Task: ... + def has_cameras(self) -> Task: ... + def has_projector(self) -> Task: ... + def has_turntable(self) -> Task: ... + def system_info(self, installed: MF_V3_Settings_Software_Software.Package, available: MF_V3_Settings_Software_Software.Package, nightlyIncluded: bool = None) -> Task: ... + def camera_calibration(self) -> Task: ... + def turntable_calibration(self) -> Task: ... + def calibration_capture_targets(self) -> Task: ... + def calibrate_cameras(self) -> Task: ... + def calibrate_turntable(self) -> Task: ... + def detect_calibration_card(self, Input: int) -> Task: ... + def restore_factory_calibration(self) -> Task: ... + def start_video(self) -> Task: ... + def stop_video(self) -> Task: ... + def set_cameras(self, selection: int, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> Task: ... + def set_projector(self, color: float, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None) -> Task: ... + def auto_focus(self, cameras: MF_V3_Settings_AutoFocus_AutoFocus.Camera, applyAll: bool) -> Task: ... + def rotate_turntable(self, Input: int) -> Task: ... + def new_scan(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: ... + def depth_map(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: ... + def reboot(self) -> Task: ... + def shutdown(self) -> Task: ... diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 94b9d20..6846f73 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -148,6 +148,8 @@ def generate_import_lines(descriptorsLists:Dict[str, List[ImportDescriptor]], fi importList.types.append({"type":descriptor.type, "replacement":descriptor.replacement}) ImportListArray.append(importList) + ImportListArray.sort(key=lambda x: x.file) + for importList in ImportListArray: if importList.file == "enum": @@ -492,7 +494,7 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: method_name += "_" method_name += c.lower() - service_code += f" def {method_name}(scanner" + service_code += f" def {method_name}(self" # loop over all the properties from the request node to get the input node method_properties = [] @@ -613,7 +615,7 @@ def create_object_code(node:TreeNode, postfix:str, ignore_optionals:bool)->str: service_code += create_object_code(response_node, "response", True) service_code += f" task = {task_name}(Index=0, Type=\"{procedure.name}\", Input={method_name}_request, Output={method_name}_response)\n" - service_code += f" scanner.SendTask(task)\n" + service_code += f" self.SendTask(task)\n" service_code += f" return task\n\n" return service_code From 6be1a30a9abf3ccfdd481a1587db6da7ed316e09 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Mon, 30 Sep 2024 13:11:03 -0400 Subject: [PATCH 56/86] Sorting imports for init files --- .../MF/V3/Descriptors/Settings/__init__.py | 16 ++-- maf_three/MF/V3/Descriptors/__init__.py | 8 +- maf_three/MF/V3/Settings/__init__.py | 42 ++++----- maf_three/MF/V3/Tasks/__init__.py | 88 +++++++++---------- maf_three/MF/V3/__init__.py | 2 +- scripts/transpileProto.py | 6 +- 6 files changed, 82 insertions(+), 80 deletions(-) diff --git a/maf_three/MF/V3/Descriptors/Settings/__init__.py b/maf_three/MF/V3/Descriptors/Settings/__init__.py index fceebd7..03ad69e 100644 --- a/maf_three/MF/V3/Descriptors/Settings/__init__.py +++ b/maf_three/MF/V3/Descriptors/Settings/__init__.py @@ -1,11 +1,11 @@ -from MF.V3.Descriptors.Settings.Style import * -from MF.V3.Descriptors.Settings.Turntable import * -from MF.V3.Descriptors.Settings.Viewer import * -from MF.V3.Descriptors.Settings.Projector import * -from MF.V3.Descriptors.Settings.Tutorials import * -from MF.V3.Descriptors.Settings.I18n import * from MF.V3.Descriptors.Settings.Advanced import * -from MF.V3.Descriptors.Settings.Scanner import * -from MF.V3.Descriptors.Settings.Capture import * from MF.V3.Descriptors.Settings.Camera import * +from MF.V3.Descriptors.Settings.Capture import * +from MF.V3.Descriptors.Settings.I18n import * +from MF.V3.Descriptors.Settings.Projector import * +from MF.V3.Descriptors.Settings.Scanner import * from MF.V3.Descriptors.Settings.Software import * +from MF.V3.Descriptors.Settings.Style import * +from MF.V3.Descriptors.Settings.Turntable import * +from MF.V3.Descriptors.Settings.Tutorials import * +from MF.V3.Descriptors.Settings.Viewer import * diff --git a/maf_three/MF/V3/Descriptors/__init__.py b/maf_three/MF/V3/Descriptors/__init__.py index 92fcd1e..859bf4d 100644 --- a/maf_three/MF/V3/Descriptors/__init__.py +++ b/maf_three/MF/V3/Descriptors/__init__.py @@ -1,12 +1,12 @@ from MF.V3.Descriptors.BoundingBox import * -from MF.V3.Descriptors.Image import * from MF.V3.Descriptors.Export import * +from MF.V3.Descriptors.Image import * from MF.V3.Descriptors.Merge import * -from MF.V3.Descriptors.System import * from MF.V3.Descriptors.Project import * from MF.V3.Descriptors.ProjectActions import * +from MF.V3.Descriptors.RemoveVertices import * +from MF.V3.Descriptors.ScanData import * +from MF.V3.Descriptors.System import * from MF.V3.Descriptors.Transform import * from MF.V3.Descriptors.VideoFrame import * from MF.V3.Descriptors.Wifi import * -from MF.V3.Descriptors.ScanData import * -from MF.V3.Descriptors.RemoveVertices import * diff --git a/maf_three/MF/V3/Settings/__init__.py b/maf_three/MF/V3/Settings/__init__.py index 2ec545c..a3259aa 100644 --- a/maf_three/MF/V3/Settings/__init__.py +++ b/maf_three/MF/V3/Settings/__init__.py @@ -1,29 +1,29 @@ -from MF.V3.Settings.ScanData import * -from MF.V3.Settings.Capture import * -from MF.V3.Settings.I18n import * -from MF.V3.Settings.Style import * -from MF.V3.Settings.Remesh import * -from MF.V3.Settings.Turntable import * +from MF.V3.Settings.Advanced import * +from MF.V3.Settings.Align import * +from MF.V3.Settings.AutoFocus import * +from MF.V3.Settings.BoundingBox import * from MF.V3.Settings.Camera import * +from MF.V3.Settings.Capture import * +from MF.V3.Settings.Export import * from MF.V3.Settings.Group import * -from MF.V3.Settings.BoundingBox import * -from MF.V3.Settings.Scan import * -from MF.V3.Settings.Viewer import * -from MF.V3.Settings.Tutorials import * +from MF.V3.Settings.I18n import * +from MF.V3.Settings.Merge import * from MF.V3.Settings.NewGroup import * -from MF.V3.Settings.Rectangle import * -from MF.V3.Settings.AutoFocus import * -from MF.V3.Settings.Export import * from MF.V3.Settings.Project import * -from MF.V3.Settings.RemoveVertices import * -from MF.V3.Settings.Advanced import * -from MF.V3.Settings.Wifi import * -from MF.V3.Settings.Video import * -from MF.V3.Settings.Software import * -from MF.V3.Settings.Align import * +from MF.V3.Settings.Projector import * from MF.V3.Settings.Quality import * +from MF.V3.Settings.Rectangle import * +from MF.V3.Settings.Remesh import * +from MF.V3.Settings.RemoveVertices import * +from MF.V3.Settings.Scan import * +from MF.V3.Settings.ScanData import * from MF.V3.Settings.ScanSelection import * from MF.V3.Settings.Scanner import * -from MF.V3.Settings.Projector import * -from MF.V3.Settings.Merge import * +from MF.V3.Settings.Software import * +from MF.V3.Settings.Style import * +from MF.V3.Settings.Turntable import * +from MF.V3.Settings.Tutorials import * from MF.V3.Settings.Upgrade import * +from MF.V3.Settings.Video import * +from MF.V3.Settings.Viewer import * +from MF.V3.Settings.Wifi import * diff --git a/maf_three/MF/V3/Tasks/__init__.py b/maf_three/MF/V3/Tasks/__init__.py index 8d8a903..d91979d 100644 --- a/maf_three/MF/V3/Tasks/__init__.py +++ b/maf_three/MF/V3/Tasks/__init__.py @@ -1,56 +1,56 @@ -from MF.V3.Tasks.DownloadProject import * -from MF.V3.Tasks.ConnectWifi import * -from MF.V3.Tasks.CloseProject import * -from MF.V3.Tasks.FlattenGroup import * -from MF.V3.Tasks.CalibrateCameras import * -from MF.V3.Tasks.MergeData import * from MF.V3.Tasks.AddMergeToProject import * -from MF.V3.Tasks.PushSettings import * -from MF.V3.Tasks.RestoreFactoryCalibration import * -from MF.V3.Tasks.PopSettings import * -from MF.V3.Tasks.RemoveGroups import * -from MF.V3.Tasks.OpenProject import * -from MF.V3.Tasks.Merge import * -from MF.V3.Tasks.SetGroup import * -from MF.V3.Tasks.Reboot import * -from MF.V3.Tasks.ListSettings import * +from MF.V3.Tasks.Align import * +from MF.V3.Tasks.AutoFocus import * +from MF.V3.Tasks.BoundingBox import * +from MF.V3.Tasks.CalibrateCameras import * +from MF.V3.Tasks.CalibrateTurntable import * +from MF.V3.Tasks.CalibrationCaptureTargets import * +from MF.V3.Tasks.CameraCalibration import * +from MF.V3.Tasks.CloseProject import * +from MF.V3.Tasks.ConnectWifi import * +from MF.V3.Tasks.DepthMap import * +from MF.V3.Tasks.DetectCalibrationCard import * +from MF.V3.Tasks.DownloadProject import * +from MF.V3.Tasks.Export import * from MF.V3.Tasks.ExportLogs import * -from MF.V3.Tasks.RemoveProjects import * -from MF.V3.Tasks.TransformGroup import * +from MF.V3.Tasks.ExportMerge import * +from MF.V3.Tasks.FlattenGroup import * from MF.V3.Tasks.ForgetWifi import * -from MF.V3.Tasks.MoveGroup import * +from MF.V3.Tasks.HasCameras import * +from MF.V3.Tasks.HasProjector import * +from MF.V3.Tasks.HasTurntable import * from MF.V3.Tasks.ListExportFormats import * -from MF.V3.Tasks.Align import * -from MF.V3.Tasks.SplitGroup import * -from MF.V3.Tasks.ListProjects import * -from MF.V3.Tasks.CameraCalibration import * from MF.V3.Tasks.ListGroups import * -from MF.V3.Tasks.CalibrationCaptureTargets import * -from MF.V3.Tasks.NewScan import * from MF.V3.Tasks.ListNetworkInterfaces import * -from MF.V3.Tasks.HasProjector import * -from MF.V3.Tasks.Export import * -from MF.V3.Tasks.BoundingBox import * -from MF.V3.Tasks.DepthMap import * +from MF.V3.Tasks.ListProjects import * +from MF.V3.Tasks.ListScans import * +from MF.V3.Tasks.ListSettings import * +from MF.V3.Tasks.ListWifi import * +from MF.V3.Tasks.Merge import * +from MF.V3.Tasks.MergeData import * +from MF.V3.Tasks.MoveGroup import * +from MF.V3.Tasks.NewGroup import * +from MF.V3.Tasks.NewProject import * +from MF.V3.Tasks.NewScan import * +from MF.V3.Tasks.OpenProject import * +from MF.V3.Tasks.PopSettings import * +from MF.V3.Tasks.PushSettings import * +from MF.V3.Tasks.Reboot import * +from MF.V3.Tasks.RemoveGroups import * +from MF.V3.Tasks.RemoveProjects import * +from MF.V3.Tasks.RestoreFactoryCalibration import * +from MF.V3.Tasks.RotateTurntable import * +from MF.V3.Tasks.ScanData import * from MF.V3.Tasks.SetCameras import * -from MF.V3.Tasks.DetectCalibrationCard import * +from MF.V3.Tasks.SetGroup import * +from MF.V3.Tasks.SetProject import * from MF.V3.Tasks.SetProjector import * -from MF.V3.Tasks.StopVideo import * +from MF.V3.Tasks.Shutdown import * +from MF.V3.Tasks.SplitGroup import * from MF.V3.Tasks.StartVideo import * -from MF.V3.Tasks.HasTurntable import * +from MF.V3.Tasks.StopVideo import * from MF.V3.Tasks.SystemInfo import * -from MF.V3.Tasks.RotateTurntable import * -from MF.V3.Tasks.ScanData import * -from MF.V3.Tasks.Shutdown import * -from MF.V3.Tasks.CalibrateTurntable import * -from MF.V3.Tasks.UpdateSettings import * -from MF.V3.Tasks.HasCameras import * -from MF.V3.Tasks.SetProject import * -from MF.V3.Tasks.ExportMerge import * +from MF.V3.Tasks.TransformGroup import * from MF.V3.Tasks.TurntableCalibration import * -from MF.V3.Tasks.NewProject import * -from MF.V3.Tasks.ListScans import * +from MF.V3.Tasks.UpdateSettings import * from MF.V3.Tasks.UploadProject import * -from MF.V3.Tasks.ListWifi import * -from MF.V3.Tasks.NewGroup import * -from MF.V3.Tasks.AutoFocus import * diff --git a/maf_three/MF/V3/__init__.py b/maf_three/MF/V3/__init__.py index 2b3cccc..2bcc874 100644 --- a/maf_three/MF/V3/__init__.py +++ b/maf_three/MF/V3/__init__.py @@ -1,3 +1,3 @@ -from MF.V3.Three import * from MF.V3.Buffer import * from MF.V3.Task import * +from MF.V3.Three import * diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 6846f73..daf7dd1 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -637,10 +637,12 @@ def generate_init_files(paths: set, tree: Tree, output_dir: str): for child in node.children.values(): if child.filespace: imports.add(child.filespace) - + + sorted_imports = sorted(imports) + with open(init_file, 'w') as f: f.write("") #guarantee a file - for import_path in imports: + for import_path in sorted_imports: f.write(f"from {import_path} import * \n") From f643406cdfc8c4de3008ef2bdcb62064a7c2031e Mon Sep 17 00:00:00 2001 From: drewsipher Date: Mon, 30 Sep 2024 15:36:21 -0400 Subject: [PATCH 57/86] Created a stub file for scanner --- maf_three/MF/V3/Three.py | 2103 ++++++++++++++++--------------- maf_three/examples/projector.py | 3 +- maf_three/scanner.py | 24 +- maf_three/scanner.pyi | 162 +++ out/maf_three/MF/V3/Three.pyi | 77 -- scripts/build-proto.py | 84 +- scripts/transpileProto.py | 42 +- 7 files changed, 1356 insertions(+), 1139 deletions(-) create mode 100644 maf_three/scanner.pyi delete mode 100644 out/maf_three/MF/V3/Three.pyi diff --git a/maf_three/MF/V3/Three.py b/maf_three/MF/V3/Three.py index be7396e..cb40205 100644 --- a/maf_three/MF/V3/Three.py +++ b/maf_three/MF/V3/Three.py @@ -80,1032 +80,1083 @@ from MF.V3.Tasks.UploadProject import UploadProject as MF_V3_Tasks_UploadProject -class Three: - # Three scanner API. - def __init__(self): - pass - - def list_network_interfaces(self) -> Task: - # List available wifi networks. - list_network_interfaces_request = MF_V3_Tasks_ListNetworkInterfaces.Request( - Index=0, - Type="ListNetworkInterfaces" - ) - list_network_interfaces_response = MF_V3_Tasks_ListNetworkInterfaces.Response( - Index=0, - Type="ListNetworkInterfaces" - ) - task = Task(Index=0, Type="ListNetworkInterfaces", Input=list_network_interfaces_request, Output=list_network_interfaces_response) - self.SendTask(task) - return task - - def list_wifi(self) -> Task: - # List available wifi networks. - list_wifi_request = MF_V3_Tasks_ListWifi.Request( - Index=0, - Type="ListWifi" - ) - list_wifi_response = MF_V3_Tasks_ListWifi.Response( - Index=0, - Type="ListWifi" - ) - task = Task(Index=0, Type="ListWifi", Input=list_wifi_request, Output=list_wifi_response) - self.SendTask(task) - return task - - def connect_wifi(self, ssid: str, password: str) -> Task: - # Connect to a wifi network. - connect_wifi_request = MF_V3_Tasks_ConnectWifi.Request( - Index=0, - Type="ConnectWifi", - Input=MF_V3_Settings_Wifi_Wifi( - ssid=ssid, - password=password, - ) - ) - connect_wifi_response = MF_V3_Tasks_ConnectWifi.Response( - Index=0, - Type="ConnectWifi", - Input=MF_V3_Settings_Wifi_Wifi( - ssid=ssid, - password=password, - ) - ) - task = Task(Index=0, Type="ConnectWifi", Input=connect_wifi_request, Output=connect_wifi_response) - self.SendTask(task) - return task - - def forget_wifi(self) -> Task: - # Forget all wifi connections. - forget_wifi_request = MF_V3_Tasks_ForgetWifi.Request( - Index=0, - Type="ForgetWifi" - ) - forget_wifi_response = MF_V3_Tasks_ForgetWifi.Response( - Index=0, - Type="ForgetWifi" - ) - task = Task(Index=0, Type="ForgetWifi", Input=forget_wifi_request, Output=forget_wifi_response) - self.SendTask(task) - return task - - def list_settings(self) -> Task: - # Get scanner settings. - list_settings_request = MF_V3_Tasks_ListSettings.Request( - Index=0, - Type="ListSettings" - ) - list_settings_response = MF_V3_Tasks_ListSettings.Response( - Index=0, - Type="ListSettings" - ) - task = Task(Index=0, Type="ListSettings", Input=list_settings_request, Output=list_settings_response) - self.SendTask(task) - return task - - def push_settings(self) -> Task: - # Push the current scanner settings to the settings stack. - push_settings_request = MF_V3_Tasks_PushSettings.Request( - Index=0, - Type="PushSettings" - ) - push_settings_response = MF_V3_Tasks_PushSettings.Response( - Index=0, - Type="PushSettings" - ) - task = Task(Index=0, Type="PushSettings", Input=push_settings_request, Output=push_settings_response) - self.SendTask(task) - return task - - def pop_settings(self, Input: bool = None) -> Task: - # Pop and restore scanner settings from the settings stack. - pop_settings_request = MF_V3_Tasks_PopSettings.Request( - Index=0, - Type="PopSettings", - Input=Input - ) - pop_settings_response = MF_V3_Tasks_PopSettings.Response( - Index=0, - Type="PopSettings" - ) - task = Task(Index=0, Type="PopSettings", Input=pop_settings_request, Output=pop_settings_response) - self.SendTask(task) - return task - - def update_settings(self, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None) -> Task: - # Update scanner settings. - update_settings_request = MF_V3_Tasks_UpdateSettings.Request( - Index=0, - Type="UpdateSettings", - Input=MF_V3_Settings_Scanner_Scanner( - advanced=advanced, - camera=camera, - capture=capture, - i18n=i18n, - projector=projector, - style=style, - turntable=turntable, - tutorials=tutorials, - viewer=viewer, - software=software, - ) - ) - update_settings_response = MF_V3_Tasks_UpdateSettings.Response( - Index=0, - Type="UpdateSettings", - Input=MF_V3_Settings_Scanner_Scanner( - advanced=advanced, - camera=camera, - capture=capture, - i18n=i18n, - projector=projector, - style=style, - turntable=turntable, - tutorials=tutorials, - viewer=viewer, - software=software, - ) - ) - task = Task(Index=0, Type="UpdateSettings", Input=update_settings_request, Output=update_settings_response) - self.SendTask(task) - return task - - def list_projects(self) -> Task: - # List all projects. - list_projects_request = MF_V3_Tasks_ListProjects.Request( - Index=0, - Type="ListProjects" - ) - list_projects_response = MF_V3_Tasks_ListProjects.Response( - Index=0, - Type="ListProjects" - ) - task = Task(Index=0, Type="ListProjects", Input=list_projects_request, Output=list_projects_response) - self.SendTask(task) - return task - - def download_project(self, Input: int) -> Task: - # Download a project from the scanner. - download_project_request = MF_V3_Tasks_DownloadProject.Request( - Index=0, - Type="DownloadProject", - Input=Input - ) - download_project_response = MF_V3_Tasks_DownloadProject.Response( - Index=0, - Type="DownloadProject", - Input=Input - ) - task = Task(Index=0, Type="DownloadProject", Input=download_project_request, Output=download_project_response) - self.SendTask(task) - return task - - def upload_project(self) -> Task: - # Upload a project to the scanner. - upload_project_request = MF_V3_Tasks_UploadProject.Request( - Index=0, - Type="UploadProject" - ) - upload_project_response = MF_V3_Tasks_UploadProject.Response( - Index=0, - Type="UploadProject" - ) - task = Task(Index=0, Type="UploadProject", Input=upload_project_request, Output=upload_project_response) - self.SendTask(task) - return task - - def new_project(self, Input: str = None) -> Task: - # Create a new project. - new_project_request = MF_V3_Tasks_NewProject.Request( - Index=0, - Type="NewProject", - Input=Input - ) - new_project_response = MF_V3_Tasks_NewProject.Response( - Index=0, - Type="NewProject" - ) - task = Task(Index=0, Type="NewProject", Input=new_project_request, Output=new_project_response) - self.SendTask(task) - return task - - def open_project(self, Input: int) -> Task: - # Open an existing project. - open_project_request = MF_V3_Tasks_OpenProject.Request( - Index=0, - Type="OpenProject", - Input=Input - ) - open_project_response = MF_V3_Tasks_OpenProject.Response( - Index=0, - Type="OpenProject", - Input=Input - ) - task = Task(Index=0, Type="OpenProject", Input=open_project_request, Output=open_project_response) - self.SendTask(task) - return task - - def close_project(self) -> Task: - # Close the current open project. - close_project_request = MF_V3_Tasks_CloseProject.Request( - Index=0, - Type="CloseProject" - ) - close_project_response = MF_V3_Tasks_CloseProject.Response( - Index=0, - Type="CloseProject" - ) - task = Task(Index=0, Type="CloseProject", Input=close_project_request, Output=close_project_response) - self.SendTask(task) - return task - - def remove_projects(self, Input: int) -> Task: - # Remove selected projects. - remove_projects_request = MF_V3_Tasks_RemoveProjects.Request( - Index=0, - Type="RemoveProjects", - Input=Input - ) - remove_projects_response = MF_V3_Tasks_RemoveProjects.Response( - Index=0, - Type="RemoveProjects", - Input=Input - ) - task = Task(Index=0, Type="RemoveProjects", Input=remove_projects_request, Output=remove_projects_response) - self.SendTask(task) - return task - - def list_groups(self) -> Task: - # List the scan groups in the current open project. - list_groups_request = MF_V3_Tasks_ListGroups.Request( - Index=0, - Type="ListGroups" - ) - list_groups_response = MF_V3_Tasks_ListGroups.Response( - Index=0, - Type="ListGroups", - Output=None - ) - task = Task(Index=0, Type="ListGroups", Input=list_groups_request, Output=list_groups_response) - self.SendTask(task) - return task - - def list_scans(self) -> Task: - # List the scans in the current open project. - list_scans_request = MF_V3_Tasks_ListScans.Request( - Index=0, - Type="ListScans" - ) - list_scans_response = MF_V3_Tasks_ListScans.Response( - Index=0, - Type="ListScans", - Output=None - ) - task = Task(Index=0, Type="ListScans", Input=list_scans_request, Output=list_scans_response) - self.SendTask(task) - return task - - def scan_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: - # Download the raw scan data for a scan in the current open project. - scan_data_request = MF_V3_Tasks_ScanData.Request( - Index=0, - Type="ScanData", - Input=MF_V3_Settings_ScanData_ScanData( - index=index, - buffers=buffers, - metadata=metadata, - mergeStep=mergeStep, - ) - ) - scan_data_response = MF_V3_Tasks_ScanData.Response( - Index=0, - Type="ScanData", - Input=MF_V3_Settings_ScanData_ScanData( - index=index, - buffers=buffers, - metadata=metadata, - mergeStep=mergeStep, - ), - Output=None - ) - task = Task(Index=0, Type="ScanData", Input=scan_data_request, Output=scan_data_response) - self.SendTask(task) - return task - - def set_project(self, index: int = None, name: str = None) -> Task: - # Apply settings to the current open project. - set_project_request = MF_V3_Tasks_SetProject.Request( - Index=0, - Type="SetProject", - Input=MF_V3_Settings_Project_Project( - index=index, - name=name, - ) - ) - set_project_response = MF_V3_Tasks_SetProject.Response( - Index=0, - Type="SetProject" - ) - task = Task(Index=0, Type="SetProject", Input=set_project_request, Output=set_project_response) - self.SendTask(task) - return task - - def set_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: - # Set scan group properties. - set_group_request = MF_V3_Tasks_SetGroup.Request( - Index=0, - Type="SetGroup", - Input=MF_V3_Settings_Group_Group( - index=index, - color=color, - rotation=rotation, - translation=translation, - name=name, - visible=visible, - collapsed=collapsed, - ) - ) - set_group_response = MF_V3_Tasks_SetGroup.Response( - Index=0, - Type="SetGroup", - Input=MF_V3_Settings_Group_Group( - index=index, - color=color, - rotation=rotation, - translation=translation, - name=name, - visible=visible, - collapsed=collapsed, - ), - Output=None - ) - task = Task(Index=0, Type="SetGroup", Input=set_group_request, Output=set_group_response) - self.SendTask(task) - return task - - def new_group(self, color: float, rotation: float, translation: float, parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None) -> Task: - # Create a new scan group. - new_group_request = MF_V3_Tasks_NewGroup.Request( - Index=0, - Type="NewGroup", - Input=MF_V3_Settings_NewGroup_NewGroup( - color=color, - rotation=rotation, - translation=translation, - parentIndex=parentIndex, - baseName=baseName, - visible=visible, - collapsed=collapsed, - ) - ) - new_group_response = MF_V3_Tasks_NewGroup.Response( - Index=0, - Type="NewGroup", - Output=None - ) - task = Task(Index=0, Type="NewGroup", Input=new_group_request, Output=new_group_response) - self.SendTask(task) - return task - - def move_group(self, Input: int) -> Task: - # Move a scan group. - move_group_request = MF_V3_Tasks_MoveGroup.Request( - Index=0, - Type="MoveGroup", - Input=Input - ) - move_group_response = MF_V3_Tasks_MoveGroup.Response( - Index=0, - Type="MoveGroup", - Input=Input, - Output=None - ) - task = Task(Index=0, Type="MoveGroup", Input=move_group_request, Output=move_group_response) - self.SendTask(task) - return task - - def flatten_group(self, Input: int) -> Task: - # Flatten a scan group such that it only consists of single scans. - flatten_group_request = MF_V3_Tasks_FlattenGroup.Request( - Index=0, - Type="FlattenGroup", - Input=Input - ) - flatten_group_response = MF_V3_Tasks_FlattenGroup.Response( - Index=0, - Type="FlattenGroup", - Input=Input, - Output=None - ) - task = Task(Index=0, Type="FlattenGroup", Input=flatten_group_request, Output=flatten_group_response) - self.SendTask(task) - return task - - def split_group(self, Input: int) -> Task: - # Split a scan group (ie. move its subgroups to its parent group). - split_group_request = MF_V3_Tasks_SplitGroup.Request( - Index=0, - Type="SplitGroup", - Input=Input - ) - split_group_response = MF_V3_Tasks_SplitGroup.Response( - Index=0, - Type="SplitGroup", - Input=Input, - Output=None - ) - task = Task(Index=0, Type="SplitGroup", Input=split_group_request, Output=split_group_response) - self.SendTask(task) - return task - - def transform_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: - # Apply a rigid transformation to a group. - transform_group_request = MF_V3_Tasks_TransformGroup.Request( - Index=0, - Type="TransformGroup", - Input=MF_V3_Settings_Group_Group( - index=index, - color=color, - rotation=rotation, - translation=translation, - name=name, - visible=visible, - collapsed=collapsed, - ) - ) - transform_group_response = MF_V3_Tasks_TransformGroup.Response( - Index=0, - Type="TransformGroup", - Input=MF_V3_Settings_Group_Group( - index=index, - color=color, - rotation=rotation, - translation=translation, - name=name, - visible=visible, - collapsed=collapsed, - ), - Output=None - ) - task = Task(Index=0, Type="TransformGroup", Input=transform_group_request, Output=transform_group_response) - self.SendTask(task) - return task - - def remove_groups(self, Input: int) -> Task: - # Remove selected scan groups. - remove_groups_request = MF_V3_Tasks_RemoveGroups.Request( - Index=0, - Type="RemoveGroups", - Input=Input - ) - remove_groups_response = MF_V3_Tasks_RemoveGroups.Response( - Index=0, - Type="RemoveGroups", - Input=Input, - Output=None - ) - task = Task(Index=0, Type="RemoveGroups", Input=remove_groups_request, Output=remove_groups_response) - self.SendTask(task) - return task - - def bounding_box(self, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool) -> Task: - # Get the bounding box of a set of scan groups. - bounding_box_request = MF_V3_Tasks_BoundingBox.Request( - Index=0, - Type="BoundingBox", - Input=MF_V3_Settings_BoundingBox_BoundingBox( - selection=selection, - axisAligned=axisAligned, - ) - ) - bounding_box_response = MF_V3_Tasks_BoundingBox.Response( - Index=0, - Type="BoundingBox", - Input=MF_V3_Settings_BoundingBox_BoundingBox( - selection=selection, - axisAligned=axisAligned, - ), - Output=None - ) - task = Task(Index=0, Type="BoundingBox", Input=bounding_box_request, Output=bounding_box_response) - self.SendTask(task) - return task - - def align(self, source: int, target: int, rough: MF_V3_Settings_Align_Align.Rough = None, fine: MF_V3_Settings_Align_Align.Fine = None) -> Task: - # Align two scan groups. - align_request = MF_V3_Tasks_Align.Request( - Index=0, - Type="Align", - Input=MF_V3_Settings_Align_Align( - source=source, - target=target, - rough=rough, - fine=fine, - ) - ) - align_response = MF_V3_Tasks_Align.Response( - Index=0, - Type="Align", - Input=MF_V3_Settings_Align_Align( - source=source, - target=target, - rough=rough, - fine=fine, - ), - Output=None - ) - task = Task(Index=0, Type="Align", Input=align_request, Output=align_response) - self.SendTask(task) - return task - - def merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: MF_V3_Settings_Merge_Merge.Remesh = None, simplify: MF_V3_Settings_Merge_Merge.Simplify = None, texturize: bool = None) -> Task: - # Merge two or more scan groups. - merge_request = MF_V3_Tasks_Merge.Request( - Index=0, - Type="Merge", - Input=MF_V3_Settings_Merge_Merge( - selection=selection, - remesh=remesh, - simplify=simplify, - texturize=texturize, - ) - ) - merge_response = MF_V3_Tasks_Merge.Response( - Index=0, - Type="Merge", - Input=MF_V3_Settings_Merge_Merge( - selection=selection, - remesh=remesh, - simplify=simplify, - texturize=texturize, - ), - Output=None - ) - task = Task(Index=0, Type="Merge", Input=merge_request, Output=merge_response) - self.SendTask(task) - return task - - def merge_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: - # Download the raw scan data for the current merge process. - merge_data_request = MF_V3_Tasks_MergeData.Request( - Index=0, - Type="MergeData", - Input=MF_V3_Settings_ScanData_ScanData( - index=index, - buffers=buffers, - metadata=metadata, - mergeStep=mergeStep, - ) - ) - merge_data_response = MF_V3_Tasks_MergeData.Response( - Index=0, - Type="MergeData", - Input=MF_V3_Settings_ScanData_ScanData( - index=index, - buffers=buffers, - metadata=metadata, - mergeStep=mergeStep, - ), - Output=None - ) - task = Task(Index=0, Type="MergeData", Input=merge_data_request, Output=merge_data_response) - self.SendTask(task) - return task - - def add_merge_to_project(self) -> Task: - # Add a merged scan to the current project. - add_merge_to_project_request = MF_V3_Tasks_AddMergeToProject.Request( - Index=0, - Type="AddMergeToProject" - ) - add_merge_to_project_response = MF_V3_Tasks_AddMergeToProject.Response( - Index=0, - Type="AddMergeToProject", - Output=None - ) - task = Task(Index=0, Type="AddMergeToProject", Input=add_merge_to_project_request, Output=add_merge_to_project_response) - self.SendTask(task) - return task - - def list_export_formats(self) -> Task: - # List all export formats. - list_export_formats_request = MF_V3_Tasks_ListExportFormats.Request( - Index=0, - Type="ListExportFormats" - ) - list_export_formats_response = MF_V3_Tasks_ListExportFormats.Response( - Index=0, - Type="ListExportFormats", - Output=None - ) - task = Task(Index=0, Type="ListExportFormats", Input=list_export_formats_request, Output=list_export_formats_response) - self.SendTask(task) - return task - - def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: - # Export a group of scans. - export_request = MF_V3_Tasks_Export.Request( - Index=0, - Type="Export", - Input=MF_V3_Settings_Export_Export( - selection=selection, - texture=texture, - merge=merge, - format=format, - ) - ) - export_response = MF_V3_Tasks_Export.Response( - Index=0, - Type="Export", - Input=MF_V3_Settings_Export_Export( - selection=selection, - texture=texture, - merge=merge, - format=format, - ) - ) - task = Task(Index=0, Type="Export", Input=export_request, Output=export_response) - self.SendTask(task) - return task - - def export_merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: - # Export a merged scan. - export_merge_request = MF_V3_Tasks_ExportMerge.Request( - Index=0, - Type="ExportMerge", - Input=MF_V3_Settings_Export_Export( - selection=selection, - texture=texture, - merge=merge, - format=format, - ) - ) - export_merge_response = MF_V3_Tasks_ExportMerge.Response( - Index=0, - Type="ExportMerge", - Input=MF_V3_Settings_Export_Export( - selection=selection, - texture=texture, - merge=merge, - format=format, - ) - ) - task = Task(Index=0, Type="ExportMerge", Input=export_merge_request, Output=export_merge_response) - self.SendTask(task) - return task - - def export_logs(self, Input: bool = None) -> Task: - # Export scanner logs. - export_logs_request = MF_V3_Tasks_ExportLogs.Request( - Index=0, - Type="ExportLogs", - Input=Input - ) - export_logs_response = MF_V3_Tasks_ExportLogs.Response( - Index=0, - Type="ExportLogs" - ) - task = Task(Index=0, Type="ExportLogs", Input=export_logs_request, Output=export_logs_response) - self.SendTask(task) - return task - - def has_cameras(self) -> Task: - # Check if the scanner has working cameras. - has_cameras_request = MF_V3_Tasks_HasCameras.Request( - Index=0, - Type="HasCameras" - ) - has_cameras_response = MF_V3_Tasks_HasCameras.Response( - Index=0, - Type="HasCameras" - ) - task = Task(Index=0, Type="HasCameras", Input=has_cameras_request, Output=has_cameras_response) - self.SendTask(task) - return task - - def has_projector(self) -> Task: - # Check if the scanner has a working projector. - has_projector_request = MF_V3_Tasks_HasProjector.Request( - Index=0, - Type="HasProjector" - ) - has_projector_response = MF_V3_Tasks_HasProjector.Response( - Index=0, - Type="HasProjector" - ) - task = Task(Index=0, Type="HasProjector", Input=has_projector_request, Output=has_projector_response) - self.SendTask(task) - return task - - def has_turntable(self) -> Task: - # Check if the scanner is connected to a working turntable. - has_turntable_request = MF_V3_Tasks_HasTurntable.Request( - Index=0, - Type="HasTurntable" - ) - has_turntable_response = MF_V3_Tasks_HasTurntable.Response( - Index=0, - Type="HasTurntable" - ) - task = Task(Index=0, Type="HasTurntable", Input=has_turntable_request, Output=has_turntable_response) - self.SendTask(task) - return task - - def system_info(self, installed: MF_V3_Settings_Software_Software.Package, available: MF_V3_Settings_Software_Software.Package, nightlyIncluded: bool = None) -> Task: - # Get system information. - system_info_request = MF_V3_Tasks_SystemInfo.Request( - Index=0, - Type="SystemInfo", - Input=MF_V3_Settings_Software_Software( - installed=installed, - available=available, - nightlyIncluded=nightlyIncluded, - ) - ) - system_info_response = MF_V3_Tasks_SystemInfo.Response( - Index=0, - Type="SystemInfo", - Output=None - ) - task = Task(Index=0, Type="SystemInfo", Input=system_info_request, Output=system_info_response) - self.SendTask(task) - return task - - def camera_calibration(self) -> Task: - # Get the camera calibration descriptor. - camera_calibration_request = MF_V3_Tasks_CameraCalibration.Request( - Index=0, - Type="CameraCalibration" - ) - camera_calibration_response = MF_V3_Tasks_CameraCalibration.Response( - Index=0, - Type="CameraCalibration" - ) - task = Task(Index=0, Type="CameraCalibration", Input=camera_calibration_request, Output=camera_calibration_response) - self.SendTask(task) - return task - - def turntable_calibration(self) -> Task: - # Get the turntable calibration descriptor. - turntable_calibration_request = MF_V3_Tasks_TurntableCalibration.Request( - Index=0, - Type="TurntableCalibration" - ) - turntable_calibration_response = MF_V3_Tasks_TurntableCalibration.Response( - Index=0, - Type="TurntableCalibration" - ) - task = Task(Index=0, Type="TurntableCalibration", Input=turntable_calibration_request, Output=turntable_calibration_response) - self.SendTask(task) - return task - - def calibration_capture_targets(self) -> Task: - # Get the calibration capture target for each camera calibration capture. - calibration_capture_targets_request = MF_V3_Tasks_CalibrationCaptureTargets.Request( - Index=0, - Type="CalibrationCaptureTargets" - ) - calibration_capture_targets_response = MF_V3_Tasks_CalibrationCaptureTargets.Response( - Index=0, - Type="CalibrationCaptureTargets" - ) - task = Task(Index=0, Type="CalibrationCaptureTargets", Input=calibration_capture_targets_request, Output=calibration_capture_targets_response) - self.SendTask(task) - return task - - def calibrate_cameras(self) -> Task: - # Calibrate the cameras. - calibrate_cameras_request = MF_V3_Tasks_CalibrateCameras.Request( - Index=0, - Type="CalibrateCameras" - ) - calibrate_cameras_response = MF_V3_Tasks_CalibrateCameras.Response( - Index=0, - Type="CalibrateCameras" - ) - task = Task(Index=0, Type="CalibrateCameras", Input=calibrate_cameras_request, Output=calibrate_cameras_response) - self.SendTask(task) - return task - - def calibrate_turntable(self) -> Task: - # Calibrate the turntable. - calibrate_turntable_request = MF_V3_Tasks_CalibrateTurntable.Request( - Index=0, - Type="CalibrateTurntable" - ) - calibrate_turntable_response = MF_V3_Tasks_CalibrateTurntable.Response( - Index=0, - Type="CalibrateTurntable" - ) - task = Task(Index=0, Type="CalibrateTurntable", Input=calibrate_turntable_request, Output=calibrate_turntable_response) - self.SendTask(task) - return task - - def detect_calibration_card(self, Input: int) -> Task: - # Detect the calibration card on one or both cameras. - detect_calibration_card_request = MF_V3_Tasks_DetectCalibrationCard.Request( - Index=0, - Type="DetectCalibrationCard", - Input=Input - ) - detect_calibration_card_response = MF_V3_Tasks_DetectCalibrationCard.Response( - Index=0, - Type="DetectCalibrationCard", - Input=Input - ) - task = Task(Index=0, Type="DetectCalibrationCard", Input=detect_calibration_card_request, Output=detect_calibration_card_response) - self.SendTask(task) - return task - - def restore_factory_calibration(self) -> Task: - # Restore factory calibration. - restore_factory_calibration_request = MF_V3_Tasks_RestoreFactoryCalibration.Request( - Index=0, - Type="RestoreFactoryCalibration" - ) - restore_factory_calibration_response = MF_V3_Tasks_RestoreFactoryCalibration.Response( - Index=0, - Type="RestoreFactoryCalibration" - ) - task = Task(Index=0, Type="RestoreFactoryCalibration", Input=restore_factory_calibration_request, Output=restore_factory_calibration_response) - self.SendTask(task) - return task - - def start_video(self) -> Task: - # Start the video stream. - start_video_request = MF_V3_Tasks_StartVideo.Request( - Index=0, - Type="StartVideo" - ) - start_video_response = MF_V3_Tasks_StartVideo.Response( - Index=0, - Type="StartVideo" - ) - task = Task(Index=0, Type="StartVideo", Input=start_video_request, Output=start_video_response) - self.SendTask(task) - return task - - def stop_video(self) -> Task: - # Stop the video stream. - stop_video_request = MF_V3_Tasks_StopVideo.Request( - Index=0, - Type="StopVideo" - ) - stop_video_response = MF_V3_Tasks_StopVideo.Response( - Index=0, - Type="StopVideo" - ) - task = Task(Index=0, Type="StopVideo", Input=stop_video_request, Output=stop_video_response) - self.SendTask(task) - return task - - def set_cameras(self, selection: int, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> Task: - # Apply camera settings to one or both cameras. - set_cameras_request = MF_V3_Tasks_SetCameras.Request( - Index=0, - Type="SetCameras", - Input=MF_V3_Settings_Camera_Camera( - selection=selection, - autoExposure=autoExposure, - exposure=exposure, - analogGain=analogGain, - digitalGain=digitalGain, - focus=focus, - ) - ) - set_cameras_response = MF_V3_Tasks_SetCameras.Response( - Index=0, - Type="SetCameras" - ) - task = Task(Index=0, Type="SetCameras", Input=set_cameras_request, Output=set_cameras_response) - self.SendTask(task) - return task - - def set_projector(self, color: float, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None) -> Task: - # Apply projector settings. - set_projector_request = MF_V3_Tasks_SetProjector.Request( - Index=0, - Type="SetProjector", - Input=MF_V3_Settings_Projector_Projector( - color=color, - on=on, - brightness=brightness, - pattern=pattern, - image=image, - ) - ) - set_projector_response = MF_V3_Tasks_SetProjector.Response( - Index=0, - Type="SetProjector" - ) - task = Task(Index=0, Type="SetProjector", Input=set_projector_request, Output=set_projector_response) - self.SendTask(task) - return task - - def auto_focus(self, cameras: MF_V3_Settings_AutoFocus_AutoFocus.Camera, applyAll: bool) -> Task: - # Auto focus one or both cameras. - auto_focus_request = MF_V3_Tasks_AutoFocus.Request( - Index=0, - Type="AutoFocus", - Input=MF_V3_Settings_AutoFocus_AutoFocus( - cameras=cameras, - applyAll=applyAll, - ) - ) - auto_focus_response = MF_V3_Tasks_AutoFocus.Response( - Index=0, - Type="AutoFocus" - ) - task = Task(Index=0, Type="AutoFocus", Input=auto_focus_request, Output=auto_focus_response) - self.SendTask(task) - return task - - def rotate_turntable(self, Input: int) -> Task: - # Rotate the turntable. - rotate_turntable_request = MF_V3_Tasks_RotateTurntable.Request( - Index=0, - Type="RotateTurntable", - Input=Input - ) - rotate_turntable_response = MF_V3_Tasks_RotateTurntable.Response( - Index=0, - Type="RotateTurntable", - Input=Input - ) - task = Task(Index=0, Type="RotateTurntable", Input=rotate_turntable_request, Output=rotate_turntable_response) - self.SendTask(task) - return task - - def new_scan(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: - # Capture a new scan. - new_scan_request = MF_V3_Tasks_NewScan.Request( - Index=0, - Type="NewScan", - Input=MF_V3_Settings_Scan_Scan( - camera=camera, - projector=projector, - turntable=turntable, - capture=capture, - processing=processing, - ) - ) - new_scan_response = MF_V3_Tasks_NewScan.Response( - Index=0, - Type="NewScan" - ) - task = Task(Index=0, Type="NewScan", Input=new_scan_request, Output=new_scan_response) - self.SendTask(task) - return task - - def depth_map(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: - # Capture a depth map. - depth_map_request = MF_V3_Tasks_DepthMap.Request( - Index=0, - Type="DepthMap", - Input=MF_V3_Settings_Scan_Scan( - camera=camera, - projector=projector, - turntable=turntable, - capture=capture, - processing=processing, - ) - ) - depth_map_response = MF_V3_Tasks_DepthMap.Response( - Index=0, - Type="DepthMap", - Output=None - ) - task = Task(Index=0, Type="DepthMap", Input=depth_map_request, Output=depth_map_response) - self.SendTask(task) - return task - - def reboot(self) -> Task: - # Reboot the scanner. - reboot_request = MF_V3_Tasks_Reboot.Request( - Index=0, - Type="Reboot" - ) - reboot_response = MF_V3_Tasks_Reboot.Response( - Index=0, - Type="Reboot" - ) - task = Task(Index=0, Type="Reboot", Input=reboot_request, Output=reboot_response) - self.SendTask(task) - return task - - def shutdown(self) -> Task: - # Shutdown the scanner. - shutdown_request = MF_V3_Tasks_Shutdown.Request( - Index=0, - Type="Shutdown" - ) - shutdown_response = MF_V3_Tasks_Shutdown.Response( - Index=0, - Type="Shutdown" - ) - task = Task(Index=0, Type="Shutdown", Input=shutdown_request, Output=shutdown_response) - self.SendTask(task) - return task +def list_network_interfaces(self) -> Task: + # List available wifi networks. + list_network_interfaces_request = MF_V3_Tasks_ListNetworkInterfaces.Request( + Index=0, + Type="ListNetworkInterfaces" + ) + list_network_interfaces_response = MF_V3_Tasks_ListNetworkInterfaces.Response( + Index=0, + Type="ListNetworkInterfaces" + ) + task = Task(Index=0, Type="ListNetworkInterfaces", Input=list_network_interfaces_request, Output=list_network_interfaces_response) + self.SendTask(task) + return task + + +def list_wifi(self) -> Task: + # List available wifi networks. + list_wifi_request = MF_V3_Tasks_ListWifi.Request( + Index=0, + Type="ListWifi" + ) + list_wifi_response = MF_V3_Tasks_ListWifi.Response( + Index=0, + Type="ListWifi" + ) + task = Task(Index=0, Type="ListWifi", Input=list_wifi_request, Output=list_wifi_response) + self.SendTask(task) + return task + + +def connect_wifi(self, ssid: str, password: str) -> Task: + # Connect to a wifi network. + connect_wifi_request = MF_V3_Tasks_ConnectWifi.Request( + Index=0, + Type="ConnectWifi", + Input=MF_V3_Settings_Wifi_Wifi( + ssid=ssid, + password=password, + ) + ) + connect_wifi_response = MF_V3_Tasks_ConnectWifi.Response( + Index=0, + Type="ConnectWifi", + Input=MF_V3_Settings_Wifi_Wifi( + ssid=ssid, + password=password, + ) + ) + task = Task(Index=0, Type="ConnectWifi", Input=connect_wifi_request, Output=connect_wifi_response) + self.SendTask(task) + return task + + +def forget_wifi(self) -> Task: + # Forget all wifi connections. + forget_wifi_request = MF_V3_Tasks_ForgetWifi.Request( + Index=0, + Type="ForgetWifi" + ) + forget_wifi_response = MF_V3_Tasks_ForgetWifi.Response( + Index=0, + Type="ForgetWifi" + ) + task = Task(Index=0, Type="ForgetWifi", Input=forget_wifi_request, Output=forget_wifi_response) + self.SendTask(task) + return task + + +def list_settings(self) -> Task: + # Get scanner settings. + list_settings_request = MF_V3_Tasks_ListSettings.Request( + Index=0, + Type="ListSettings" + ) + list_settings_response = MF_V3_Tasks_ListSettings.Response( + Index=0, + Type="ListSettings" + ) + task = Task(Index=0, Type="ListSettings", Input=list_settings_request, Output=list_settings_response) + self.SendTask(task) + return task + + +def push_settings(self) -> Task: + # Push the current scanner settings to the settings stack. + push_settings_request = MF_V3_Tasks_PushSettings.Request( + Index=0, + Type="PushSettings" + ) + push_settings_response = MF_V3_Tasks_PushSettings.Response( + Index=0, + Type="PushSettings" + ) + task = Task(Index=0, Type="PushSettings", Input=push_settings_request, Output=push_settings_response) + self.SendTask(task) + return task + + +def pop_settings(self, Input: bool = None) -> Task: + # Pop and restore scanner settings from the settings stack. + pop_settings_request = MF_V3_Tasks_PopSettings.Request( + Index=0, + Type="PopSettings", + Input=Input + ) + pop_settings_response = MF_V3_Tasks_PopSettings.Response( + Index=0, + Type="PopSettings" + ) + task = Task(Index=0, Type="PopSettings", Input=pop_settings_request, Output=pop_settings_response) + self.SendTask(task) + return task + + +def update_settings(self, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None) -> Task: + # Update scanner settings. + update_settings_request = MF_V3_Tasks_UpdateSettings.Request( + Index=0, + Type="UpdateSettings", + Input=MF_V3_Settings_Scanner_Scanner( + advanced=advanced, + camera=camera, + capture=capture, + i18n=i18n, + projector=projector, + style=style, + turntable=turntable, + tutorials=tutorials, + viewer=viewer, + software=software, + ) + ) + update_settings_response = MF_V3_Tasks_UpdateSettings.Response( + Index=0, + Type="UpdateSettings", + Input=MF_V3_Settings_Scanner_Scanner( + advanced=advanced, + camera=camera, + capture=capture, + i18n=i18n, + projector=projector, + style=style, + turntable=turntable, + tutorials=tutorials, + viewer=viewer, + software=software, + ) + ) + task = Task(Index=0, Type="UpdateSettings", Input=update_settings_request, Output=update_settings_response) + self.SendTask(task) + return task + + +def list_projects(self) -> Task: + # List all projects. + list_projects_request = MF_V3_Tasks_ListProjects.Request( + Index=0, + Type="ListProjects" + ) + list_projects_response = MF_V3_Tasks_ListProjects.Response( + Index=0, + Type="ListProjects" + ) + task = Task(Index=0, Type="ListProjects", Input=list_projects_request, Output=list_projects_response) + self.SendTask(task) + return task + + +def download_project(self, Input: int) -> Task: + # Download a project from the scanner. + download_project_request = MF_V3_Tasks_DownloadProject.Request( + Index=0, + Type="DownloadProject", + Input=Input + ) + download_project_response = MF_V3_Tasks_DownloadProject.Response( + Index=0, + Type="DownloadProject", + Input=Input + ) + task = Task(Index=0, Type="DownloadProject", Input=download_project_request, Output=download_project_response) + self.SendTask(task) + return task + + +def upload_project(self) -> Task: + # Upload a project to the scanner. + upload_project_request = MF_V3_Tasks_UploadProject.Request( + Index=0, + Type="UploadProject" + ) + upload_project_response = MF_V3_Tasks_UploadProject.Response( + Index=0, + Type="UploadProject" + ) + task = Task(Index=0, Type="UploadProject", Input=upload_project_request, Output=upload_project_response) + self.SendTask(task) + return task + + +def new_project(self, Input: str = None) -> Task: + # Create a new project. + new_project_request = MF_V3_Tasks_NewProject.Request( + Index=0, + Type="NewProject", + Input=Input + ) + new_project_response = MF_V3_Tasks_NewProject.Response( + Index=0, + Type="NewProject" + ) + task = Task(Index=0, Type="NewProject", Input=new_project_request, Output=new_project_response) + self.SendTask(task) + return task + + +def open_project(self, Input: int) -> Task: + # Open an existing project. + open_project_request = MF_V3_Tasks_OpenProject.Request( + Index=0, + Type="OpenProject", + Input=Input + ) + open_project_response = MF_V3_Tasks_OpenProject.Response( + Index=0, + Type="OpenProject", + Input=Input + ) + task = Task(Index=0, Type="OpenProject", Input=open_project_request, Output=open_project_response) + self.SendTask(task) + return task + + +def close_project(self) -> Task: + # Close the current open project. + close_project_request = MF_V3_Tasks_CloseProject.Request( + Index=0, + Type="CloseProject" + ) + close_project_response = MF_V3_Tasks_CloseProject.Response( + Index=0, + Type="CloseProject" + ) + task = Task(Index=0, Type="CloseProject", Input=close_project_request, Output=close_project_response) + self.SendTask(task) + return task + + +def remove_projects(self, Input: int) -> Task: + # Remove selected projects. + remove_projects_request = MF_V3_Tasks_RemoveProjects.Request( + Index=0, + Type="RemoveProjects", + Input=Input + ) + remove_projects_response = MF_V3_Tasks_RemoveProjects.Response( + Index=0, + Type="RemoveProjects", + Input=Input + ) + task = Task(Index=0, Type="RemoveProjects", Input=remove_projects_request, Output=remove_projects_response) + self.SendTask(task) + return task + + +def list_groups(self) -> Task: + # List the scan groups in the current open project. + list_groups_request = MF_V3_Tasks_ListGroups.Request( + Index=0, + Type="ListGroups" + ) + list_groups_response = MF_V3_Tasks_ListGroups.Response( + Index=0, + Type="ListGroups", + Output=None + ) + task = Task(Index=0, Type="ListGroups", Input=list_groups_request, Output=list_groups_response) + self.SendTask(task) + return task + + +def list_scans(self) -> Task: + # List the scans in the current open project. + list_scans_request = MF_V3_Tasks_ListScans.Request( + Index=0, + Type="ListScans" + ) + list_scans_response = MF_V3_Tasks_ListScans.Response( + Index=0, + Type="ListScans", + Output=None + ) + task = Task(Index=0, Type="ListScans", Input=list_scans_request, Output=list_scans_response) + self.SendTask(task) + return task + + +def scan_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: + # Download the raw scan data for a scan in the current open project. + scan_data_request = MF_V3_Tasks_ScanData.Request( + Index=0, + Type="ScanData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + buffers=buffers, + metadata=metadata, + mergeStep=mergeStep, + ) + ) + scan_data_response = MF_V3_Tasks_ScanData.Response( + Index=0, + Type="ScanData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + buffers=buffers, + metadata=metadata, + mergeStep=mergeStep, + ), + Output=None + ) + task = Task(Index=0, Type="ScanData", Input=scan_data_request, Output=scan_data_response) + self.SendTask(task) + return task + + +def set_project(self, index: int = None, name: str = None) -> Task: + # Apply settings to the current open project. + set_project_request = MF_V3_Tasks_SetProject.Request( + Index=0, + Type="SetProject", + Input=MF_V3_Settings_Project_Project( + index=index, + name=name, + ) + ) + set_project_response = MF_V3_Tasks_SetProject.Response( + Index=0, + Type="SetProject" + ) + task = Task(Index=0, Type="SetProject", Input=set_project_request, Output=set_project_response) + self.SendTask(task) + return task + + +def set_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: + # Set scan group properties. + set_group_request = MF_V3_Tasks_SetGroup.Request( + Index=0, + Type="SetGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + color=color, + rotation=rotation, + translation=translation, + name=name, + visible=visible, + collapsed=collapsed, + ) + ) + set_group_response = MF_V3_Tasks_SetGroup.Response( + Index=0, + Type="SetGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + color=color, + rotation=rotation, + translation=translation, + name=name, + visible=visible, + collapsed=collapsed, + ), + Output=None + ) + task = Task(Index=0, Type="SetGroup", Input=set_group_request, Output=set_group_response) + self.SendTask(task) + return task + + +def new_group(self, color: float, rotation: float, translation: float, parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None) -> Task: + # Create a new scan group. + new_group_request = MF_V3_Tasks_NewGroup.Request( + Index=0, + Type="NewGroup", + Input=MF_V3_Settings_NewGroup_NewGroup( + color=color, + rotation=rotation, + translation=translation, + parentIndex=parentIndex, + baseName=baseName, + visible=visible, + collapsed=collapsed, + ) + ) + new_group_response = MF_V3_Tasks_NewGroup.Response( + Index=0, + Type="NewGroup", + Output=None + ) + task = Task(Index=0, Type="NewGroup", Input=new_group_request, Output=new_group_response) + self.SendTask(task) + return task + + +def move_group(self, Input: int) -> Task: + # Move a scan group. + move_group_request = MF_V3_Tasks_MoveGroup.Request( + Index=0, + Type="MoveGroup", + Input=Input + ) + move_group_response = MF_V3_Tasks_MoveGroup.Response( + Index=0, + Type="MoveGroup", + Input=Input, + Output=None + ) + task = Task(Index=0, Type="MoveGroup", Input=move_group_request, Output=move_group_response) + self.SendTask(task) + return task + + +def flatten_group(self, Input: int) -> Task: + # Flatten a scan group such that it only consists of single scans. + flatten_group_request = MF_V3_Tasks_FlattenGroup.Request( + Index=0, + Type="FlattenGroup", + Input=Input + ) + flatten_group_response = MF_V3_Tasks_FlattenGroup.Response( + Index=0, + Type="FlattenGroup", + Input=Input, + Output=None + ) + task = Task(Index=0, Type="FlattenGroup", Input=flatten_group_request, Output=flatten_group_response) + self.SendTask(task) + return task + + +def split_group(self, Input: int) -> Task: + # Split a scan group (ie. move its subgroups to its parent group). + split_group_request = MF_V3_Tasks_SplitGroup.Request( + Index=0, + Type="SplitGroup", + Input=Input + ) + split_group_response = MF_V3_Tasks_SplitGroup.Response( + Index=0, + Type="SplitGroup", + Input=Input, + Output=None + ) + task = Task(Index=0, Type="SplitGroup", Input=split_group_request, Output=split_group_response) + self.SendTask(task) + return task + + +def transform_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: + # Apply a rigid transformation to a group. + transform_group_request = MF_V3_Tasks_TransformGroup.Request( + Index=0, + Type="TransformGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + color=color, + rotation=rotation, + translation=translation, + name=name, + visible=visible, + collapsed=collapsed, + ) + ) + transform_group_response = MF_V3_Tasks_TransformGroup.Response( + Index=0, + Type="TransformGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + color=color, + rotation=rotation, + translation=translation, + name=name, + visible=visible, + collapsed=collapsed, + ), + Output=None + ) + task = Task(Index=0, Type="TransformGroup", Input=transform_group_request, Output=transform_group_response) + self.SendTask(task) + return task + + +def remove_groups(self, Input: int) -> Task: + # Remove selected scan groups. + remove_groups_request = MF_V3_Tasks_RemoveGroups.Request( + Index=0, + Type="RemoveGroups", + Input=Input + ) + remove_groups_response = MF_V3_Tasks_RemoveGroups.Response( + Index=0, + Type="RemoveGroups", + Input=Input, + Output=None + ) + task = Task(Index=0, Type="RemoveGroups", Input=remove_groups_request, Output=remove_groups_response) + self.SendTask(task) + return task + + +def bounding_box(self, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool) -> Task: + # Get the bounding box of a set of scan groups. + bounding_box_request = MF_V3_Tasks_BoundingBox.Request( + Index=0, + Type="BoundingBox", + Input=MF_V3_Settings_BoundingBox_BoundingBox( + selection=selection, + axisAligned=axisAligned, + ) + ) + bounding_box_response = MF_V3_Tasks_BoundingBox.Response( + Index=0, + Type="BoundingBox", + Input=MF_V3_Settings_BoundingBox_BoundingBox( + selection=selection, + axisAligned=axisAligned, + ), + Output=None + ) + task = Task(Index=0, Type="BoundingBox", Input=bounding_box_request, Output=bounding_box_response) + self.SendTask(task) + return task + + +def align(self, source: int, target: int, rough: MF_V3_Settings_Align_Align.Rough = None, fine: MF_V3_Settings_Align_Align.Fine = None) -> Task: + # Align two scan groups. + align_request = MF_V3_Tasks_Align.Request( + Index=0, + Type="Align", + Input=MF_V3_Settings_Align_Align( + source=source, + target=target, + rough=rough, + fine=fine, + ) + ) + align_response = MF_V3_Tasks_Align.Response( + Index=0, + Type="Align", + Input=MF_V3_Settings_Align_Align( + source=source, + target=target, + rough=rough, + fine=fine, + ), + Output=None + ) + task = Task(Index=0, Type="Align", Input=align_request, Output=align_response) + self.SendTask(task) + return task + + +def merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: MF_V3_Settings_Merge_Merge.Remesh = None, simplify: MF_V3_Settings_Merge_Merge.Simplify = None, texturize: bool = None) -> Task: + # Merge two or more scan groups. + merge_request = MF_V3_Tasks_Merge.Request( + Index=0, + Type="Merge", + Input=MF_V3_Settings_Merge_Merge( + selection=selection, + remesh=remesh, + simplify=simplify, + texturize=texturize, + ) + ) + merge_response = MF_V3_Tasks_Merge.Response( + Index=0, + Type="Merge", + Input=MF_V3_Settings_Merge_Merge( + selection=selection, + remesh=remesh, + simplify=simplify, + texturize=texturize, + ), + Output=None + ) + task = Task(Index=0, Type="Merge", Input=merge_request, Output=merge_response) + self.SendTask(task) + return task + + +def merge_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: + # Download the raw scan data for the current merge process. + merge_data_request = MF_V3_Tasks_MergeData.Request( + Index=0, + Type="MergeData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + buffers=buffers, + metadata=metadata, + mergeStep=mergeStep, + ) + ) + merge_data_response = MF_V3_Tasks_MergeData.Response( + Index=0, + Type="MergeData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + buffers=buffers, + metadata=metadata, + mergeStep=mergeStep, + ), + Output=None + ) + task = Task(Index=0, Type="MergeData", Input=merge_data_request, Output=merge_data_response) + self.SendTask(task) + return task + + +def add_merge_to_project(self) -> Task: + # Add a merged scan to the current project. + add_merge_to_project_request = MF_V3_Tasks_AddMergeToProject.Request( + Index=0, + Type="AddMergeToProject" + ) + add_merge_to_project_response = MF_V3_Tasks_AddMergeToProject.Response( + Index=0, + Type="AddMergeToProject", + Output=None + ) + task = Task(Index=0, Type="AddMergeToProject", Input=add_merge_to_project_request, Output=add_merge_to_project_response) + self.SendTask(task) + return task + + +def list_export_formats(self) -> Task: + # List all export formats. + list_export_formats_request = MF_V3_Tasks_ListExportFormats.Request( + Index=0, + Type="ListExportFormats" + ) + list_export_formats_response = MF_V3_Tasks_ListExportFormats.Response( + Index=0, + Type="ListExportFormats", + Output=None + ) + task = Task(Index=0, Type="ListExportFormats", Input=list_export_formats_request, Output=list_export_formats_response) + self.SendTask(task) + return task + + +def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: + # Export a group of scans. + export_request = MF_V3_Tasks_Export.Request( + Index=0, + Type="Export", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + ) + ) + export_response = MF_V3_Tasks_Export.Response( + Index=0, + Type="Export", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + ) + ) + task = Task(Index=0, Type="Export", Input=export_request, Output=export_response) + self.SendTask(task) + return task + + +def export_merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: + # Export a merged scan. + export_merge_request = MF_V3_Tasks_ExportMerge.Request( + Index=0, + Type="ExportMerge", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + ) + ) + export_merge_response = MF_V3_Tasks_ExportMerge.Response( + Index=0, + Type="ExportMerge", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + ) + ) + task = Task(Index=0, Type="ExportMerge", Input=export_merge_request, Output=export_merge_response) + self.SendTask(task) + return task + + +def export_logs(self, Input: bool = None) -> Task: + # Export scanner logs. + export_logs_request = MF_V3_Tasks_ExportLogs.Request( + Index=0, + Type="ExportLogs", + Input=Input + ) + export_logs_response = MF_V3_Tasks_ExportLogs.Response( + Index=0, + Type="ExportLogs" + ) + task = Task(Index=0, Type="ExportLogs", Input=export_logs_request, Output=export_logs_response) + self.SendTask(task) + return task + + +def has_cameras(self) -> Task: + # Check if the scanner has working cameras. + has_cameras_request = MF_V3_Tasks_HasCameras.Request( + Index=0, + Type="HasCameras" + ) + has_cameras_response = MF_V3_Tasks_HasCameras.Response( + Index=0, + Type="HasCameras" + ) + task = Task(Index=0, Type="HasCameras", Input=has_cameras_request, Output=has_cameras_response) + self.SendTask(task) + return task + + +def has_projector(self) -> Task: + # Check if the scanner has a working projector. + has_projector_request = MF_V3_Tasks_HasProjector.Request( + Index=0, + Type="HasProjector" + ) + has_projector_response = MF_V3_Tasks_HasProjector.Response( + Index=0, + Type="HasProjector" + ) + task = Task(Index=0, Type="HasProjector", Input=has_projector_request, Output=has_projector_response) + self.SendTask(task) + return task + + +def has_turntable(self) -> Task: + # Check if the scanner is connected to a working turntable. + has_turntable_request = MF_V3_Tasks_HasTurntable.Request( + Index=0, + Type="HasTurntable" + ) + has_turntable_response = MF_V3_Tasks_HasTurntable.Response( + Index=0, + Type="HasTurntable" + ) + task = Task(Index=0, Type="HasTurntable", Input=has_turntable_request, Output=has_turntable_response) + self.SendTask(task) + return task + + +def system_info(self, installed: MF_V3_Settings_Software_Software.Package, available: MF_V3_Settings_Software_Software.Package, nightlyIncluded: bool = None) -> Task: + # Get system information. + system_info_request = MF_V3_Tasks_SystemInfo.Request( + Index=0, + Type="SystemInfo", + Input=MF_V3_Settings_Software_Software( + installed=installed, + available=available, + nightlyIncluded=nightlyIncluded, + ) + ) + system_info_response = MF_V3_Tasks_SystemInfo.Response( + Index=0, + Type="SystemInfo", + Output=None + ) + task = Task(Index=0, Type="SystemInfo", Input=system_info_request, Output=system_info_response) + self.SendTask(task) + return task + + +def camera_calibration(self) -> Task: + # Get the camera calibration descriptor. + camera_calibration_request = MF_V3_Tasks_CameraCalibration.Request( + Index=0, + Type="CameraCalibration" + ) + camera_calibration_response = MF_V3_Tasks_CameraCalibration.Response( + Index=0, + Type="CameraCalibration" + ) + task = Task(Index=0, Type="CameraCalibration", Input=camera_calibration_request, Output=camera_calibration_response) + self.SendTask(task) + return task + + +def turntable_calibration(self) -> Task: + # Get the turntable calibration descriptor. + turntable_calibration_request = MF_V3_Tasks_TurntableCalibration.Request( + Index=0, + Type="TurntableCalibration" + ) + turntable_calibration_response = MF_V3_Tasks_TurntableCalibration.Response( + Index=0, + Type="TurntableCalibration" + ) + task = Task(Index=0, Type="TurntableCalibration", Input=turntable_calibration_request, Output=turntable_calibration_response) + self.SendTask(task) + return task + + +def calibration_capture_targets(self) -> Task: + # Get the calibration capture target for each camera calibration capture. + calibration_capture_targets_request = MF_V3_Tasks_CalibrationCaptureTargets.Request( + Index=0, + Type="CalibrationCaptureTargets" + ) + calibration_capture_targets_response = MF_V3_Tasks_CalibrationCaptureTargets.Response( + Index=0, + Type="CalibrationCaptureTargets" + ) + task = Task(Index=0, Type="CalibrationCaptureTargets", Input=calibration_capture_targets_request, Output=calibration_capture_targets_response) + self.SendTask(task) + return task + + +def calibrate_cameras(self) -> Task: + # Calibrate the cameras. + calibrate_cameras_request = MF_V3_Tasks_CalibrateCameras.Request( + Index=0, + Type="CalibrateCameras" + ) + calibrate_cameras_response = MF_V3_Tasks_CalibrateCameras.Response( + Index=0, + Type="CalibrateCameras" + ) + task = Task(Index=0, Type="CalibrateCameras", Input=calibrate_cameras_request, Output=calibrate_cameras_response) + self.SendTask(task) + return task + + +def calibrate_turntable(self) -> Task: + # Calibrate the turntable. + calibrate_turntable_request = MF_V3_Tasks_CalibrateTurntable.Request( + Index=0, + Type="CalibrateTurntable" + ) + calibrate_turntable_response = MF_V3_Tasks_CalibrateTurntable.Response( + Index=0, + Type="CalibrateTurntable" + ) + task = Task(Index=0, Type="CalibrateTurntable", Input=calibrate_turntable_request, Output=calibrate_turntable_response) + self.SendTask(task) + return task + + +def detect_calibration_card(self, Input: int) -> Task: + # Detect the calibration card on one or both cameras. + detect_calibration_card_request = MF_V3_Tasks_DetectCalibrationCard.Request( + Index=0, + Type="DetectCalibrationCard", + Input=Input + ) + detect_calibration_card_response = MF_V3_Tasks_DetectCalibrationCard.Response( + Index=0, + Type="DetectCalibrationCard", + Input=Input + ) + task = Task(Index=0, Type="DetectCalibrationCard", Input=detect_calibration_card_request, Output=detect_calibration_card_response) + self.SendTask(task) + return task + + +def restore_factory_calibration(self) -> Task: + # Restore factory calibration. + restore_factory_calibration_request = MF_V3_Tasks_RestoreFactoryCalibration.Request( + Index=0, + Type="RestoreFactoryCalibration" + ) + restore_factory_calibration_response = MF_V3_Tasks_RestoreFactoryCalibration.Response( + Index=0, + Type="RestoreFactoryCalibration" + ) + task = Task(Index=0, Type="RestoreFactoryCalibration", Input=restore_factory_calibration_request, Output=restore_factory_calibration_response) + self.SendTask(task) + return task + + +def start_video(self) -> Task: + # Start the video stream. + start_video_request = MF_V3_Tasks_StartVideo.Request( + Index=0, + Type="StartVideo" + ) + start_video_response = MF_V3_Tasks_StartVideo.Response( + Index=0, + Type="StartVideo" + ) + task = Task(Index=0, Type="StartVideo", Input=start_video_request, Output=start_video_response) + self.SendTask(task) + return task + + +def stop_video(self) -> Task: + # Stop the video stream. + stop_video_request = MF_V3_Tasks_StopVideo.Request( + Index=0, + Type="StopVideo" + ) + stop_video_response = MF_V3_Tasks_StopVideo.Response( + Index=0, + Type="StopVideo" + ) + task = Task(Index=0, Type="StopVideo", Input=stop_video_request, Output=stop_video_response) + self.SendTask(task) + return task + + +def set_cameras(self, selection: int, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> Task: + # Apply camera settings to one or both cameras. + set_cameras_request = MF_V3_Tasks_SetCameras.Request( + Index=0, + Type="SetCameras", + Input=MF_V3_Settings_Camera_Camera( + selection=selection, + autoExposure=autoExposure, + exposure=exposure, + analogGain=analogGain, + digitalGain=digitalGain, + focus=focus, + ) + ) + set_cameras_response = MF_V3_Tasks_SetCameras.Response( + Index=0, + Type="SetCameras" + ) + task = Task(Index=0, Type="SetCameras", Input=set_cameras_request, Output=set_cameras_response) + self.SendTask(task) + return task + + +def set_projector(self, color: float, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None) -> Task: + # Apply projector settings. + set_projector_request = MF_V3_Tasks_SetProjector.Request( + Index=0, + Type="SetProjector", + Input=MF_V3_Settings_Projector_Projector( + color=color, + on=on, + brightness=brightness, + pattern=pattern, + image=image, + ) + ) + set_projector_response = MF_V3_Tasks_SetProjector.Response( + Index=0, + Type="SetProjector" + ) + task = Task(Index=0, Type="SetProjector", Input=set_projector_request, Output=set_projector_response) + self.SendTask(task) + return task + + +def auto_focus(self, cameras: MF_V3_Settings_AutoFocus_AutoFocus.Camera, applyAll: bool) -> Task: + # Auto focus one or both cameras. + auto_focus_request = MF_V3_Tasks_AutoFocus.Request( + Index=0, + Type="AutoFocus", + Input=MF_V3_Settings_AutoFocus_AutoFocus( + cameras=cameras, + applyAll=applyAll, + ) + ) + auto_focus_response = MF_V3_Tasks_AutoFocus.Response( + Index=0, + Type="AutoFocus" + ) + task = Task(Index=0, Type="AutoFocus", Input=auto_focus_request, Output=auto_focus_response) + self.SendTask(task) + return task + + +def rotate_turntable(self, Input: int) -> Task: + # Rotate the turntable. + rotate_turntable_request = MF_V3_Tasks_RotateTurntable.Request( + Index=0, + Type="RotateTurntable", + Input=Input + ) + rotate_turntable_response = MF_V3_Tasks_RotateTurntable.Response( + Index=0, + Type="RotateTurntable", + Input=Input + ) + task = Task(Index=0, Type="RotateTurntable", Input=rotate_turntable_request, Output=rotate_turntable_response) + self.SendTask(task) + return task + + +def new_scan(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: + # Capture a new scan. + new_scan_request = MF_V3_Tasks_NewScan.Request( + Index=0, + Type="NewScan", + Input=MF_V3_Settings_Scan_Scan( + camera=camera, + projector=projector, + turntable=turntable, + capture=capture, + processing=processing, + ) + ) + new_scan_response = MF_V3_Tasks_NewScan.Response( + Index=0, + Type="NewScan" + ) + task = Task(Index=0, Type="NewScan", Input=new_scan_request, Output=new_scan_response) + self.SendTask(task) + return task + + +def depth_map(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: + # Capture a depth map. + depth_map_request = MF_V3_Tasks_DepthMap.Request( + Index=0, + Type="DepthMap", + Input=MF_V3_Settings_Scan_Scan( + camera=camera, + projector=projector, + turntable=turntable, + capture=capture, + processing=processing, + ) + ) + depth_map_response = MF_V3_Tasks_DepthMap.Response( + Index=0, + Type="DepthMap", + Output=None + ) + task = Task(Index=0, Type="DepthMap", Input=depth_map_request, Output=depth_map_response) + self.SendTask(task) + return task + + +def reboot(self) -> Task: + # Reboot the scanner. + reboot_request = MF_V3_Tasks_Reboot.Request( + Index=0, + Type="Reboot" + ) + reboot_response = MF_V3_Tasks_Reboot.Response( + Index=0, + Type="Reboot" + ) + task = Task(Index=0, Type="Reboot", Input=reboot_request, Output=reboot_response) + self.SendTask(task) + return task + + +def shutdown(self) -> Task: + # Shutdown the scanner. + shutdown_request = MF_V3_Tasks_Shutdown.Request( + Index=0, + Type="Shutdown" + ) + shutdown_response = MF_V3_Tasks_Shutdown.Response( + Index=0, + Type="Shutdown" + ) + task = Task(Index=0, Type="Shutdown", Input=shutdown_request, Output=shutdown_response) + self.SendTask(task) + return task + diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index 2388ae9..72ac1fe 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -9,14 +9,13 @@ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) from maf_three.scanner import Scanner - +import maf_three.MF.V3.Three as Three def main(): try: scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) scanner.Connect("ws://matterandform.local:8081") - scanner.set_projector(on=True, brightness=1.0, color=[1,1,1]) # Sleep for 5 seconds diff --git a/maf_three/scanner.py b/maf_three/scanner.py index c07782f..f8788dc 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -20,7 +20,7 @@ from maf_three.serialization import TO_JSON from maf_three.MF.V3.Buffer import Buffer -from maf_three.MF.V3.Three import Three +import maf_three.MF.V3.Three as Three class Scanner: """ @@ -59,12 +59,16 @@ def __init__(self, self.__task_return_event = threading.Event() - # Dynamically import and add functions from Three.py - Three_module = importlib.import_module('.Three', package='maf_three.MF.V3') - for name, func in inspect.getmembers(Three_module.Three, inspect.isfunction): - bound_func = types.MethodType(func, self) - setattr(self, name, bound_func) - + # Dynamically add methods from Three to Scanner + self._add_three_methods() + + def _add_three_methods(self): + """ + Dynamically adds functions from the three_methods module to the Scanner class. + """ + for name, func in inspect.getmembers(Three, predicate=inspect.isfunction): + if not name.startswith('_'): + setattr(self, name, func.__get__(self, self.__class__)) def Connect(self, URI:str, timeoutSec=5) -> bool: @@ -326,3 +330,9 @@ def __FindTaskWithIndex(self, index:int) -> Task: return t break return None + +if __name__ == "__main__": + scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) + scanner.Connect("ws://matterandform.local:8081") + + scanner.set_projector(on=True, brightness=1.0, color=[1,1,1]) \ No newline at end of file diff --git a/maf_three/scanner.pyi b/maf_three/scanner.pyi new file mode 100644 index 0000000..277a146 --- /dev/null +++ b/maf_three/scanner.pyi @@ -0,0 +1,162 @@ +import MF +import MF.V3 +import MF.V3.Settings +import MF.V3.Settings.Advanced +import MF.V3.Settings.Align +import MF.V3.Settings.AutoFocus +import MF.V3.Settings.BoundingBox +import MF.V3.Settings.Camera +import MF.V3.Settings.Capture +import MF.V3.Settings.Export +import MF.V3.Settings.Group +import MF.V3.Settings.I18n +import MF.V3.Settings.Merge +import MF.V3.Settings.NewGroup +import MF.V3.Settings.Project +import MF.V3.Settings.Projector +import MF.V3.Settings.Scan +import MF.V3.Settings.ScanData +import MF.V3.Settings.ScanSelection +import MF.V3.Settings.Scanner +import MF.V3.Settings.Software +import MF.V3.Settings.Style +import MF.V3.Settings.Turntable +import MF.V3.Settings.Tutorials +import MF.V3.Settings.Viewer +import MF.V3.Settings.Wifi +import MF.V3.Tasks +import MF.V3.Tasks.AddMergeToProject +import MF.V3.Tasks.Align +import MF.V3.Tasks.AutoFocus +import MF.V3.Tasks.BoundingBox +import MF.V3.Tasks.CalibrateCameras +import MF.V3.Tasks.CalibrateTurntable +import MF.V3.Tasks.CalibrationCaptureTargets +import MF.V3.Tasks.CameraCalibration +import MF.V3.Tasks.CloseProject +import MF.V3.Tasks.ConnectWifi +import MF.V3.Tasks.DepthMap +import MF.V3.Tasks.DetectCalibrationCard +import MF.V3.Tasks.DownloadProject +import MF.V3.Tasks.Export +import MF.V3.Tasks.ExportLogs +import MF.V3.Tasks.ExportMerge +import MF.V3.Tasks.FlattenGroup +import MF.V3.Tasks.ForgetWifi +import MF.V3.Tasks.HasCameras +import MF.V3.Tasks.HasProjector +import MF.V3.Tasks.HasTurntable +import MF.V3.Tasks.ListExportFormats +import MF.V3.Tasks.ListGroups +import MF.V3.Tasks.ListNetworkInterfaces +import MF.V3.Tasks.ListProjects +import MF.V3.Tasks.ListScans +import MF.V3.Tasks.ListSettings +import MF.V3.Tasks.ListWifi +import MF.V3.Tasks.Merge +import MF.V3.Tasks.MergeData +import MF.V3.Tasks.MoveGroup +import MF.V3.Tasks.NewGroup +import MF.V3.Tasks.NewProject +import MF.V3.Tasks.NewScan +import MF.V3.Tasks.OpenProject +import MF.V3.Tasks.PopSettings +import MF.V3.Tasks.PushSettings +import MF.V3.Tasks.Reboot +import MF.V3.Tasks.RemoveGroups +import MF.V3.Tasks.RemoveProjects +import MF.V3.Tasks.RestoreFactoryCalibration +import MF.V3.Tasks.RotateTurntable +import MF.V3.Tasks.ScanData +import MF.V3.Tasks.SetCameras +import MF.V3.Tasks.SetGroup +import MF.V3.Tasks.SetProject +import MF.V3.Tasks.SetProjector +import MF.V3.Tasks.Shutdown +import MF.V3.Tasks.SplitGroup +import MF.V3.Tasks.StartVideo +import MF.V3.Tasks.StopVideo +import MF.V3.Tasks.SystemInfo +import MF.V3.Tasks.TransformGroup +import MF.V3.Tasks.TurntableCalibration +import MF.V3.Tasks.UpdateSettings +import MF.V3.Tasks.UploadProject +import importlib +import inspect +import json +import maf_three +import maf_three.MF +import maf_three.MF.V3 +import maf_three.MF.V3.Buffer +import maf_three.MF.V3.Three +import maf_three.serialization +import threading +import time +import types +import typing +import websocket +from typing import Optional, Callable, Any, Union + + +class Scanner: + def __init__(self, OnTask: Optional[Callable[[MF.V3.Task.Task], None]] = None, OnMessage: Optional[Callable[[str], None]] = None, OnBuffer: Optional[Callable[[Any, bytes], None]] = None): ... + def Connect(self, URI: str, timeoutSec=5) -> bool: ... + def Disconnect(self) -> None: ... + def IsConnected(self) -> bool: ... + def SendTask(self, task, buffer: bytes = None) -> Any: ... + def add_merge_to_project(self) -> MF.V3.Task.Task: ... + def align(self, source: int, target: int, rough: MF.V3.Settings.Align.Align.Rough = None, fine: MF.V3.Settings.Align.Align.Fine = None) -> MF.V3.Task.Task: ... + def auto_focus(self, cameras: MF.V3.Settings.AutoFocus.AutoFocus.Camera, applyAll: bool) -> MF.V3.Task.Task: ... + def bounding_box(self, selection: MF.V3.Settings.ScanSelection.ScanSelection, axisAligned: bool) -> MF.V3.Task.Task: ... + def calibrate_cameras(self) -> MF.V3.Task.Task: ... + def calibrate_turntable(self) -> MF.V3.Task.Task: ... + def calibration_capture_targets(self) -> MF.V3.Task.Task: ... + def camera_calibration(self) -> MF.V3.Task.Task: ... + def close_project(self) -> MF.V3.Task.Task: ... + def connect_wifi(self, ssid: str, password: str) -> MF.V3.Task.Task: ... + def depth_map(self, camera: MF.V3.Settings.Camera.Camera = None, projector: MF.V3.Settings.Projector.Projector = None, turntable: MF.V3.Settings.Turntable.Turntable = None, capture: MF.V3.Settings.Capture.Capture = None, processing: MF.V3.Settings.Scan.Scan.Processing = None) -> MF.V3.Task.Task: ... + def detect_calibration_card(self, Input: int) -> MF.V3.Task.Task: ... + def download_project(self, Input: int) -> MF.V3.Task.Task: ... + def export(self, selection: MF.V3.Settings.ScanSelection.ScanSelection = None, texture: bool = None, merge: bool = None, format: MF.V3.Settings.Export.Export.Format = None) -> MF.V3.Task.Task: ... + def export_logs(self, Input: bool = None) -> MF.V3.Task.Task: ... + def export_merge(self, selection: MF.V3.Settings.ScanSelection.ScanSelection = None, texture: bool = None, merge: bool = None, format: MF.V3.Settings.Export.Export.Format = None) -> MF.V3.Task.Task: ... + def flatten_group(self, Input: int) -> MF.V3.Task.Task: ... + def forget_wifi(self) -> MF.V3.Task.Task: ... + def has_cameras(self) -> MF.V3.Task.Task: ... + def has_projector(self) -> MF.V3.Task.Task: ... + def has_turntable(self) -> MF.V3.Task.Task: ... + def list_export_formats(self) -> MF.V3.Task.Task: ... + def list_groups(self) -> MF.V3.Task.Task: ... + def list_network_interfaces(self) -> MF.V3.Task.Task: ... + def list_projects(self) -> MF.V3.Task.Task: ... + def list_scans(self) -> MF.V3.Task.Task: ... + def list_settings(self) -> MF.V3.Task.Task: ... + def list_wifi(self) -> MF.V3.Task.Task: ... + def merge(self, selection: MF.V3.Settings.ScanSelection.ScanSelection = None, remesh: MF.V3.Settings.Merge.Merge.Remesh = None, simplify: MF.V3.Settings.Merge.Merge.Simplify = None, texturize: bool = None) -> MF.V3.Task.Task: ... + def merge_data(self, index: int, buffers: MF.V3.Settings.ScanData.ScanData.Buffer, metadata: MF.V3.Settings.ScanData.ScanData.Metadata, mergeStep: MF.V3.Settings.ScanData.ScanData.MergeStep = None) -> MF.V3.Task.Task: ... + def move_group(self, Input: int) -> MF.V3.Task.Task: ... + def new_group(self, color: float, rotation: float, translation: float, parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None) -> MF.V3.Task.Task: ... + def new_project(self, Input: str = None) -> MF.V3.Task.Task: ... + def new_scan(self, camera: MF.V3.Settings.Camera.Camera = None, projector: MF.V3.Settings.Projector.Projector = None, turntable: MF.V3.Settings.Turntable.Turntable = None, capture: MF.V3.Settings.Capture.Capture = None, processing: MF.V3.Settings.Scan.Scan.Processing = None) -> MF.V3.Task.Task: ... + def open_project(self, Input: int) -> MF.V3.Task.Task: ... + def pop_settings(self, Input: bool = None) -> MF.V3.Task.Task: ... + def push_settings(self) -> MF.V3.Task.Task: ... + def reboot(self) -> MF.V3.Task.Task: ... + def remove_groups(self, Input: int) -> MF.V3.Task.Task: ... + def remove_projects(self, Input: int) -> MF.V3.Task.Task: ... + def restore_factory_calibration(self) -> MF.V3.Task.Task: ... + def rotate_turntable(self, Input: int) -> MF.V3.Task.Task: ... + def scan_data(self, index: int, buffers: MF.V3.Settings.ScanData.ScanData.Buffer, metadata: MF.V3.Settings.ScanData.ScanData.Metadata, mergeStep: MF.V3.Settings.ScanData.ScanData.MergeStep = None) -> MF.V3.Task.Task: ... + def set_cameras(self, selection: int, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> MF.V3.Task.Task: ... + def set_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> MF.V3.Task.Task: ... + def set_project(self, index: int = None, name: str = None) -> MF.V3.Task.Task: ... + def set_projector(self, color: float, on: bool = None, brightness: float = None, pattern: MF.V3.Settings.Projector.Projector.Pattern = None, image: MF.V3.Settings.Projector.Projector.Image = None) -> MF.V3.Task.Task: ... + def shutdown(self) -> MF.V3.Task.Task: ... + def split_group(self, Input: int) -> MF.V3.Task.Task: ... + def start_video(self) -> MF.V3.Task.Task: ... + def stop_video(self) -> MF.V3.Task.Task: ... + def system_info(self, installed: MF.V3.Settings.Software.Software.Package, available: MF.V3.Settings.Software.Software.Package, nightlyIncluded: bool = None) -> MF.V3.Task.Task: ... + def transform_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> MF.V3.Task.Task: ... + def turntable_calibration(self) -> MF.V3.Task.Task: ... + def update_settings(self, advanced: MF.V3.Settings.Advanced.Advanced = None, camera: MF.V3.Settings.Camera.Camera = None, capture: MF.V3.Settings.Capture.Capture = None, i18n: MF.V3.Settings.I18n.I18n = None, projector: MF.V3.Settings.Projector.Projector = None, style: MF.V3.Settings.Style.Style = None, turntable: MF.V3.Settings.Turntable.Turntable = None, tutorials: MF.V3.Settings.Tutorials.Tutorials = None, viewer: MF.V3.Settings.Viewer.Viewer = None, software: MF.V3.Settings.Software.Software = None) -> MF.V3.Task.Task: ... + def upload_project(self) -> MF.V3.Task.Task: ... \ No newline at end of file diff --git a/out/maf_three/MF/V3/Three.pyi b/out/maf_three/MF/V3/Three.pyi deleted file mode 100644 index 8f73f41..0000000 --- a/out/maf_three/MF/V3/Three.pyi +++ /dev/null @@ -1,77 +0,0 @@ -from MF.V3 import Task -from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced -from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align -from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus -from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera -from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture -from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export -from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n -from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge -from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector -from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan -from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData -from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection -from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software -from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style -from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable -from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials -from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer - -class Three: - def __init__(self) -> None: ... - def list_network_interfaces(self) -> Task: ... - def list_wifi(self) -> Task: ... - def connect_wifi(self, ssid: str, password: str) -> Task: ... - def forget_wifi(self) -> Task: ... - def list_settings(self) -> Task: ... - def push_settings(self) -> Task: ... - def pop_settings(self, Input: bool = None) -> Task: ... - def update_settings(self, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None) -> Task: ... - def list_projects(self) -> Task: ... - def download_project(self, Input: int) -> Task: ... - def upload_project(self) -> Task: ... - def new_project(self, Input: str = None) -> Task: ... - def open_project(self, Input: int) -> Task: ... - def close_project(self) -> Task: ... - def remove_projects(self, Input: int) -> Task: ... - def list_groups(self) -> Task: ... - def list_scans(self) -> Task: ... - def scan_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: ... - def set_project(self, index: int = None, name: str = None) -> Task: ... - def set_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: ... - def new_group(self, color: float, rotation: float, translation: float, parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None) -> Task: ... - def move_group(self, Input: int) -> Task: ... - def flatten_group(self, Input: int) -> Task: ... - def split_group(self, Input: int) -> Task: ... - def transform_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: ... - def remove_groups(self, Input: int) -> Task: ... - def bounding_box(self, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool) -> Task: ... - def align(self, source: int, target: int, rough: MF_V3_Settings_Align_Align.Rough = None, fine: MF_V3_Settings_Align_Align.Fine = None) -> Task: ... - def merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: MF_V3_Settings_Merge_Merge.Remesh = None, simplify: MF_V3_Settings_Merge_Merge.Simplify = None, texturize: bool = None) -> Task: ... - def merge_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: ... - def add_merge_to_project(self) -> Task: ... - def list_export_formats(self) -> Task: ... - def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: ... - def export_merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: ... - def export_logs(self, Input: bool = None) -> Task: ... - def has_cameras(self) -> Task: ... - def has_projector(self) -> Task: ... - def has_turntable(self) -> Task: ... - def system_info(self, installed: MF_V3_Settings_Software_Software.Package, available: MF_V3_Settings_Software_Software.Package, nightlyIncluded: bool = None) -> Task: ... - def camera_calibration(self) -> Task: ... - def turntable_calibration(self) -> Task: ... - def calibration_capture_targets(self) -> Task: ... - def calibrate_cameras(self) -> Task: ... - def calibrate_turntable(self) -> Task: ... - def detect_calibration_card(self, Input: int) -> Task: ... - def restore_factory_calibration(self) -> Task: ... - def start_video(self) -> Task: ... - def stop_video(self) -> Task: ... - def set_cameras(self, selection: int, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> Task: ... - def set_projector(self, color: float, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None) -> Task: ... - def auto_focus(self, cameras: MF_V3_Settings_AutoFocus_AutoFocus.Camera, applyAll: bool) -> Task: ... - def rotate_turntable(self, Input: int) -> Task: ... - def new_scan(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: ... - def depth_map(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: ... - def reboot(self) -> Task: ... - def shutdown(self) -> Task: ... diff --git a/scripts/build-proto.py b/scripts/build-proto.py index 977b830..990cf4f 100644 --- a/scripts/build-proto.py +++ b/scripts/build-proto.py @@ -1,8 +1,10 @@ import subprocess import os +import inspect +import importlib +import ast # Build proto files - def run_transpile_proto(): script_path = os.path.join(os.path.dirname(__file__), 'transpileProto.py') input_dir = './V3Schema' @@ -13,5 +15,83 @@ def run_transpile_proto(): else: print(f"Output: {result.stdout}") +def get_imports_from_file(file_path): + with open(file_path, 'r') as file: + tree = ast.parse(file.read(), filename=file_path) + + imports = set() + for node in ast.walk(tree): + if isinstance(node, ast.Import): + for alias in node.names: + parts = alias.name.split('.') + for i in range(1, len(parts) + 1): + imports.add('.'.join(parts[:i])) + elif isinstance(node, ast.ImportFrom): + module = node.module + if module: + parts = module.split('.') + for i in range(1, len(parts) + 1): + imports.add('.'.join(parts[:i])) + return sorted(imports) + +def adjust_signature(signature): + # Replace NoneType with None in the signature + return signature.replace('NoneType', 'None') + +def generate_pyi(scanner_module_name, three_module_name, output_file): + # Import the modules + scanner_module = importlib.import_module(scanner_module_name) + three_module = importlib.import_module(three_module_name) + + # Get the class from scanner.py + scanner_class = getattr(scanner_module, 'Scanner') + + # Get functions from three.py + three_functions = inspect.getmembers(three_module, inspect.isfunction) + + # Get import statements from scanner.py and three.py + scanner_imports = get_imports_from_file(scanner_module.__file__) + three_imports = get_imports_from_file(three_module.__file__) + + # Combine and deduplicate imports + all_imports = sorted(set(scanner_imports + three_imports)) + + # Start generating the .pyi content + pyi_content = [] + + # Add imports + for imp in all_imports: + pyi_content.append(f"import {imp}") + + # Add specific imports from typing + pyi_content.append("from typing import Optional, Callable, Any, Union") + + # Add class definition + pyi_content.append("\n\nclass Scanner:") + + # Add __init__ method + init_method = scanner_class.__init__ + init_sig = str(inspect.signature(init_method)) + init_sig = adjust_signature(init_sig) + pyi_content.append(f" def __init__{init_sig}: ...") + + # Add other methods from Scanner class + for name, method in inspect.getmembers(scanner_class, inspect.isfunction): + if not name.startswith('_'): # Skip private methods + sig = str(inspect.signature(method)) + sig = adjust_signature(sig) + pyi_content.append(f" def {name}{sig}: ...") + + # Add dynamically bound functions from three.py + for name, func in three_functions: + sig = str(inspect.signature(func)) + sig = adjust_signature(sig) + pyi_content.append(f" def {name}{sig}: ...") + + # Write to the output file + with open(output_file, 'w') as f: + f.write('\n'.join(pyi_content)) + if __name__ == "__main__": - run_transpile_proto() \ No newline at end of file + run_transpile_proto() + generate_pyi('maf_three.scanner', 'maf_three.MF.V3.Three', './maf_three/scanner.pyi') \ No newline at end of file diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index daf7dd1..f8d69a6 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -328,10 +328,6 @@ def get_property(property, tree: Tree, node:TreeNode, message_namespace:str) -> tree_property.type = type_mapping.get(property.type, property.type) return tree_property - if (node.filespace == "MF.V3.Tasks.BoundingBox"): - print("debug") - - import_descriptor = ImportDescriptor(node.filespace, property.type.split(".")[-1], "") tree_property.import_descriptor = import_descriptor @@ -475,13 +471,9 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: task_descriptor = ImportDescriptor("MF.V3", "Task", "") current_node.imports.append(task_descriptor) task_name = task_descriptor.replacement if task_descriptor.replacement != '' else task_descriptor.type - - service_code = f"class {name}:\n" - - service_code += add_indents(current_node.comment, 1) - service_code += " def __init__(self):\n" - service_code += " pass\n\n" + service_code = "" + for procedure in current_node.procedures: request_node = procedure.request @@ -494,7 +486,6 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: method_name += "_" method_name += c.lower() - service_code += f" def {method_name}(self" # loop over all the properties from the request node to get the input node method_properties = [] @@ -548,7 +539,8 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: method_properties.append(prop) - + service_code += f"def {method_name}(self" + # Sort the properties so that optionals are last method_properties = sorted(method_properties, key=lambda x: x.optional) @@ -561,7 +553,7 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: service_code += f") -> {task_name}:\n" - service_code += add_indents(procedure.comment,2) + service_code += add_indents(procedure.comment,1) def create_object_code(node:TreeNode, postfix:str, ignore_optionals:bool)->str: @@ -585,7 +577,7 @@ def create_object_code(node:TreeNode, postfix:str, ignore_optionals:bool)->str: current_node.imports.append(procedure.request_import) - code += f" {method_name}_{postfix} = {new_request_property_name}(" + code += f" {method_name}_{postfix} = {new_request_property_name}(" for i, prop in enumerate(node.properties): if (prop.optional and ignore_optionals): continue @@ -595,28 +587,28 @@ def create_object_code(node:TreeNode, postfix:str, ignore_optionals:bool)->str: if prop.name == "Input": # some property types are python types, so we need to handle them differently if len(method_properties) == 1 and method_properties[0].type in python_types: - code += f" {method_properties[0].name}={method_properties[0].name}" + code += f" {method_properties[0].name}={method_properties[0].name}" else: # multiple properties will result in a complicated type - code += f" {prop.name}={prop.type}(\n" + code += f" {prop.name}={prop.type}(\n" for input_prop in method_properties: - code += f" {input_prop.name}={input_prop.name},\n" - code += " )" + code += f" {input_prop.name}={input_prop.name},\n" + code += " )" elif prop.name == "Type": - code += f" {prop.name}=\"{procedure.name}\"" + code += f" {prop.name}=\"{procedure.name}\"" elif prop.name == "Index": - code += f" {prop.name}=0" + code += f" {prop.name}=0" else: - code += f" {prop.name}=None" - code += "\n )\n" + code += f" {prop.name}=None" + code += "\n )\n" return code service_code += create_object_code(request_node, "request", False) service_code += create_object_code(response_node, "response", True) - service_code += f" task = {task_name}(Index=0, Type=\"{procedure.name}\", Input={method_name}_request, Output={method_name}_response)\n" - service_code += f" self.SendTask(task)\n" - service_code += f" return task\n\n" + service_code += f" task = {task_name}(Index=0, Type=\"{procedure.name}\", Input={method_name}_request, Output={method_name}_response)\n" + service_code += f" self.SendTask(task)\n" + service_code += f" return task\n\n\n" return service_code From 3f5bb9cab130caa6a14a97ac60b9a9454181f3b0 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Mon, 30 Sep 2024 16:25:12 -0400 Subject: [PATCH 58/86] repeated as optionals. Handling enum serialization --- maf_three/MF/V3/Descriptors/BoundingBox.py | 2 +- maf_three/MF/V3/Descriptors/Calibration.py | 8 +- maf_three/MF/V3/Descriptors/Export.py | 6 +- maf_three/MF/V3/Descriptors/Merge.py | 2 +- maf_three/MF/V3/Descriptors/Project.py | 12 +-- maf_three/MF/V3/Descriptors/ProjectActions.py | 8 +- maf_three/MF/V3/Descriptors/RemoveVertices.py | 2 +- maf_three/MF/V3/Descriptors/ScanData.py | 8 +- .../MF/V3/Descriptors/Settings/Advanced.py | 12 +-- .../MF/V3/Descriptors/Settings/Camera.py | 8 +- .../MF/V3/Descriptors/Settings/Tutorials.py | 2 +- maf_three/MF/V3/Descriptors/System.py | 6 +- maf_three/MF/V3/Descriptors/Transform.py | 2 +- maf_three/MF/V3/Descriptors/Wifi.py | 2 +- maf_three/MF/V3/Settings/Advanced.py | 8 +- maf_three/MF/V3/Settings/Align.py | 4 +- maf_three/MF/V3/Settings/AutoFocus.py | 6 +- maf_three/MF/V3/Settings/Camera.py | 2 +- maf_three/MF/V3/Settings/Capture.py | 10 +-- maf_three/MF/V3/Settings/Group.py | 14 ++-- maf_three/MF/V3/Settings/NewGroup.py | 22 ++--- maf_three/MF/V3/Settings/Projector.py | 6 +- maf_three/MF/V3/Settings/RemoveVertices.py | 2 +- maf_three/MF/V3/Settings/Scan.py | 8 +- maf_three/MF/V3/Settings/ScanData.py | 6 +- maf_three/MF/V3/Settings/ScanSelection.py | 2 +- maf_three/MF/V3/Settings/Software.py | 2 +- maf_three/MF/V3/Settings/Tutorials.py | 2 +- maf_three/MF/V3/Tasks/DepthMap.py | 6 +- maf_three/MF/V3/Tasks/ListExportFormats.py | 2 +- maf_three/MF/V3/Tasks/ListScans.py | 2 +- maf_three/MF/V3/Tasks/MoveGroup.py | 8 +- maf_three/MF/V3/Tasks/RemoveGroups.py | 8 +- maf_three/MF/V3/Tasks/RemoveProjects.py | 4 +- maf_three/MF/V3/Three.py | 81 +++++++++---------- maf_three/examples/projector.py | 41 ++++++---- maf_three/scanner.pyi | 26 +++--- maf_three/serialization.py | 45 ++++++++--- scripts/build-proto.py | 3 +- scripts/transpileProto.py | 8 +- scripts/tree.py | 2 + 41 files changed, 222 insertions(+), 188 deletions(-) diff --git a/maf_three/MF/V3/Descriptors/BoundingBox.py b/maf_three/MF/V3/Descriptors/BoundingBox.py index ad59c38..c7652ec 100644 --- a/maf_three/MF/V3/Descriptors/BoundingBox.py +++ b/maf_three/MF/V3/Descriptors/BoundingBox.py @@ -3,7 +3,7 @@ class BoundingBox: # BoundingBox descriptor. - def __init__(self, center: List[float], size: List[float], rotation: List[float], transform: List[float]): + def __init__(self, center: List[float] = None, size: List[float] = None, rotation: List[float] = None, transform: List[float] = None): # The center of the bounding box. self.center = center # The size of the bounding box. diff --git a/maf_three/MF/V3/Descriptors/Calibration.py b/maf_three/MF/V3/Descriptors/Calibration.py index 15d0557..3df31dc 100644 --- a/maf_three/MF/V3/Descriptors/Calibration.py +++ b/maf_three/MF/V3/Descriptors/Calibration.py @@ -13,7 +13,7 @@ class Quality(Enum): class Camera: # Camera calibration descriptor. - def __init__(self, quality: 'Quality', date: List[int]): + def __init__(self, quality: 'Quality', date: List[int] = None): # Calibration quality. self.quality = quality # Calibration date and time [year, month, day, hour, minute, second]. @@ -22,7 +22,7 @@ def __init__(self, quality: 'Quality', date: List[int]): class Turntable: # Turntable calibration descriptor. - def __init__(self, quality: 'Quality', date: List[int], focus: List[int]): + def __init__(self, quality: 'Quality', date: List[int] = None, focus: List[int] = None): # Calibration quality. self.quality = quality # Calibration date and time [year, month, day, hour, minute, second]. @@ -37,7 +37,7 @@ class CaptureTarget: The camera calibration capture targets are used to draw quad overlays on the video stream to guide a user as to where to position the calibration card for each capture during camera calibration. """ - def __init__(self, camera: int, quads: List[float]): + def __init__(self, camera: int, quads: List[float] = None): # Index of the camera that is displayed to the user for this capture. self.camera = camera """ @@ -66,7 +66,7 @@ def __init__(self, match: float, hold: float): """ self.hold = hold - def __init__(self, size: List[int], quad: List[float], corners: List[float], target: 'Target' = None): + def __init__(self, size: List[int] = None, quad: List[float] = None, corners: List[float] = None, target: 'Target' = None): # The calibration card columns and rows. self.size = size # The calibration card bounding quadrilateral. diff --git a/maf_three/MF/V3/Descriptors/Export.py b/maf_three/MF/V3/Descriptors/Export.py index 5796427..258340c 100644 --- a/maf_three/MF/V3/Descriptors/Export.py +++ b/maf_three/MF/V3/Descriptors/Export.py @@ -19,20 +19,20 @@ class Texture(Enum): Single = "Single" # The format supports a single texture only. Multiple = "Multiple" # The format supports multiple textures. - def __init__(self, format: MF_V3_Settings_Export_Export.Format, extension: str, description: str, faces: List['Face'], normals: bool, colors: bool, textures: 'Texture'): + def __init__(self, format: MF_V3_Settings_Export_Export.Format, extension: str, description: str, normals: bool, colors: bool, textures: 'Texture', faces: List['Face'] = None): # Export format. self.format = format # Export file extension. e.g. ".ply" self.extension = extension # Export format description. e.g. "Polygon format" self.description = description - # Types of supported faces. - self.faces = faces # Vertex normal support. self.normals = normals # Vertex color support. self.colors = colors # Texture (UV) support. self.textures = textures + # Types of supported faces. + self.faces = faces diff --git a/maf_three/MF/V3/Descriptors/Merge.py b/maf_three/MF/V3/Descriptors/Merge.py index daeaf43..2ebdd84 100644 --- a/maf_three/MF/V3/Descriptors/Merge.py +++ b/maf_three/MF/V3/Descriptors/Merge.py @@ -21,7 +21,7 @@ def __init__(self, name: str, triangles: int, quads: int, positions: int, normal # Total mesh size in bytes. self.size = size - def __init__(self, scans: int, textures: int, maxSimplifyCount: int, meshes: List['Mesh']): + def __init__(self, scans: int, textures: int, maxSimplifyCount: int, meshes: List['Mesh'] = None): # The number of input scans. self.scans = scans # The number of input textures. diff --git a/maf_three/MF/V3/Descriptors/Project.py b/maf_three/MF/V3/Descriptors/Project.py index 16a487f..90e35bc 100644 --- a/maf_three/MF/V3/Descriptors/Project.py +++ b/maf_three/MF/V3/Descriptors/Project.py @@ -5,7 +5,7 @@ class Project: # V3 project descriptor. class Brief: # V3 project brief descriptor. - def __init__(self, index: int, name: str, size: int, modified: List[int]): + def __init__(self, index: int, name: str, size: int, modified: List[int] = None): # Project index. self.index = index # Project name. @@ -17,25 +17,25 @@ def __init__(self, index: int, name: str, size: int, modified: List[int]): class Group: # V3 project scan group tree descriptor. - def __init__(self, index: int, name: str, color: List[float], visible: bool, collapsed: bool, rotation: List[float], translation: List[float], groups: List['Project.Group'], scan: int = None): + def __init__(self, index: int, name: str, visible: bool, collapsed: bool, color: List[float] = None, rotation: List[float] = None, translation: List[float] = None, scan: int = None, groups: List['Project.Group'] = None): # Group index. self.index = index # Group name. self.name = name - # Color in the renderer. - self.color = color # Visibility in the renderer. self.visible = visible # Collapsed state in the group tree. self.collapsed = collapsed + # Color in the renderer. + self.color = color # Axis-angle rotation vector. The direction of the vector is the rotation axis. The magnitude of the vector is rotation angle in radians. self.rotation = rotation # Translation vector. self.translation = translation - # Subgroups. - self.groups = groups # The scan index. If defined this group is a scan and cannot have subgroups. self.scan = scan + # Subgroups. + self.groups = groups def __init__(self, index: int, name: str, groups: 'Group'): # Project index. diff --git a/maf_three/MF/V3/Descriptors/ProjectActions.py b/maf_three/MF/V3/Descriptors/ProjectActions.py index cdf58ca..57485bc 100644 --- a/maf_three/MF/V3/Descriptors/ProjectActions.py +++ b/maf_three/MF/V3/Descriptors/ProjectActions.py @@ -14,21 +14,21 @@ def __init__(self, index: int, vertices: int, triangles: int): # The number of triangles after undo or redo. self.triangles = triangles - def __init__(self, task: str, scans: List['Scan'], project: MF_V3_Descriptors_Project_Project = None): + def __init__(self, task: str, project: MF_V3_Descriptors_Project_Project = None, scans: List['Scan'] = None): # The original websocket task that the action is undoing or redoing. self.task = task - # The list of scans whose vertex/triangle elements were changed by the undo/redo action. - self.scans = scans """ The updated project data after undo or redo. If undefined, then there was no change to the project. """ self.project = project + # The list of scans whose vertex/triangle elements were changed by the undo/redo action. + self.scans = scans class ProjectActions: # Project undo and redo action descriptors. - def __init__(self, undo: List[str], redo: List[str]): + def __init__(self, undo: List[str] = None, redo: List[str] = None): # Project undo action descriptors. self.undo = undo # Project redo action descriptors. diff --git a/maf_three/MF/V3/Descriptors/RemoveVertices.py b/maf_three/MF/V3/Descriptors/RemoveVertices.py index 81800b8..2aa3ac3 100644 --- a/maf_three/MF/V3/Descriptors/RemoveVertices.py +++ b/maf_three/MF/V3/Descriptors/RemoveVertices.py @@ -14,7 +14,7 @@ def __init__(self, index: int, vertices: int, triangles: int): # The number of triangles after the removal. self.triangles = triangles - def __init__(self, scans: List['Scan'], groups: MF_V3_Descriptors_Project_Project.Group = None): + def __init__(self, scans: List['Scan'] = None, groups: MF_V3_Descriptors_Project_Project.Group = None): # The list of scans whose vertices were removed. self.scans = scans """ diff --git a/maf_three/MF/V3/Descriptors/ScanData.py b/maf_three/MF/V3/Descriptors/ScanData.py index d052ba9..0442683 100644 --- a/maf_three/MF/V3/Descriptors/ScanData.py +++ b/maf_three/MF/V3/Descriptors/ScanData.py @@ -30,13 +30,13 @@ def __init__(self, type: 'Type', size: int, offset: int, normalized: bool): # Indicates if the data is normalized. self.normalized = normalized - def __init__(self, components: List['Component'], stride: int): - # Scan buffer components. - self.components = components + def __init__(self, stride: int, components: List['Component'] = None): # Scan buffer stride. This should be greater or equal to the sum of the component sizes. self.stride = stride + # Scan buffer components. + self.components = components - def __init__(self, index: int, name: str, buffers: List['Buffer'], mean: List[float], stddev: List[float], axisAlignedBoundingBox: List[float]): + def __init__(self, index: int, name: str, buffers: List['Buffer'] = None, mean: List[float] = None, stddev: List[float] = None, axisAlignedBoundingBox: List[float] = None): # Scan index. self.index = index # Scan name. diff --git a/maf_three/MF/V3/Descriptors/Settings/Advanced.py b/maf_three/MF/V3/Descriptors/Settings/Advanced.py index f71f88f..423fb3e 100644 --- a/maf_three/MF/V3/Descriptors/Settings/Advanced.py +++ b/maf_three/MF/V3/Descriptors/Settings/Advanced.py @@ -13,18 +13,18 @@ def __init__(self, value: bool, default: bool): class Capture: # Capture settings descriptor. class HorizontalFrequencies: - def __init__(self, value: List[int], default: List[int], min: int, max: int): - self.value = value - self.default = default + def __init__(self, min: int, max: int, value: List[int] = None, default: List[int] = None): self.min = min self.max = max - - class VerticalFrequencies: - def __init__(self, value: List[int], default: List[int], min: int, max: int): self.value = value self.default = default + + class VerticalFrequencies: + def __init__(self, min: int, max: int, value: List[int] = None, default: List[int] = None): self.min = min self.max = max + self.value = value + self.default = default def __init__(self, use: 'Advanced.Use', horizontalFrequencies: 'HorizontalFrequencies', verticalFrequencies: 'VerticalFrequencies'): self.use = use diff --git a/maf_three/MF/V3/Descriptors/Settings/Camera.py b/maf_three/MF/V3/Descriptors/Settings/Camera.py index a59dcb5..df45cc0 100644 --- a/maf_three/MF/V3/Descriptors/Settings/Camera.py +++ b/maf_three/MF/V3/Descriptors/Settings/Camera.py @@ -38,15 +38,15 @@ class Focus: # Focus settings descriptor. class Value: # Focus value. - def __init__(self, value: List[int], default: List[int], min: int, max: int): - self.value = value - self.default = default + def __init__(self, min: int, max: int, value: List[int] = None, default: List[int] = None): self.min = min self.max = max + self.value = value + self.default = default class Box: # Auto focus box. - def __init__(self, value: List[MF_V3_Settings_Rectangle_Rectangle], default: List[MF_V3_Settings_Rectangle_Rectangle]): + def __init__(self, value: List[MF_V3_Settings_Rectangle_Rectangle] = None, default: List[MF_V3_Settings_Rectangle_Rectangle] = None): self.value = value self.default = default diff --git a/maf_three/MF/V3/Descriptors/Settings/Tutorials.py b/maf_three/MF/V3/Descriptors/Settings/Tutorials.py index 383efda..ea01eea 100644 --- a/maf_three/MF/V3/Descriptors/Settings/Tutorials.py +++ b/maf_three/MF/V3/Descriptors/Settings/Tutorials.py @@ -13,7 +13,7 @@ class Viewed: # Viewed tutorials. class Pages: # Viewed tutorials pages. - def __init__(self, value: List[str], default: List[str]): + def __init__(self, value: List[str] = None, default: List[str] = None): self.value = value self.default = default diff --git a/maf_three/MF/V3/Descriptors/System.py b/maf_three/MF/V3/Descriptors/System.py index ef53333..a1f4780 100644 --- a/maf_three/MF/V3/Descriptors/System.py +++ b/maf_three/MF/V3/Descriptors/System.py @@ -38,13 +38,13 @@ def __init__(self, name: Software.Package, version: 'System.Software.Version', c # The package changelog. self.changelog = changelog - def __init__(self, installed: List['Package'], available: List['Package'], nightlyIncluded: bool): + def __init__(self, nightlyIncluded: bool, installed: List['Package'] = None, available: List['Package'] = None): + # Nightly releases are included. + self.nightlyIncluded = nightlyIncluded # Installed software versions. self.installed = installed # Available software versions. self.available = available - # Nightly releases are included. - self.nightlyIncluded = nightlyIncluded def __init__(self, serialNumber: str, diskSpace: 'DiskSpace', software: 'Software', publicKey: str): # Serial number; diff --git a/maf_three/MF/V3/Descriptors/Transform.py b/maf_three/MF/V3/Descriptors/Transform.py index e18b19d..8638d74 100644 --- a/maf_three/MF/V3/Descriptors/Transform.py +++ b/maf_three/MF/V3/Descriptors/Transform.py @@ -3,7 +3,7 @@ class Transform: # V3 transform descriptor. - def __init__(self, rotation: List[float], translation: List[float]): + def __init__(self, rotation: List[float] = None, translation: List[float] = None): """ Axis-angle rotation vector. The direction of the vector is the rotation axis. diff --git a/maf_three/MF/V3/Descriptors/Wifi.py b/maf_three/MF/V3/Descriptors/Wifi.py index d8193e3..b2fe4b8 100644 --- a/maf_three/MF/V3/Descriptors/Wifi.py +++ b/maf_three/MF/V3/Descriptors/Wifi.py @@ -17,7 +17,7 @@ def __init__(self, ssid: str, isPublic: bool, isActive: bool, password: str = No # Signal quality [0 ; 100]. self.quality = quality - def __init__(self, ssid: str, networks: List['Network']): + def __init__(self, ssid: str, networks: List['Network'] = None): # The wifi ssid. self.ssid = ssid # The list of wifi networks. diff --git a/maf_three/MF/V3/Settings/Advanced.py b/maf_three/MF/V3/Settings/Advanced.py index b8a8e69..a54ba9b 100644 --- a/maf_three/MF/V3/Settings/Advanced.py +++ b/maf_three/MF/V3/Settings/Advanced.py @@ -7,7 +7,7 @@ class Advanced: # Advanced settings. class Capture: # Capture settings. - def __init__(self, horizontalFrequencies: List[int], verticalFrequencies: List[int], use: bool = None): + def __init__(self, horizontalFrequencies: List[int] = None, verticalFrequencies: List[int] = None, use: bool = None): # Projector sample rate. self.horizontalFrequencies = horizontalFrequencies # Image sample rate. @@ -98,11 +98,11 @@ def __init__(self, rate: float, type: MF_V3_Settings_Scan_Scan.Processing.Adapti class PointClipping: # Point32 clipping settings. - def __init__(self, transform: List[float], type: MF_V3_Settings_Scan_Scan.Processing.PointClipping.Type = None, use: bool = None): - # 4x4 transform mapping 3D points to the canonical point32 clipping coordinates. - self.transform = transform + def __init__(self, type: MF_V3_Settings_Scan_Scan.Processing.PointClipping.Type = None, transform: List[float] = None, use: bool = None): # Point32 clipping type. self.type = type + # 4x4 transform mapping 3D points to the canonical point32 clipping coordinates. + self.transform = transform # Use the point32 clipping settings. self.use = use diff --git a/maf_three/MF/V3/Settings/Align.py b/maf_three/MF/V3/Settings/Align.py index 33dbc32..c30616b 100644 --- a/maf_three/MF/V3/Settings/Align.py +++ b/maf_three/MF/V3/Settings/Align.py @@ -6,7 +6,7 @@ class Align: # Alignment settings. class Points: # Point pair alignment settings. - def __init__(self, points: List[float], absoluteError: float = None, relativeError: float = None, useAllPoints: bool = None): + def __init__(self, points: List[float] = None, absoluteError: float = None, relativeError: float = None, useAllPoints: bool = None): # The set of corresponding point pairs. self.points = points # The maximum absolute error for a point pair to be an inlier to the model. @@ -57,7 +57,7 @@ class Method(Enum): ICP = "ICP" # Iterative closest point alignment. class Transform: - def __init__(self, rotation: List[float], translation: List[float]): + def __init__(self, rotation: List[float] = None, translation: List[float] = None): self.rotation = rotation self.translation = translation diff --git a/maf_three/MF/V3/Settings/AutoFocus.py b/maf_three/MF/V3/Settings/AutoFocus.py index 5a5ed13..8a5e494 100644 --- a/maf_three/MF/V3/Settings/AutoFocus.py +++ b/maf_three/MF/V3/Settings/AutoFocus.py @@ -12,13 +12,13 @@ def __init__(self, index: int, box: MF_V3_Settings_Rectangle_Rectangle = None): # The image rectangle in video image pixels on which to apply auto focus. self.box = box - def __init__(self, cameras: List['Camera'], applyAll: bool): - # The set of cameras on which to apply auto focus. - self.cameras = cameras + def __init__(self, applyAll: bool, cameras: List['Camera'] = None): """ Apply the final focus value to both cameras. This setting is ignored if more than one camera is selected. """ self.applyAll = applyAll + # The set of cameras on which to apply auto focus. + self.cameras = cameras diff --git a/maf_three/MF/V3/Settings/Camera.py b/maf_three/MF/V3/Settings/Camera.py index fc58f6a..3054771 100644 --- a/maf_three/MF/V3/Settings/Camera.py +++ b/maf_three/MF/V3/Settings/Camera.py @@ -3,7 +3,7 @@ class Camera: # Camera settings. - def __init__(self, selection: List[int], autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None): + def __init__(self, selection: List[int] = None, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None): # Camera selection. Default is all cameras. self.selection = selection # Auto exposure. diff --git a/maf_three/MF/V3/Settings/Capture.py b/maf_three/MF/V3/Settings/Capture.py index 673ff46..40834e6 100644 --- a/maf_three/MF/V3/Settings/Capture.py +++ b/maf_three/MF/V3/Settings/Capture.py @@ -4,17 +4,17 @@ class Capture: # Capture settings. - def __init__(self, horizontalFrequencies: List[int], verticalFrequencies: List[int], quality: MF_V3_Settings_Quality_Quality = None, texture: bool = None, calibrationCard: bool = None, blendCount: int = None, horizontalBlendFrequency: int = None, verticalBlendFrequency: int = None): - # Horizontal pattern frequencies. - self.horizontalFrequencies = horizontalFrequencies - # Vertical pattern frequencies. - self.verticalFrequencies = verticalFrequencies + def __init__(self, quality: MF_V3_Settings_Quality_Quality = None, texture: bool = None, calibrationCard: bool = None, horizontalFrequencies: List[int] = None, verticalFrequencies: List[int] = None, blendCount: int = None, horizontalBlendFrequency: int = None, verticalBlendFrequency: int = None): # Capture quality preset. self.quality = quality # Capture texture. self.texture = texture # Detect the calibration card. self.calibrationCard = calibrationCard + # Horizontal pattern frequencies. + self.horizontalFrequencies = horizontalFrequencies + # Vertical pattern frequencies. + self.verticalFrequencies = verticalFrequencies # The number of capture images blended together for noise reduction. self.blendCount = blendCount # The starting horizontal frequency for blending capture images for noise reduction. diff --git a/maf_three/MF/V3/Settings/Group.py b/maf_three/MF/V3/Settings/Group.py index f3d4ac7..ab28619 100644 --- a/maf_three/MF/V3/Settings/Group.py +++ b/maf_three/MF/V3/Settings/Group.py @@ -3,11 +3,17 @@ class Group: # Scan group settings. - def __init__(self, index: int, color: List[float], rotation: List[float], translation: List[float], name: str = None, visible: bool = None, collapsed: bool = None): + def __init__(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None): # The unique group index that identifies the group within the group tree. self.index = index + # Group name. + self.name = name # Color in the renderer. self.color = color + # Visibility in the renderer. + self.visible = visible + # Collapsed state in the group tree. + self.collapsed = collapsed """ Axis-angle rotation vector. The direction of the vector is the rotation axis. @@ -16,11 +22,5 @@ def __init__(self, index: int, color: List[float], rotation: List[float], transl self.rotation = rotation # Translation vector. self.translation = translation - # Group name. - self.name = name - # Visibility in the renderer. - self.visible = visible - # Collapsed state in the group tree. - self.collapsed = collapsed diff --git a/maf_three/MF/V3/Settings/NewGroup.py b/maf_three/MF/V3/Settings/NewGroup.py index 792d90d..f466965 100644 --- a/maf_three/MF/V3/Settings/NewGroup.py +++ b/maf_three/MF/V3/Settings/NewGroup.py @@ -3,17 +3,7 @@ class NewGroup: # Scan group settings. - def __init__(self, color: List[float], rotation: List[float], translation: List[float], parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None): - # Group color. - self.color = color - """ - Group axis-angle rotation vector. - The direction of the vector is the rotation axis. - The magnitude of the vector is rotation angle in radians. - """ - self.rotation = rotation - # Group translation vector. - self.translation = translation + def __init__(self, parentIndex: int = None, baseName: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None): """ The index of the parent group in which the new group is created. If unspecified the new group is added to the root of the group tree. @@ -24,9 +14,19 @@ def __init__(self, color: List[float], rotation: List[float], translation: List[ The new group name will start with the base name followed by a unique index number chosen by the backend. """ self.baseName = baseName + # Group color. + self.color = color # Group visibility. self.visible = visible # Collapsed state in the group tree. self.collapsed = collapsed + """ + Group axis-angle rotation vector. + The direction of the vector is the rotation axis. + The magnitude of the vector is rotation angle in radians. + """ + self.rotation = rotation + # Group translation vector. + self.translation = translation diff --git a/maf_three/MF/V3/Settings/Projector.py b/maf_three/MF/V3/Settings/Projector.py index c0592fa..1740927 100644 --- a/maf_three/MF/V3/Settings/Projector.py +++ b/maf_three/MF/V3/Settings/Projector.py @@ -43,9 +43,7 @@ def __init__(self, source: 'Source', target: MF_V3_Settings_Rectangle_Rectangle) # Image target rectangle. self.target = target - def __init__(self, color: List[float], on: bool = None, brightness: float = None, pattern: 'Pattern' = None, image: 'Image' = None): - # Solid color - self.color = color + def __init__(self, on: bool = None, brightness: float = None, pattern: 'Pattern' = None, image: 'Image' = None, color: List[float] = None): # Projector on/off. self.on = on # Projector brightness. @@ -54,5 +52,7 @@ def __init__(self, color: List[float], on: bool = None, brightness: float = None self.pattern = pattern # Image to project self.image = image + # Solid color + self.color = color diff --git a/maf_three/MF/V3/Settings/RemoveVertices.py b/maf_three/MF/V3/Settings/RemoveVertices.py index 0fe0e53..1e133de 100644 --- a/maf_three/MF/V3/Settings/RemoveVertices.py +++ b/maf_three/MF/V3/Settings/RemoveVertices.py @@ -3,7 +3,7 @@ class RemoveVertices: # Remove vertices. - def __init__(self, scans: List[int]): + def __init__(self, scans: List[int] = None): # The scans indexes for which vertices are removed. self.scans = scans diff --git a/maf_three/MF/V3/Settings/Scan.py b/maf_three/MF/V3/Settings/Scan.py index 8b72fa0..7067b3b 100644 --- a/maf_three/MF/V3/Settings/Scan.py +++ b/maf_three/MF/V3/Settings/Scan.py @@ -89,7 +89,7 @@ class Type(Enum): InsideCylinder = "InsideCylinder" # Clip points inside a unit cylinder. InsideSphere = "InsideSphere" # Clip points inside a unit sphere. - def __init__(self, type: 'Type', transform: List[float]): + def __init__(self, type: 'Type', transform: List[float] = None): # Point clipping type. self.type = type # 4x4 transform mapping 3D points to the canonical point clipping coordinates. @@ -124,9 +124,7 @@ def __init__(self, neighbourCount: int, neighbourRadius: float): # The neighbour search radius. self.neighbourRadius = neighbourRadius - def __init__(self, pointClipping: List['PointClipping'], projectorSampleRate: float = None, imageSampleRate: float = None, edgeDetection: 'PhaseEdgeDetection' = None, phaseFilter: 'PhaseFilter' = None, adaptiveSampling: 'AdaptiveSampling' = None, normalEstimation: 'NormalEstimation' = None, outlierRemoval: 'OutlierRemoval' = None): - # Point clipping settings. - self.pointClipping = pointClipping + def __init__(self, projectorSampleRate: float = None, imageSampleRate: float = None, edgeDetection: 'PhaseEdgeDetection' = None, phaseFilter: 'PhaseFilter' = None, adaptiveSampling: 'AdaptiveSampling' = None, pointClipping: List['PointClipping'] = None, normalEstimation: 'NormalEstimation' = None, outlierRemoval: 'OutlierRemoval' = None): # Projector sample rate. self.projectorSampleRate = projectorSampleRate # Image sample rate. @@ -137,6 +135,8 @@ def __init__(self, pointClipping: List['PointClipping'], projectorSampleRate: fl self.phaseFilter = phaseFilter # Adaptive sampling settings. self.adaptiveSampling = adaptiveSampling + # Point clipping settings. + self.pointClipping = pointClipping # Normal estimation settings. self.normalEstimation = normalEstimation # Outlier removal settings. diff --git a/maf_three/MF/V3/Settings/ScanData.py b/maf_three/MF/V3/Settings/ScanData.py index c1f534e..5bc5314 100644 --- a/maf_three/MF/V3/Settings/ScanData.py +++ b/maf_three/MF/V3/Settings/ScanData.py @@ -27,14 +27,14 @@ class MergeStep(Enum): Simplified = "Simplified" # The combined or remeshed mesh is simplified to a reduced number of triangles. Textured = "Textured" # The merged mesh has been textured. - def __init__(self, index: int, buffers: List['Buffer'], metadata: List['Metadata'], mergeStep: 'MergeStep' = None): + def __init__(self, index: int, mergeStep: 'MergeStep' = None, buffers: List['Buffer'] = None, metadata: List['Metadata'] = None): # Requested index of the scan in the current open project. self.index = index + # The merge process step if requesting merge data. + self.mergeStep = mergeStep # Requested scan buffers. self.buffers = buffers # Requested scan metadata. self.metadata = metadata - # The merge process step if requesting merge data. - self.mergeStep = mergeStep diff --git a/maf_three/MF/V3/Settings/ScanSelection.py b/maf_three/MF/V3/Settings/ScanSelection.py index ed2e6be..8c5977d 100644 --- a/maf_three/MF/V3/Settings/ScanSelection.py +++ b/maf_three/MF/V3/Settings/ScanSelection.py @@ -10,7 +10,7 @@ class Mode(Enum): visible = "visible" # Select visible scans. all = "all" # Select all scans. - def __init__(self, mode: 'Mode', groups: List[int]): + def __init__(self, mode: 'Mode', groups: List[int] = None): # The scan selection mode. self.mode = mode """ diff --git a/maf_three/MF/V3/Settings/Software.py b/maf_three/MF/V3/Settings/Software.py index 8ab2263..b014fd1 100644 --- a/maf_three/MF/V3/Settings/Software.py +++ b/maf_three/MF/V3/Settings/Software.py @@ -9,7 +9,7 @@ class Package(Enum): server = "server" # The server software package. frontend = "frontend" # The frontend software package. - def __init__(self, installed: List['Package'], available: List['Package'], nightlyIncluded: bool = None): + def __init__(self, installed: List['Package'] = None, available: List['Package'] = None, nightlyIncluded: bool = None): # Request installed software packages. If undefined all installed packages are returned. self.installed = installed # Request available software packages. If undefined all available packages are returned. diff --git a/maf_three/MF/V3/Settings/Tutorials.py b/maf_three/MF/V3/Settings/Tutorials.py index 19d34f6..569d51a 100644 --- a/maf_three/MF/V3/Settings/Tutorials.py +++ b/maf_three/MF/V3/Settings/Tutorials.py @@ -5,7 +5,7 @@ class Tutorials: # Tutorials settings. class Viewed: # Viewed tutorials. - def __init__(self, pages: List[str]): + def __init__(self, pages: List[str] = None): # Viewed tutorials pages. self.pages = pages diff --git a/maf_three/MF/V3/Tasks/DepthMap.py b/maf_three/MF/V3/Tasks/DepthMap.py index 47c3cfd..4dfcff3 100644 --- a/maf_three/MF/V3/Tasks/DepthMap.py +++ b/maf_three/MF/V3/Tasks/DepthMap.py @@ -110,15 +110,15 @@ def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None class Response: # Server response for the `DepthMap` task. - def __init__(self, Index: int, Type: str, Output: List[float], Input: MF_V3_Settings_Scan_Scan = None, State: MF_V3_Task_TaskState = None, Error: str = None): + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None, Output: List[float] = None, State: MF_V3_Task_TaskState = None, Error: str = None): # The unique identifier generated by the client. self.Index = Index # "DepthMap" self.Type = Type - # The 9 values of the camera matrix corresponding to the depth map (row-major). - self.Output = Output # Requested scan settings. self.Input = Input + # The 9 values of the camera matrix corresponding to the depth map (row-major). + self.Output = Output # The current state of the task. self.State = State # A string describing the error if the task has failed. diff --git a/maf_three/MF/V3/Tasks/ListExportFormats.py b/maf_three/MF/V3/Tasks/ListExportFormats.py index ec2b30b..326b812 100644 --- a/maf_three/MF/V3/Tasks/ListExportFormats.py +++ b/maf_three/MF/V3/Tasks/ListExportFormats.py @@ -69,7 +69,7 @@ def __init__(self, Index: int, Type: str): class Response: # Server response for the `ListExportFormats` task. - def __init__(self, Index: int, Type: str, Output: List[MF_V3_Descriptors_Export_Export], State: MF_V3_Task_TaskState = None, Error: str = None): + def __init__(self, Index: int, Type: str, Output: List[MF_V3_Descriptors_Export_Export] = None, State: MF_V3_Task_TaskState = None, Error: str = None): # The unique identifier generated by the client. self.Index = Index # "ListExportFormats" diff --git a/maf_three/MF/V3/Tasks/ListScans.py b/maf_three/MF/V3/Tasks/ListScans.py index a6047f7..8926274 100644 --- a/maf_three/MF/V3/Tasks/ListScans.py +++ b/maf_three/MF/V3/Tasks/ListScans.py @@ -60,7 +60,7 @@ def __init__(self, Index: int, Type: str): class Response: # Server response for the `ListScans` task. - def __init__(self, Index: int, Type: str, Output: List[MF_V3_Descriptors_Project_Project.Group], State: MF_V3_Task_TaskState = None, Error: str = None): + def __init__(self, Index: int, Type: str, Output: List[MF_V3_Descriptors_Project_Project.Group] = None, State: MF_V3_Task_TaskState = None, Error: str = None): # The unique identifier generated by the client. self.Index = Index # "ListScans" diff --git a/maf_three/MF/V3/Tasks/MoveGroup.py b/maf_three/MF/V3/Tasks/MoveGroup.py index 3897331..ba5d1aa 100644 --- a/maf_three/MF/V3/Tasks/MoveGroup.py +++ b/maf_three/MF/V3/Tasks/MoveGroup.py @@ -44,7 +44,7 @@ class MoveGroup: """ class Request: # Client request for the `MoveGroup` task. - def __init__(self, Index: int, Type: str, Input: List[int]): + def __init__(self, Index: int, Type: str, Input: List[int] = None): # A unique identifier generated by the client. self.Index = Index # "MoveGroup" @@ -60,15 +60,15 @@ def __init__(self, Index: int, Type: str, Input: List[int]): class Response: # Server response for the `MoveGroup` task. - def __init__(self, Index: int, Type: str, Input: List[int], Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, Input: List[int] = None, State: MF_V3_Task_TaskState = None, Error: str = None): # The unique identifier generated by the client. self.Index = Index # "MoveGroup" self.Type = Type - # The requested source and destination move indices. - self.Input = Input # The root scan group in the current open project. self.Output = Output + # The requested source and destination move indices. + self.Input = Input # The current state of the task. self.State = State # A string describing the error if the task has failed. diff --git a/maf_three/MF/V3/Tasks/RemoveGroups.py b/maf_three/MF/V3/Tasks/RemoveGroups.py index bf2a77d..cc0cbd3 100644 --- a/maf_three/MF/V3/Tasks/RemoveGroups.py +++ b/maf_three/MF/V3/Tasks/RemoveGroups.py @@ -35,7 +35,7 @@ class RemoveGroups: """ class Request: # Client request for the `RemoveGroups` task. - def __init__(self, Index: int, Type: str, Input: List[int]): + def __init__(self, Index: int, Type: str, Input: List[int] = None): # A unique identifier generated by the client. self.Index = Index # "RemoveGroups" @@ -45,15 +45,15 @@ def __init__(self, Index: int, Type: str, Input: List[int]): class Response: # Server response for the `RemoveGroups` task. - def __init__(self, Index: int, Type: str, Input: List[int], Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, Input: List[int] = None, State: MF_V3_Task_TaskState = None, Error: str = None): # The unique identifier generated by the client. self.Index = Index # "RemoveGroups" self.Type = Type - # The requested of indices of the scan groups to remove. - self.Input = Input # The root scan group in the current open project. self.Output = Output + # The requested of indices of the scan groups to remove. + self.Input = Input # The current state of the task. self.State = State # A string describing the error if the task has failed. diff --git a/maf_three/MF/V3/Tasks/RemoveProjects.py b/maf_three/MF/V3/Tasks/RemoveProjects.py index 78f7815..aef7e61 100644 --- a/maf_three/MF/V3/Tasks/RemoveProjects.py +++ b/maf_three/MF/V3/Tasks/RemoveProjects.py @@ -39,7 +39,7 @@ class RemoveProjects: """ class Request: # Client request for the `RemoveProjects` task. - def __init__(self, Index: int, Type: str, Input: List[int]): + def __init__(self, Index: int, Type: str, Input: List[int] = None): # A unique identifier generated by the client. self.Index = Index # "RemoveProjects" @@ -49,7 +49,7 @@ def __init__(self, Index: int, Type: str, Input: List[int]): class Response: # Server response for the `RemoveProjects` task. - def __init__(self, Index: int, Type: str, Input: List[int], Output: MF_V3_Descriptors_Project_Project.Brief = None, State: MF_V3_Task_TaskState = None, Error: str = None): + def __init__(self, Index: int, Type: str, Input: List[int] = None, Output: MF_V3_Descriptors_Project_Project.Brief = None, State: MF_V3_Task_TaskState = None, Error: str = None): # The unique identifier generated by the client. self.Index = Index # "RemoveProjects" diff --git a/maf_three/MF/V3/Three.py b/maf_three/MF/V3/Three.py index cb40205..f594b21 100644 --- a/maf_three/MF/V3/Three.py +++ b/maf_three/MF/V3/Three.py @@ -78,6 +78,7 @@ from MF.V3.Tasks.TurntableCalibration import TurntableCalibration as MF_V3_Tasks_TurntableCalibration from MF.V3.Tasks.UpdateSettings import UpdateSettings as MF_V3_Tasks_UpdateSettings from MF.V3.Tasks.UploadProject import UploadProject as MF_V3_Tasks_UploadProject +from typing import List def list_network_interfaces(self) -> Task: @@ -328,7 +329,7 @@ def close_project(self) -> Task: return task -def remove_projects(self, Input: int) -> Task: +def remove_projects(self, Input: List[int] = None) -> Task: # Remove selected projects. remove_projects_request = MF_V3_Tasks_RemoveProjects.Request( Index=0, @@ -337,8 +338,7 @@ def remove_projects(self, Input: int) -> Task: ) remove_projects_response = MF_V3_Tasks_RemoveProjects.Response( Index=0, - Type="RemoveProjects", - Input=Input + Type="RemoveProjects" ) task = Task(Index=0, Type="RemoveProjects", Input=remove_projects_request, Output=remove_projects_response) self.SendTask(task) @@ -369,24 +369,23 @@ def list_scans(self) -> Task: ) list_scans_response = MF_V3_Tasks_ListScans.Response( Index=0, - Type="ListScans", - Output=None + Type="ListScans" ) task = Task(Index=0, Type="ListScans", Input=list_scans_request, Output=list_scans_response) self.SendTask(task) return task -def scan_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: +def scan_data(self, index: int, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None, buffers: List[MF_V3_Settings_ScanData_ScanData.Buffer] = None, metadata: List[MF_V3_Settings_ScanData_ScanData.Metadata] = None) -> Task: # Download the raw scan data for a scan in the current open project. scan_data_request = MF_V3_Tasks_ScanData.Request( Index=0, Type="ScanData", Input=MF_V3_Settings_ScanData_ScanData( index=index, + mergeStep=mergeStep, buffers=buffers, metadata=metadata, - mergeStep=mergeStep, ) ) scan_data_response = MF_V3_Tasks_ScanData.Response( @@ -394,9 +393,9 @@ def scan_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer Type="ScanData", Input=MF_V3_Settings_ScanData_ScanData( index=index, + mergeStep=mergeStep, buffers=buffers, metadata=metadata, - mergeStep=mergeStep, ), Output=None ) @@ -424,19 +423,19 @@ def set_project(self, index: int = None, name: str = None) -> Task: return task -def set_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: +def set_group(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> Task: # Set scan group properties. set_group_request = MF_V3_Tasks_SetGroup.Request( Index=0, Type="SetGroup", Input=MF_V3_Settings_Group_Group( index=index, - color=color, - rotation=rotation, - translation=translation, name=name, + color=color, visible=visible, collapsed=collapsed, + rotation=rotation, + translation=translation, ) ) set_group_response = MF_V3_Tasks_SetGroup.Response( @@ -444,12 +443,12 @@ def set_group(self, index: int, color: float, rotation: float, translation: floa Type="SetGroup", Input=MF_V3_Settings_Group_Group( index=index, - color=color, - rotation=rotation, - translation=translation, name=name, + color=color, visible=visible, collapsed=collapsed, + rotation=rotation, + translation=translation, ), Output=None ) @@ -458,19 +457,19 @@ def set_group(self, index: int, color: float, rotation: float, translation: floa return task -def new_group(self, color: float, rotation: float, translation: float, parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None) -> Task: +def new_group(self, parentIndex: int = None, baseName: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> Task: # Create a new scan group. new_group_request = MF_V3_Tasks_NewGroup.Request( Index=0, Type="NewGroup", Input=MF_V3_Settings_NewGroup_NewGroup( - color=color, - rotation=rotation, - translation=translation, parentIndex=parentIndex, baseName=baseName, + color=color, visible=visible, collapsed=collapsed, + rotation=rotation, + translation=translation, ) ) new_group_response = MF_V3_Tasks_NewGroup.Response( @@ -483,7 +482,7 @@ def new_group(self, color: float, rotation: float, translation: float, parentInd return task -def move_group(self, Input: int) -> Task: +def move_group(self, Input: List[int] = None) -> Task: # Move a scan group. move_group_request = MF_V3_Tasks_MoveGroup.Request( Index=0, @@ -493,7 +492,6 @@ def move_group(self, Input: int) -> Task: move_group_response = MF_V3_Tasks_MoveGroup.Response( Index=0, Type="MoveGroup", - Input=Input, Output=None ) task = Task(Index=0, Type="MoveGroup", Input=move_group_request, Output=move_group_response) @@ -537,19 +535,19 @@ def split_group(self, Input: int) -> Task: return task -def transform_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> Task: +def transform_group(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> Task: # Apply a rigid transformation to a group. transform_group_request = MF_V3_Tasks_TransformGroup.Request( Index=0, Type="TransformGroup", Input=MF_V3_Settings_Group_Group( index=index, - color=color, - rotation=rotation, - translation=translation, name=name, + color=color, visible=visible, collapsed=collapsed, + rotation=rotation, + translation=translation, ) ) transform_group_response = MF_V3_Tasks_TransformGroup.Response( @@ -557,12 +555,12 @@ def transform_group(self, index: int, color: float, rotation: float, translation Type="TransformGroup", Input=MF_V3_Settings_Group_Group( index=index, - color=color, - rotation=rotation, - translation=translation, name=name, + color=color, visible=visible, collapsed=collapsed, + rotation=rotation, + translation=translation, ), Output=None ) @@ -571,7 +569,7 @@ def transform_group(self, index: int, color: float, rotation: float, translation return task -def remove_groups(self, Input: int) -> Task: +def remove_groups(self, Input: List[int] = None) -> Task: # Remove selected scan groups. remove_groups_request = MF_V3_Tasks_RemoveGroups.Request( Index=0, @@ -581,7 +579,6 @@ def remove_groups(self, Input: int) -> Task: remove_groups_response = MF_V3_Tasks_RemoveGroups.Response( Index=0, Type="RemoveGroups", - Input=Input, Output=None ) task = Task(Index=0, Type="RemoveGroups", Input=remove_groups_request, Output=remove_groups_response) @@ -669,16 +666,16 @@ def merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, re return task -def merge_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffer, metadata: MF_V3_Settings_ScanData_ScanData.Metadata, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None) -> Task: +def merge_data(self, index: int, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None, buffers: List[MF_V3_Settings_ScanData_ScanData.Buffer] = None, metadata: List[MF_V3_Settings_ScanData_ScanData.Metadata] = None) -> Task: # Download the raw scan data for the current merge process. merge_data_request = MF_V3_Tasks_MergeData.Request( Index=0, Type="MergeData", Input=MF_V3_Settings_ScanData_ScanData( index=index, + mergeStep=mergeStep, buffers=buffers, metadata=metadata, - mergeStep=mergeStep, ) ) merge_data_response = MF_V3_Tasks_MergeData.Response( @@ -686,9 +683,9 @@ def merge_data(self, index: int, buffers: MF_V3_Settings_ScanData_ScanData.Buffe Type="MergeData", Input=MF_V3_Settings_ScanData_ScanData( index=index, + mergeStep=mergeStep, buffers=buffers, metadata=metadata, - mergeStep=mergeStep, ), Output=None ) @@ -721,8 +718,7 @@ def list_export_formats(self) -> Task: ) list_export_formats_response = MF_V3_Tasks_ListExportFormats.Response( Index=0, - Type="ListExportFormats", - Output=None + Type="ListExportFormats" ) task = Task(Index=0, Type="ListExportFormats", Input=list_export_formats_request, Output=list_export_formats_response) self.SendTask(task) @@ -844,7 +840,7 @@ def has_turntable(self) -> Task: return task -def system_info(self, installed: MF_V3_Settings_Software_Software.Package, available: MF_V3_Settings_Software_Software.Package, nightlyIncluded: bool = None) -> Task: +def system_info(self, installed: List[MF_V3_Settings_Software_Software.Package] = None, available: List[MF_V3_Settings_Software_Software.Package] = None, nightlyIncluded: bool = None) -> Task: # Get system information. system_info_request = MF_V3_Tasks_SystemInfo.Request( Index=0, @@ -1002,7 +998,7 @@ def stop_video(self) -> Task: return task -def set_cameras(self, selection: int, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> Task: +def set_cameras(self, selection: List[int] = None, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> Task: # Apply camera settings to one or both cameras. set_cameras_request = MF_V3_Tasks_SetCameras.Request( Index=0, @@ -1025,17 +1021,17 @@ def set_cameras(self, selection: int, autoExposure: bool = None, exposure: int = return task -def set_projector(self, color: float, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None) -> Task: +def set_projector(self, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None, color: List[float] = None) -> Task: # Apply projector settings. set_projector_request = MF_V3_Tasks_SetProjector.Request( Index=0, Type="SetProjector", Input=MF_V3_Settings_Projector_Projector( - color=color, on=on, brightness=brightness, pattern=pattern, image=image, + color=color, ) ) set_projector_response = MF_V3_Tasks_SetProjector.Response( @@ -1047,14 +1043,14 @@ def set_projector(self, color: float, on: bool = None, brightness: float = None, return task -def auto_focus(self, cameras: MF_V3_Settings_AutoFocus_AutoFocus.Camera, applyAll: bool) -> Task: +def auto_focus(self, applyAll: bool, cameras: List[MF_V3_Settings_AutoFocus_AutoFocus.Camera] = None) -> Task: # Auto focus one or both cameras. auto_focus_request = MF_V3_Tasks_AutoFocus.Request( Index=0, Type="AutoFocus", Input=MF_V3_Settings_AutoFocus_AutoFocus( - cameras=cameras, applyAll=applyAll, + cameras=cameras, ) ) auto_focus_response = MF_V3_Tasks_AutoFocus.Response( @@ -1120,8 +1116,7 @@ def depth_map(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V ) depth_map_response = MF_V3_Tasks_DepthMap.Response( Index=0, - Type="DepthMap", - Output=None + Type="DepthMap" ) task = Task(Index=0, Type="DepthMap", Input=depth_map_request, Output=depth_map_response) self.SendTask(task) diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index 72ac1fe..00903d5 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -10,6 +10,7 @@ from maf_three.scanner import Scanner import maf_three.MF.V3.Three as Three +from maf_three.MF.V3.Settings.Projector import Projector def main(): @@ -17,30 +18,36 @@ def main(): scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) scanner.Connect("ws://matterandform.local:8081") - scanner.set_projector(on=True, brightness=1.0, color=[1,1,1]) - # Sleep for 5 seconds - time.sleep(1) - - # task.Projector.CopyFrom(Projector(on=True, brightness=1.0, color=[1,1,1])) - # print("test2") - # print(task) - # scanner.SendTask(task) + # # Set white color + # scanner.set_projector(color=[1,1,1], on=True, brightness=1.0) + # # Sleep for 1 second # time.sleep(1) - # #### Project Red - # print('Project Red') - # scanner.SendTask(1, V3Task.SetProjector, Projector(color=[1,0,0])) + # # # Set red color + # scanner.set_projector(color=[1,0,0]) + # # Sleep for 1 second # time.sleep(1) - # #### Project Green - # print('Project Green') - # scanner.SendTask(2, V3Task.SetProjector, Projector(color=[0,1,0])) + # # Set green color + # scanner.set_projector(color=[0,1,0]) + # # Sleep for 1 second # time.sleep(1) - # #### Project Blue - # print('Project Blue') - # scanner.SendTask(3, V3Task.SetProjector, Projector(color=[0,0,1])) + # # Set blue color + # scanner.set_projector(color=[0,0,1]) + # # Sleep for 1 second + # time.sleep(1) + + # # Set brightness to 0.25. The other settings will persist + # scanner.set_projector(brightness=0.25) # time.sleep(1) + + pattern = Projector.Pattern(Projector.Orientation.Vertical,4, 1) + scanner.set_projector(True, 1.0, pattern) + time.sleep(1) + + # Turn off + scanner.set_projector(on=False) # #### Project Vertical Pattern # print('Project Vertical Pattern (Identical image columns)') diff --git a/maf_three/scanner.pyi b/maf_three/scanner.pyi index 277a146..bcb9815 100644 --- a/maf_three/scanner.pyi +++ b/maf_three/scanner.pyi @@ -95,7 +95,7 @@ import time import types import typing import websocket -from typing import Optional, Callable, Any, Union +from typing import Optional, Callable, Any, Union, List class Scanner: @@ -106,7 +106,7 @@ class Scanner: def SendTask(self, task, buffer: bytes = None) -> Any: ... def add_merge_to_project(self) -> MF.V3.Task.Task: ... def align(self, source: int, target: int, rough: MF.V3.Settings.Align.Align.Rough = None, fine: MF.V3.Settings.Align.Align.Fine = None) -> MF.V3.Task.Task: ... - def auto_focus(self, cameras: MF.V3.Settings.AutoFocus.AutoFocus.Camera, applyAll: bool) -> MF.V3.Task.Task: ... + def auto_focus(self, applyAll: bool, cameras: List[MF.V3.Settings.AutoFocus.AutoFocus.Camera] = None) -> MF.V3.Task.Task: ... def bounding_box(self, selection: MF.V3.Settings.ScanSelection.ScanSelection, axisAligned: bool) -> MF.V3.Task.Task: ... def calibrate_cameras(self) -> MF.V3.Task.Task: ... def calibrate_turntable(self) -> MF.V3.Task.Task: ... @@ -133,30 +133,30 @@ class Scanner: def list_settings(self) -> MF.V3.Task.Task: ... def list_wifi(self) -> MF.V3.Task.Task: ... def merge(self, selection: MF.V3.Settings.ScanSelection.ScanSelection = None, remesh: MF.V3.Settings.Merge.Merge.Remesh = None, simplify: MF.V3.Settings.Merge.Merge.Simplify = None, texturize: bool = None) -> MF.V3.Task.Task: ... - def merge_data(self, index: int, buffers: MF.V3.Settings.ScanData.ScanData.Buffer, metadata: MF.V3.Settings.ScanData.ScanData.Metadata, mergeStep: MF.V3.Settings.ScanData.ScanData.MergeStep = None) -> MF.V3.Task.Task: ... - def move_group(self, Input: int) -> MF.V3.Task.Task: ... - def new_group(self, color: float, rotation: float, translation: float, parentIndex: int = None, baseName: str = None, visible: bool = None, collapsed: bool = None) -> MF.V3.Task.Task: ... + def merge_data(self, index: int, mergeStep: MF.V3.Settings.ScanData.ScanData.MergeStep = None, buffers: List[MF.V3.Settings.ScanData.ScanData.Buffer] = None, metadata: List[MF.V3.Settings.ScanData.ScanData.Metadata] = None) -> MF.V3.Task.Task: ... + def move_group(self, Input: List[int] = None) -> MF.V3.Task.Task: ... + def new_group(self, parentIndex: int = None, baseName: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> MF.V3.Task.Task: ... def new_project(self, Input: str = None) -> MF.V3.Task.Task: ... def new_scan(self, camera: MF.V3.Settings.Camera.Camera = None, projector: MF.V3.Settings.Projector.Projector = None, turntable: MF.V3.Settings.Turntable.Turntable = None, capture: MF.V3.Settings.Capture.Capture = None, processing: MF.V3.Settings.Scan.Scan.Processing = None) -> MF.V3.Task.Task: ... def open_project(self, Input: int) -> MF.V3.Task.Task: ... def pop_settings(self, Input: bool = None) -> MF.V3.Task.Task: ... def push_settings(self) -> MF.V3.Task.Task: ... def reboot(self) -> MF.V3.Task.Task: ... - def remove_groups(self, Input: int) -> MF.V3.Task.Task: ... - def remove_projects(self, Input: int) -> MF.V3.Task.Task: ... + def remove_groups(self, Input: List[int] = None) -> MF.V3.Task.Task: ... + def remove_projects(self, Input: List[int] = None) -> MF.V3.Task.Task: ... def restore_factory_calibration(self) -> MF.V3.Task.Task: ... def rotate_turntable(self, Input: int) -> MF.V3.Task.Task: ... - def scan_data(self, index: int, buffers: MF.V3.Settings.ScanData.ScanData.Buffer, metadata: MF.V3.Settings.ScanData.ScanData.Metadata, mergeStep: MF.V3.Settings.ScanData.ScanData.MergeStep = None) -> MF.V3.Task.Task: ... - def set_cameras(self, selection: int, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> MF.V3.Task.Task: ... - def set_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> MF.V3.Task.Task: ... + def scan_data(self, index: int, mergeStep: MF.V3.Settings.ScanData.ScanData.MergeStep = None, buffers: List[MF.V3.Settings.ScanData.ScanData.Buffer] = None, metadata: List[MF.V3.Settings.ScanData.ScanData.Metadata] = None) -> MF.V3.Task.Task: ... + def set_cameras(self, selection: List[int] = None, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> MF.V3.Task.Task: ... + def set_group(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> MF.V3.Task.Task: ... def set_project(self, index: int = None, name: str = None) -> MF.V3.Task.Task: ... - def set_projector(self, color: float, on: bool = None, brightness: float = None, pattern: MF.V3.Settings.Projector.Projector.Pattern = None, image: MF.V3.Settings.Projector.Projector.Image = None) -> MF.V3.Task.Task: ... + def set_projector(self, on: bool = None, brightness: float = None, pattern: MF.V3.Settings.Projector.Projector.Pattern = None, image: MF.V3.Settings.Projector.Projector.Image = None, color: List[float] = None) -> MF.V3.Task.Task: ... def shutdown(self) -> MF.V3.Task.Task: ... def split_group(self, Input: int) -> MF.V3.Task.Task: ... def start_video(self) -> MF.V3.Task.Task: ... def stop_video(self) -> MF.V3.Task.Task: ... - def system_info(self, installed: MF.V3.Settings.Software.Software.Package, available: MF.V3.Settings.Software.Software.Package, nightlyIncluded: bool = None) -> MF.V3.Task.Task: ... - def transform_group(self, index: int, color: float, rotation: float, translation: float, name: str = None, visible: bool = None, collapsed: bool = None) -> MF.V3.Task.Task: ... + def system_info(self, installed: List[MF.V3.Settings.Software.Software.Package] = None, available: List[MF.V3.Settings.Software.Software.Package] = None, nightlyIncluded: bool = None) -> MF.V3.Task.Task: ... + def transform_group(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> MF.V3.Task.Task: ... def turntable_calibration(self) -> MF.V3.Task.Task: ... def update_settings(self, advanced: MF.V3.Settings.Advanced.Advanced = None, camera: MF.V3.Settings.Camera.Camera = None, capture: MF.V3.Settings.Capture.Capture = None, i18n: MF.V3.Settings.I18n.I18n = None, projector: MF.V3.Settings.Projector.Projector = None, style: MF.V3.Settings.Style.Style = None, turntable: MF.V3.Settings.Turntable.Turntable = None, tutorials: MF.V3.Settings.Tutorials.Tutorials = None, viewer: MF.V3.Settings.Viewer.Viewer = None, software: MF.V3.Settings.Software.Software = None) -> MF.V3.Task.Task: ... def upload_project(self) -> MF.V3.Task.Task: ... \ No newline at end of file diff --git a/maf_three/serialization.py b/maf_three/serialization.py index 01d7087..502ccb6 100644 --- a/maf_three/serialization.py +++ b/maf_three/serialization.py @@ -1,12 +1,29 @@ -# serialization.py - -from array import * +# import logging +from array import array import json - from google.protobuf.json_format import MessageToDict +from enum import Enum + +# Configure logging +# logging.basicConfig(level=logging.DEBUG) +# logger = logging.getLogger(__name__) + +def Serializer(object, visited=None): + if visited is None: + visited = set() + # logger.debug(f"Serializing object: {object} (id: {id(object)})") + + # Detect circular references + if id(object) in visited: + # logger.warning(f"Circular reference detected for object: {object} (id: {id(object)})") + return None + visited.add(id(object)) + + # Handle enums + if isinstance(object, Enum): + return object.name -def Serializer(object): # Array is not JSON serializable => Convert to list if isinstance(object, array): return object.tolist() @@ -18,11 +35,17 @@ def Serializer(object): preserving_proto_field_name=True, including_default_value_fields=True ) - return dict(filter(lambda tup:tup[1] is not None, dic.items())) + return dict(filter(lambda tup: tup[1] is not None, dic.items())) # Our objects - return dict(filter(lambda tup:tup[1] is not None, object.__dict__.items())) + if hasattr(object, '__dict__'): + dic = dict(filter(lambda tup: tup[1] is not None, object.__dict__.items())) + for key, value in dic.items(): + dic[key] = Serializer(value, visited) + return dic + # Handle other types if necessary + return object def TO_JSON(object) -> str: """ @@ -35,8 +58,8 @@ def TO_JSON(object) -> str: The string representing the object. """ - return json.dumps( - object, - default=Serializer, - allow_nan=False) + object, + default=Serializer, + allow_nan=False + ) \ No newline at end of file diff --git a/scripts/build-proto.py b/scripts/build-proto.py index 990cf4f..6af5a24 100644 --- a/scripts/build-proto.py +++ b/scripts/build-proto.py @@ -64,7 +64,8 @@ def generate_pyi(scanner_module_name, three_module_name, output_file): pyi_content.append(f"import {imp}") # Add specific imports from typing - pyi_content.append("from typing import Optional, Callable, Any, Union") + pyi_content.append("from typing import Optional, Callable, Any, Union, List") + # Add class definition pyi_content.append("\n\nclass Scanner:") diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index f8d69a6..715b60a 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -544,8 +544,14 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: # Sort the properties so that optionals are last method_properties = sorted(method_properties, key=lambda x: x.optional) + descriptor = ImportDescriptor("typing", "List", "") + current_node.imports.append(descriptor) + for prop in method_properties: - service_code += f", {prop.name}: {prop.type}" + if prop.repeated: + service_code += f", {prop.name}: List[{prop.type}]" + else: + service_code += f", {prop.name}: {prop.type}" if prop.optional: service_code += " = None" if prop.import_descriptor != None: diff --git a/scripts/tree.py b/scripts/tree.py index d4c1097..1045fd3 100644 --- a/scripts/tree.py +++ b/scripts/tree.py @@ -9,6 +9,8 @@ def __init__(self, type_: str, name: str, optional: bool, comment: str, repeated self.repeated: bool = repeated self.comment: str = comment self.import_descriptor: ImportDescriptor = import_descriptor + if self.repeated: + self.optional = True class TreeProcedure: From d9123eb4cff748604d90e79968e8b7ee4fa4e70a Mon Sep 17 00:00:00 2001 From: drewsipher Date: Mon, 30 Sep 2024 17:00:53 -0400 Subject: [PATCH 59/86] Starting to implement buffers --- maf_three/MF/V3/Three.py | 8 ++--- maf_three/examples/projector.py | 58 ++++++++++++++------------------- maf_three/scanner.pyi | 4 +-- scripts/transpileProto.py | 38 ++++++++++++++++++--- 4 files changed, 63 insertions(+), 45 deletions(-) diff --git a/maf_three/MF/V3/Three.py b/maf_three/MF/V3/Three.py index f594b21..b9fc123 100644 --- a/maf_three/MF/V3/Three.py +++ b/maf_three/MF/V3/Three.py @@ -266,7 +266,7 @@ def download_project(self, Input: int) -> Task: return task -def upload_project(self) -> Task: +def upload_project(self, buffer: bytes) -> Task: # Upload a project to the scanner. upload_project_request = MF_V3_Tasks_UploadProject.Request( Index=0, @@ -277,7 +277,7 @@ def upload_project(self) -> Task: Type="UploadProject" ) task = Task(Index=0, Type="UploadProject", Input=upload_project_request, Output=upload_project_response) - self.SendTask(task) + self.SendTask(task, buffer) return task @@ -1021,7 +1021,7 @@ def set_cameras(self, selection: List[int] = None, autoExposure: bool = None, ex return task -def set_projector(self, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None, color: List[float] = None) -> Task: +def set_projector(self, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None, color: List[float] = None, buffer: bytes = None) -> Task: # Apply projector settings. set_projector_request = MF_V3_Tasks_SetProjector.Request( Index=0, @@ -1039,7 +1039,7 @@ def set_projector(self, on: bool = None, brightness: float = None, pattern: MF_V Type="SetProjector" ) task = Task(Index=0, Type="SetProjector", Input=set_projector_request, Output=set_projector_response) - self.SendTask(task) + self.SendTask(task, buffer) return task diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index 00903d5..b003a8f 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -11,6 +11,8 @@ from maf_three.scanner import Scanner import maf_three.MF.V3.Three as Three from maf_three.MF.V3.Settings.Projector import Projector +from maf_three.MF.V3.Settings.Video import Video +from maf_three.MF.V3.Settings.Rectangle import Rectangle def main(): @@ -20,10 +22,10 @@ def main(): # # Set white color # scanner.set_projector(color=[1,1,1], on=True, brightness=1.0) - # # Sleep for 1 second + # Sleep for 1 second # time.sleep(1) - # # # Set red color + # # Set red color # scanner.set_projector(color=[1,0,0]) # # Sleep for 1 second # time.sleep(1) @@ -42,42 +44,30 @@ def main(): # scanner.set_projector(brightness=0.25) # time.sleep(1) - pattern = Projector.Pattern(Projector.Orientation.Vertical,4, 1) - scanner.set_projector(True, 1.0, pattern) - time.sleep(1) - - # Turn off - scanner.set_projector(on=False) - - # #### Project Vertical Pattern - # print('Project Vertical Pattern (Identical image columns)') - # scanner.SendTask(4, V3Task.SetProjector, Projector(pattern=Projector.Pattern(orientation=Projector.Orientation.Vertical,frequency=4,phase=1))) + # pattern = Projector.Pattern(Projector.Orientation.Vertical,4, 1) + # scanner.set_projector(True, 1.0, pattern, None) # time.sleep(1) - # #### Project Horizontal Pattern - # print('Project Horizontal Pattern (Identical image rows)') - # scanner.SendTask(5, V3Task.SetProjector, Projector(pattern=Projector.Pattern(orientation=Projector.Orientation.Horizontal,frequency=4,phase=1))) - # time.sleep(1) + ### Project an image + print('Project Image') + width = 640 + height = 480 + img = np.zeros([height, width, 3], np.uint8) + for y in range(height): + for x in range(0, width): + img[y,x] = ( + 255 * y / height , # Blue + 255 * x / width , # Green + 255 - 255 * y / height # Red + ) + source = Projector.Image.Source(format = Video.Format.BGR888, width=width, height=height, step=3*width, fixAspectRatio=True) + scanner.set_projector(on=True, brightness=1.0, pattern=None, image=Projector.Image(source, Rectangle(0,0,width,height)), color=None, buffer=img.tobytes()) + + time.sleep(1) - # ### Project an image - # print('Project Image') - # width = 640 - # height = 480 - # image = np.zeros([height, width, 3], np.uint8) - # for y in range(height): - # for x in range(0, width): - # image[y,x] = ( - # 255 * y / height , # Blue - # 255 * x / width , # Green - # 255 - 255 * y / height # Red - # ) - # source = Projector.Image.Source(format = Video.Format.BGR888, width=width, height=height, step=3*width, fixAspectRatio=True) - # scanner.SendTaskWithBuffer(6, V3Task.SetProjector, image.tobytes(), Projector(image=Projector.Image(source=source, target=Rectangle(x=100,y=100,width=640, height=480))) ) - # time.sleep(1) + #### Turn OFF + scanner.set_projector(on=False) - # #### Turn OFF - # print('Turn OFF') - # scanner.SendTask(7, V3Task.SetProjector, Projector(on=False)) except Exception as error: print('Error: ', error) diff --git a/maf_three/scanner.pyi b/maf_three/scanner.pyi index bcb9815..c88c209 100644 --- a/maf_three/scanner.pyi +++ b/maf_three/scanner.pyi @@ -150,7 +150,7 @@ class Scanner: def set_cameras(self, selection: List[int] = None, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> MF.V3.Task.Task: ... def set_group(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> MF.V3.Task.Task: ... def set_project(self, index: int = None, name: str = None) -> MF.V3.Task.Task: ... - def set_projector(self, on: bool = None, brightness: float = None, pattern: MF.V3.Settings.Projector.Projector.Pattern = None, image: MF.V3.Settings.Projector.Projector.Image = None, color: List[float] = None) -> MF.V3.Task.Task: ... + def set_projector(self, on: bool = None, brightness: float = None, pattern: MF.V3.Settings.Projector.Projector.Pattern = None, image: MF.V3.Settings.Projector.Projector.Image = None, color: List[float] = None, buffer: bytes = None) -> MF.V3.Task.Task: ... def shutdown(self) -> MF.V3.Task.Task: ... def split_group(self, Input: int) -> MF.V3.Task.Task: ... def start_video(self) -> MF.V3.Task.Task: ... @@ -159,4 +159,4 @@ class Scanner: def transform_group(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> MF.V3.Task.Task: ... def turntable_calibration(self) -> MF.V3.Task.Task: ... def update_settings(self, advanced: MF.V3.Settings.Advanced.Advanced = None, camera: MF.V3.Settings.Camera.Camera = None, capture: MF.V3.Settings.Capture.Capture = None, i18n: MF.V3.Settings.I18n.I18n = None, projector: MF.V3.Settings.Projector.Projector = None, style: MF.V3.Settings.Style.Style = None, turntable: MF.V3.Settings.Turntable.Turntable = None, tutorials: MF.V3.Settings.Tutorials.Tutorials = None, viewer: MF.V3.Settings.Viewer.Viewer = None, software: MF.V3.Settings.Software.Software = None) -> MF.V3.Task.Task: ... - def upload_project(self) -> MF.V3.Task.Task: ... \ No newline at end of file + def upload_project(self, buffer: bytes) -> MF.V3.Task.Task: ... \ No newline at end of file diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 715b60a..25f17d7 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -36,6 +36,26 @@ "str", "bytes" ] + +required_upload_procedures = [ + "UploadProject", + "RemoveVertices" +] + +optional_upload_procedures = [ + "SetProjector" +] + +required_download_procedures = [ + "ScanData", + "MergeData", + "Export", + "ExportMerge", + "ExportLogs", + "StartVideo", + "DepthMap", + "DownloadProject" +] def generate_python_code(output_dir: str, tree:Tree) -> set: @@ -458,7 +478,6 @@ def generate_enum_code(enum:TreeNode) -> str: def get_replacement_name(path:str) -> str: return path.replace(".", "_") - def generate_service_code( current_node:TreeNode, tree:Tree) -> str: """ @@ -478,7 +497,7 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: request_node = procedure.request response_node = procedure.response - + # create a method name from the name value, by adding underscores between camel case method_name = "" for i, c in enumerate(procedure.name): @@ -547,6 +566,9 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: descriptor = ImportDescriptor("typing", "List", "") current_node.imports.append(descriptor) + if procedure.name in required_upload_procedures: + service_code += ", buffer: bytes" + for prop in method_properties: if prop.repeated: service_code += f", {prop.name}: List[{prop.type}]" @@ -557,7 +579,9 @@ def generate_service_code( current_node:TreeNode, tree:Tree) -> str: if prop.import_descriptor != None: current_node.imports.append(prop.import_descriptor) - + if procedure.name in optional_upload_procedures: + service_code += ", buffer: bytes = None" + service_code += f") -> {task_name}:\n" service_code += add_indents(procedure.comment,1) @@ -611,9 +635,13 @@ def create_object_code(node:TreeNode, postfix:str, ignore_optionals:bool)->str: service_code += create_object_code(request_node, "request", False) service_code += create_object_code(response_node, "response", True) - + + service_code += f" task = {task_name}(Index=0, Type=\"{procedure.name}\", Input={method_name}_request, Output={method_name}_response)\n" - service_code += f" self.SendTask(task)\n" + if procedure.name in required_upload_procedures or procedure.name in optional_upload_procedures: + service_code += f" self.SendTask(task, buffer)\n" + else: + service_code += f" self.SendTask(task)\n" service_code += f" return task\n\n\n" return service_code From f1e9459a62b9442c2323281a378cd1b549c5700b Mon Sep 17 00:00:00 2001 From: drewsipher Date: Tue, 1 Oct 2024 12:19:54 -0400 Subject: [PATCH 60/86] Sending images working --- maf_three/examples/projector.py | 45 ++++++++++++++++----------------- maf_three/scanner.py | 9 +++++-- maf_three/serialization.py | 10 ++++---- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index b003a8f..71ccb2f 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -20,33 +20,33 @@ def main(): scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) scanner.Connect("ws://matterandform.local:8081") - # # Set white color - # scanner.set_projector(color=[1,1,1], on=True, brightness=1.0) + # Set white color + scanner.set_projector(color=[1,1,1], on=True, brightness=1.0) # Sleep for 1 second - # time.sleep(1) + time.sleep(1) - # # Set red color - # scanner.set_projector(color=[1,0,0]) - # # Sleep for 1 second - # time.sleep(1) + # Set red color + scanner.set_projector(color=[1,0,0]) + # Sleep for 1 second + time.sleep(1) - # # Set green color - # scanner.set_projector(color=[0,1,0]) - # # Sleep for 1 second - # time.sleep(1) + # Set green color + scanner.set_projector(color=[0,1,0]) + # Sleep for 1 second + time.sleep(1) - # # Set blue color - # scanner.set_projector(color=[0,0,1]) - # # Sleep for 1 second - # time.sleep(1) + # Set blue color + scanner.set_projector(color=[0,0,1]) + # Sleep for 1 second + time.sleep(1) - # # Set brightness to 0.25. The other settings will persist - # scanner.set_projector(brightness=0.25) - # time.sleep(1) + # Set brightness to 0.25. The other settings will persist + scanner.set_projector(brightness=0.25) + time.sleep(1) - # pattern = Projector.Pattern(Projector.Orientation.Vertical,4, 1) - # scanner.set_projector(True, 1.0, pattern, None) - # time.sleep(1) + pattern = Projector.Pattern(Projector.Orientation.Vertical,4, 1) + scanner.set_projector(True, 1.0, pattern, None) + time.sleep(1) ### Project an image print('Project Image') @@ -61,14 +61,13 @@ def main(): 255 - 255 * y / height # Red ) source = Projector.Image.Source(format = Video.Format.BGR888, width=width, height=height, step=3*width, fixAspectRatio=True) - scanner.set_projector(on=True, brightness=1.0, pattern=None, image=Projector.Image(source, Rectangle(0,0,width,height)), color=None, buffer=img.tobytes()) + scanner.set_projector(on=True, image=Projector.Image(source, Rectangle(0,0,width,height)), color=None, buffer=img.tobytes()) time.sleep(1) #### Turn OFF scanner.set_projector(on=False) - except Exception as error: print('Error: ', error) except: diff --git a/maf_three/scanner.py b/maf_three/scanner.py index f8788dc..5dd1ee9 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -213,7 +213,12 @@ def __OnMessage(self, ws, message) -> None: inputTask = self.__FindTaskWithIndex(task.Index) if inputTask == None: raise Exception('Task not found') - + + if task.Error: + inputTask.Error = task.Error + self.__OnError(self.websocket, task.Error) + self.__task_return_event.set() + # If assigned => Call the handler if self.OnTask: self.OnTask(task) @@ -297,7 +302,7 @@ def __SendTaskWithBuffer(self, task:Task, buffer:bytes): assert self.__isConnected # Send the task - self.__SendTask(task.Input) + self.__SendTask(task) # Build the buffer descriptor bufferSize = len(buffer) diff --git a/maf_three/serialization.py b/maf_three/serialization.py index 502ccb6..ec322ae 100644 --- a/maf_three/serialization.py +++ b/maf_three/serialization.py @@ -14,11 +14,11 @@ def Serializer(object, visited=None): # logger.debug(f"Serializing object: {object} (id: {id(object)})") - # Detect circular references - if id(object) in visited: - # logger.warning(f"Circular reference detected for object: {object} (id: {id(object)})") - return None - visited.add(id(object)) + # Only track objects for circular references + if isinstance(object, (dict, list, set, tuple, Enum)) or hasattr(object, '__dict__'): + if id(object) in visited: + return None + visited.add(id(object)) # Handle enums if isinstance(object, Enum): From aa84fa75e1582a335c9714514c4dd930b116aec4 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Tue, 1 Oct 2024 12:34:28 -0400 Subject: [PATCH 61/86] Cleanup and faster priocessing without subprocessess --- scripts/build-proto.py | 39 ++++++++++++++------- scripts/transpileProto.py | 74 +++++++++------------------------------ scripts/tree.py | 36 ------------------- 3 files changed, 43 insertions(+), 106 deletions(-) diff --git a/scripts/build-proto.py b/scripts/build-proto.py index 6af5a24..3fa9287 100644 --- a/scripts/build-proto.py +++ b/scripts/build-proto.py @@ -4,16 +4,9 @@ import importlib import ast -# Build proto files -def run_transpile_proto(): - script_path = os.path.join(os.path.dirname(__file__), 'transpileProto.py') - input_dir = './V3Schema' - output_dir = './maf_three/' - result = subprocess.run(['python', script_path, input_dir, output_dir], capture_output=True, text=True) - if result.returncode != 0: - print(f"Error: {result.stderr}") - else: - print(f"Output: {result.stdout}") +import transpileProto +from flake8.api import legacy as flake8 + def get_imports_from_file(file_path): with open(file_path, 'r') as file: @@ -93,6 +86,28 @@ def generate_pyi(scanner_module_name, three_module_name, output_file): with open(output_file, 'w') as f: f.write('\n'.join(pyi_content)) + +def run_flake8(file_path): + style_guide = flake8.get_style_guide(select=['E', 'F'], ignore=['E501']) + report = style_guide.check_files([file_path]) + return report.get_statistics('E') + report.get_statistics('F') + +def check_files(directory): + for root, _, files in os.walk(directory): + for file in files: + if file.endswith('.py') and file != '__init__.py': + filepath = os.path.join(root, file) + # print(f"Running flake8 on {filepath}...") + flake8_output = run_flake8(filepath) + if flake8_output: + print(f"flake8 issues in {filepath}:\n{flake8_output}") + + if __name__ == "__main__": - run_transpile_proto() - generate_pyi('maf_three.scanner', 'maf_three.MF.V3.Three', './maf_three/scanner.pyi') \ No newline at end of file + print("Building python files...") + transpileProto.transpile("./V3Schema/", "./maf_three/") + print("Checking python files...") + check_files("./maf_three/MF/V3/") + print("Generating .pyi file...") + generate_pyi('maf_three.scanner', 'maf_three.MF.V3.Three', './maf_three/scanner.pyi') + print("Completed!") \ No newline at end of file diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 25f17d7..8b55526 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -672,67 +672,25 @@ def generate_init_files(paths: set, tree: Tree, output_dir: str): f.write(f"from {import_path} import * \n") -# Checking files for consistency after building -def check_undefined_names(file_path): - with open(file_path, 'r') as file: - tree = ast.parse(file.read(), filename=file_path) - - undefined_names = set() - defined_names = set() - - class NameVisitor(ast.NodeVisitor): - def visit_Name(self, node): - if isinstance(node.ctx, ast.Load): - if node.id not in defined_names and node.id not in dir(__builtins__): - undefined_names.add(node.id) - elif isinstance(node.ctx, ast.Store): - defined_names.add(node.id) - self.generic_visit(node) - - visitor = NameVisitor() - visitor.visit(tree) - - return undefined_names - -def run_flake8(file_path): - result = subprocess.run( - ['flake8', '--select=E,F', '--ignore=E501', file_path], - capture_output=True, text=True - ) - return result.stdout - -def check_files(directory): - for root, _, files in os.walk(directory): - for file in files: - if file.endswith('.py') and file != '__init__.py': - filepath = os.path.join(root, file) - # print(f"Running flake8 on {filepath}...") - flake8_output = run_flake8(filepath) - if flake8_output: - print(f"flake8 issues in {filepath}:\n{flake8_output}") - -def main(): - - parser = argparse.ArgumentParser(description="Generate Python classes and enums from protobuf schema objects.") - parser.add_argument('input_dir', type=str, nargs='?', default='./V3Schema', help='The input directory containing the protobuf schema objects.') - parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three/', help='The output directory to write the generated Python classes and enums.') - args = parser.parse_args() - # Check to see if args.input_dir and args.output_dir contain a trailing slash - if args.input_dir[-1] == '/': - args.input_dir = args.input_dir[:-1] - if args.output_dir[-1] == '/': - args.output_dir = args.output_dir[:-1] +def transpile(input_dir:str, output_dir:str): + # Check to see if input_dir and output_dir contain a trailing slash + if input_dir[-1] == '/': + input_dir = input_dir[:-1] + if output_dir[-1] == '/': + output_dir = output_dir[:-1] - proto_objects = create_proto_objects(args.input_dir) + proto_objects = create_proto_objects(input_dir) tree= get_tree(proto_objects) - paths = generate_python_code(args.output_dir, tree) - generate_init_files(paths, tree, args.output_dir) + paths = generate_python_code(output_dir, tree) + generate_init_files(paths, tree, output_dir) - check_files(args.output_dir+"/MF/V3/") - - exit(0) + if __name__ == "__main__": - main() - \ No newline at end of file + parser = argparse.ArgumentParser(description="Generate Python classes and enums from protobuf schema objects.") + parser.add_argument('input_dir', type=str, nargs='?', default='./V3Schema', help='The input directory containing the protobuf schema objects.') + parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three/', help='The output directory to write the generated Python classes and enums.') + args = parser.parse_args() + transpile(args.input_dir, args.output_dir) + exit(0) \ No newline at end of file diff --git a/scripts/tree.py b/scripts/tree.py index 1045fd3..51e0313 100644 --- a/scripts/tree.py +++ b/scripts/tree.py @@ -76,16 +76,6 @@ def get_path(self): current_node = current_node.parent return '.'.join(reversed(path)) - def get_relative_path(self, node): - path = [] - current_node = self - while current_node != node: - if current_node.name == "root": - break - path.append(current_node.name) - current_node = current_node.parent - return '.'.join(reversed(path)) - def get_relative_path_from_filespace(self): path = [] current_node = self @@ -97,32 +87,6 @@ def get_relative_path_from_filespace(self): path.append(current_node.name) current_node = current_node.parent return '.'.join(reversed(path)) - - def get_first_parent_with_name(self, name: str): - # Break the name into parts - top_name = name.split('.')[0] - - current_node = self - while current_node: - if current_node.name == "root": - break - if current_node.name == top_name: - return current_node - current_node = current_node.parent - return None - - def climbing_search(self, name: str): - current_node = self - #find the top level node and return it's child - while current_node: - if current_node.name == "root": - break - if current_node.name == name: - return current_node - elif current_node.has_child(name): - return current_node.get_child(name) - current_node = current_node.parent - return None class Tree: def __init__(self): From 0a72111bbec2b8d17d32e948939109d62b1b9f6a Mon Sep 17 00:00:00 2001 From: drewsipher Date: Tue, 1 Oct 2024 12:39:02 -0400 Subject: [PATCH 62/86] Check errors and fail build when using flake --- scripts/build-proto.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/build-proto.py b/scripts/build-proto.py index 3fa9287..ba382eb 100644 --- a/scripts/build-proto.py +++ b/scripts/build-proto.py @@ -93,6 +93,7 @@ def run_flake8(file_path): return report.get_statistics('E') + report.get_statistics('F') def check_files(directory): + hasError = False for root, _, files in os.walk(directory): for file in files: if file.endswith('.py') and file != '__init__.py': @@ -101,7 +102,11 @@ def check_files(directory): flake8_output = run_flake8(filepath) if flake8_output: print(f"flake8 issues in {filepath}:\n{flake8_output}") - + hasError = True + else: + print(f"Clean: {filepath}") + if hasError: + raise Exception("Formatting Or Linting Issues Found") if __name__ == "__main__": print("Building python files...") @@ -110,4 +115,5 @@ def check_files(directory): check_files("./maf_three/MF/V3/") print("Generating .pyi file...") generate_pyi('maf_three.scanner', 'maf_three.MF.V3.Three', './maf_three/scanner.pyi') - print("Completed!") \ No newline at end of file + print("Completed!") + exit(0) \ No newline at end of file From 7945b1fe47ad198d4805a4ff4fc2be8de4881f37 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Tue, 1 Oct 2024 17:00:10 -0400 Subject: [PATCH 63/86] Proper working Scanner example. Added progress to schema. --- V3Schema | 2 +- maf_three/MF/V3/Descriptors/Progress.py | 16 ++++ maf_three/MF/V3/Descriptors/__init__.py | 1 + maf_three/MF/V3/Task.py | 5 +- maf_three/examples/simpleScanner.py | 120 +++++++++++++++--------- maf_three/scanner.py | 8 +- 6 files changed, 98 insertions(+), 54 deletions(-) create mode 100644 maf_three/MF/V3/Descriptors/Progress.py diff --git a/V3Schema b/V3Schema index 8ccc60a..da52790 160000 --- a/V3Schema +++ b/V3Schema @@ -1 +1 @@ -Subproject commit 8ccc60ab1ee9d5f4ea4850bae80c89977c6c892c +Subproject commit da52790aeee335fe2f6b9f602c6144c7929e78d1 diff --git a/maf_three/MF/V3/Descriptors/Progress.py b/maf_three/MF/V3/Descriptors/Progress.py new file mode 100644 index 0000000..e76b025 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Progress.py @@ -0,0 +1,16 @@ +class Progress: + # V3 Task Progress Descriptor + class ScanProgress: + # The Scan Progress descriptor + def __init__(self, current: int, step: str, total: int): + # The current step of the scan. + self.current = current + # The string description of the current step. + self.step = step + # The total steps in the progress. + self.total = total + + def __init__(self, ScanProgress: 'ScanProgress' = None): + self.ScanProgress = ScanProgress + + diff --git a/maf_three/MF/V3/Descriptors/__init__.py b/maf_three/MF/V3/Descriptors/__init__.py index 859bf4d..46b8994 100644 --- a/maf_three/MF/V3/Descriptors/__init__.py +++ b/maf_three/MF/V3/Descriptors/__init__.py @@ -2,6 +2,7 @@ from MF.V3.Descriptors.Export import * from MF.V3.Descriptors.Image import * from MF.V3.Descriptors.Merge import * +from MF.V3.Descriptors.Progress import * from MF.V3.Descriptors.Project import * from MF.V3.Descriptors.ProjectActions import * from MF.V3.Descriptors.RemoveVertices import * diff --git a/maf_three/MF/V3/Task.py b/maf_three/MF/V3/Task.py index 95529af..52494d0 100644 --- a/maf_three/MF/V3/Task.py +++ b/maf_three/MF/V3/Task.py @@ -1,3 +1,4 @@ +from MF.V3.Descriptors.Progress import Progress as MF_V3_Descriptors_Progress_Progress from enum import Enum from google.protobuf import any_pb2 as _any_pb2 @@ -60,7 +61,7 @@ class Task: } ``` """ - def __init__(self, Index: int, Type: str, Input: _any_pb2 = None, Output: _any_pb2 = None, State: 'TaskState' = None, Error: str = None): + def __init__(self, Index: int, Type: str, Input: _any_pb2 = None, Output: _any_pb2 = None, State: 'TaskState' = None, Error: str = None, Progress: MF_V3_Descriptors_Progress_Progress = None): # A unique identifier generated by the client. This identifier associates all incoming and outgoing task messages with a specific task requested by the client. self.Index = Index # The string identifying the task type. See task definitions for the list of valid task strings. @@ -73,5 +74,7 @@ def __init__(self, Index: int, Type: str, Input: _any_pb2 = None, Output: _any_p self.State = State # A string describing the error if the task has failed. self.Error = Error + # A Progress object for tasks that give updates on long running tasks + self.Progress = Progress diff --git a/maf_three/examples/simpleScanner.py b/maf_three/examples/simpleScanner.py index da6671c..26543c4 100644 --- a/maf_three/examples/simpleScanner.py +++ b/maf_three/examples/simpleScanner.py @@ -3,24 +3,19 @@ import numpy as np # Three library -from maf_three.V3Task import V3Task from maf_three.scanner import Scanner -from maf_three.task import Task, TaskState - -from MF.V3.Settings.Camera_pb2 import Camera -from MF.V3.Settings.Capture_pb2 import Capture -from MF.V3.Settings.Projector_pb2 import Projector -from MF.V3.Settings.Turntable_pb2 import Turntable -from MF.V3.Settings.Scan_pb2 import Scan - +from maf_three.MF.V3.Settings import Camera, Projector, Turntable, Scan, Capture +from maf_three.MF.V3.Descriptors import Project +from maf_three.MF.V3.Descriptors.Settings import Scanner as ScannerDescriptor, Camera as CameraDescriptor, Projector as ProjectorDescriptor, Turntable as TurntableDescriptor +from maf_three.MF.V3 import Task, TaskState # Two frames for the video stream frame0 = np.zeros((0,0,3), np.uint8) frame1 = np.zeros((0,0,3), np.uint8) # Camera/Projector settings camera = Camera(exposure=50000, digitalGain=256, analogGain=256.0) -projector = Projector(brightness=0.5) -turntable = Turntable(use=False) +projector = Projector(on=True, brightness=0.5) +turntable = Turntable(8,360,False) def main(): @@ -43,17 +38,21 @@ def main(): # Task update def OnTask(task:Task): - if task.State == TaskState.Completed: + if task.Progress: + print(task.Progress) + else: + print(task.State) + # if task.State == TaskState.Completed: # New Test Scan - if(task.Type == V3Task.NewTestScan): - if task.Output: - print('Scan Completed -> Requesting the data') - index = task.Output[0] - filePath = f'TestScans/Scan-{index}/Scan-{index}.ply' - scanner.SendTask(1, V3Task.DownloadFile, filePath ) + # if(task.Type == V3Task.NewTestScan): + # if task.Output: + # print('Scan Completed -> Requesting the data') + # index = task.Output[0] + # filePath = f'TestScans/Scan-{index}/Scan-{index}.ply' + # scanner.SendTask(1, V3Task.DownloadFile, filePath ) - elif task.State == TaskState.Failed: - print('Failed Task: ', task) + # elif task.State == TaskState.Failed: + # print('Failed Task: ', task) # Buffer received def OnBuffer(descriptor, buffer:bytes): @@ -74,24 +73,23 @@ def OnBuffer(descriptor, buffer:bytes): def OnTrackbarExposure(value): - global camera + # Exposure Min in 9000 + if (value < 9000): + value = 9000 camera.exposure = value - if scanner.IsConnected(): scanner.SendTask(99, V3Task.SetCameras, Camera(exposure=value)) + scanner.set_cameras(exposure=value) def OnTrackbarAnalogGain(value): - global camera camera.analogGain = value - if scanner.IsConnected(): scanner.SendTask(99, V3Task.SetCameras, Camera(analogGain=value)) - + scanner.set_cameras(analogGain=value) + def OnTrackbarDigitalGain(value): - global camera camera.digitalGain = value - if scanner.IsConnected(): scanner.SendTask(99, V3Task.SetCameras, Camera(digitalGain=value)) + scanner.set_cameras(digitalGain=value) def OnTrackbarProjectorBrightness(value): - global projector - projector.brightness = float(value / 100) - if scanner.IsConnected(): scanner.SendTask(112, V3Task.SetProjector, Projector(brightness=value/100)) + projector.brightness = value/100 + scanner.set_projector(brightness=value/100) def OnTrackbarUseTurntable(value): global turntable @@ -105,11 +103,32 @@ def OnTrackbarTurntableSteps(value): global turntable turntable.steps = value + def OnTrackbarFocus(value): + camera.focus = value + scanner.set_cameras(focus=value) + + try: + global camera, projector, turntable + # Connect to the scanner scanner = Scanner(OnTask=OnTask, OnBuffer=OnBuffer, OnMessage=None) scanner.Connect("ws://matterandform.local:8081") + scanSettingsTask = scanner.list_settings() + cameraDescriptor = CameraDescriptor(**scanSettingsTask.Output["camera"]) + projectorDescriptor = ProjectorDescriptor(**scanSettingsTask.Output["projector"]) + turntableDescriptor = TurntableDescriptor(**scanSettingsTask.Output["turntable"]) + + camera.exposure = cameraDescriptor.exposure["value"] + camera.analogGain = cameraDescriptor.analogGain["value"] + camera.digitalGain = cameraDescriptor.digitalGain["value"] + camera.focus = cameraDescriptor.focus["value"]["default"][0] + projector.brightness = projectorDescriptor.brightness["value"] + turntable.use = False + turntable.sweep = turntableDescriptor.sweep["value"] + turntable.scans = turntableDescriptor.scans["value"] + # Create the UI cv2.namedWindow(ControlsWindow) cv2.namedWindow(Camera0Window) @@ -117,17 +136,24 @@ def OnTrackbarTurntableSteps(value): cv2.moveWindow(ControlsWindow,0, 550) cv2.moveWindow(Camera0Window,0,100) cv2.moveWindow(Camera1Window,550,100) - cv2.createTrackbar('Exposure', ControlsWindow , camera.exposure, 100000, OnTrackbarExposure) - cv2.createTrackbar('Analog Gain', ControlsWindow , int(camera.analogGain), 1024, OnTrackbarAnalogGain) - cv2.createTrackbar('Digital Gain', ControlsWindow , camera.digitalGain, 1024, OnTrackbarDigitalGain) - cv2.createTrackbar('Projector Brightness', ControlsWindow , int(100 * projector.brightness), 100, OnTrackbarProjectorBrightness) - cv2.createTrackbar('Use Turntable', ControlsWindow , 1 if turntable.use else 0, 1, OnTrackbarUseTurntable) - cv2.createTrackbar('Turntable Sweep', ControlsWindow , 180, 360, OnTrackbarTurntableSweep) - cv2.createTrackbar('Turntable Steps', ControlsWindow , 0, 32, OnTrackbarTurntableSteps) + cv2.createTrackbar('Exposure', ControlsWindow, int(camera.exposure), int(cameraDescriptor.exposure["max"]), OnTrackbarExposure) + cv2.createTrackbar('Camera Focus', ControlsWindow, int(camera.focus), int(cameraDescriptor.focus["value"]["max"]), OnTrackbarFocus) + cv2.createTrackbar('Analog Gain', ControlsWindow, int(camera.analogGain), int(cameraDescriptor.analogGain["max"]), OnTrackbarAnalogGain) + cv2.createTrackbar('Digital Gain', ControlsWindow, int(camera.digitalGain), int(cameraDescriptor.digitalGain["max"]), OnTrackbarDigitalGain) + cv2.createTrackbar('Projector Brightness', ControlsWindow, int(100 * projector.brightness), 100, OnTrackbarProjectorBrightness) + cv2.createTrackbar('Use Turntable', ControlsWindow, 1 if turntable.use else 0, 1, OnTrackbarUseTurntable) + cv2.createTrackbar('Turntable Sweep', ControlsWindow, int(turntable.sweep), int(turntableDescriptor.sweep["max"]), OnTrackbarTurntableSweep) + cv2.createTrackbar('Turntable Scans', ControlsWindow, int(turntable.scans), int(turntableDescriptor.scans["max"]), OnTrackbarTurntableSteps) + + new_project_return = scanner.new_project('SimpleScanner') + project:Project = Project(**new_project_return.Output) + scanner.open_project(project.index) + # Turn on the projector and start the video - scanner.SendTask(112, V3Task.SetProjector, Projector(color=[1,1,1], on=True, brightness=projector.brightness)) - scanner.SendTask(-1, V3Task.StartVideo) + scanner.set_projector(on=True, brightness=projector.brightness, color=[1,1,1]) + scanner.start_video() + # User input loop print('Press "Esc" to quit.') @@ -147,15 +173,19 @@ def OnTrackbarTurntableSteps(value): break elif key == 115: # 's' => Create a new Test Scan - scan = Scan( - camera=camera, - capture=Capture(), - projector=projector, - turntable=turntable) - scanner.SendTask(115, V3Task.NewTestScan, scan) + if turntable.use: + scanner.new_scan(camera=camera, projector=projector, turntable=turntable) + else: + scanner.new_scan(camera=camera, projector=projector) except Exception as error: print('Error: ', error) + + finally: + if scanner.IsConnected(): + if project: + scanner.remove_projects([project.index]) + scanner.set_projector(on=False) scanner.Disconnect() diff --git a/maf_three/scanner.py b/maf_three/scanner.py index 5dd1ee9..c69f880 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -334,10 +334,4 @@ def __FindTaskWithIndex(self, index:int) -> Task: if t.Index == index: return t break - return None - -if __name__ == "__main__": - scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) - scanner.Connect("ws://matterandform.local:8081") - - scanner.set_projector(on=True, brightness=1.0, color=[1,1,1]) \ No newline at end of file + return None \ No newline at end of file From 72967a2a3b4f85232676d776e81d6942af584bcb Mon Sep 17 00:00:00 2001 From: drewsipher Date: Tue, 19 Nov 2024 11:35:40 -0500 Subject: [PATCH 64/86] Working on scanner. Updated with scale export --- maf_three/MF/V3/Descriptors/__init__.py | 1 - maf_three/MF/V3/Settings/CopyProject.py | 9 +++++++ maf_three/MF/V3/Settings/Export.py | 4 ++- maf_three/MF/V3/Settings/__init__.py | 1 + maf_three/MF/V3/Task.py | 13 ++++++++-- maf_three/MF/V3/Three.py | 8 ++++-- maf_three/examples/simpleScanner.py | 33 +++++++++++-------------- maf_three/scanner.py | 20 ++++++++++++--- maf_three/scanner.pyi | 4 +-- 9 files changed, 63 insertions(+), 30 deletions(-) create mode 100644 maf_three/MF/V3/Settings/CopyProject.py diff --git a/maf_three/MF/V3/Descriptors/__init__.py b/maf_three/MF/V3/Descriptors/__init__.py index 46b8994..859bf4d 100644 --- a/maf_three/MF/V3/Descriptors/__init__.py +++ b/maf_three/MF/V3/Descriptors/__init__.py @@ -2,7 +2,6 @@ from MF.V3.Descriptors.Export import * from MF.V3.Descriptors.Image import * from MF.V3.Descriptors.Merge import * -from MF.V3.Descriptors.Progress import * from MF.V3.Descriptors.Project import * from MF.V3.Descriptors.ProjectActions import * from MF.V3.Descriptors.RemoveVertices import * diff --git a/maf_three/MF/V3/Settings/CopyProject.py b/maf_three/MF/V3/Settings/CopyProject.py new file mode 100644 index 0000000..7000d81 --- /dev/null +++ b/maf_three/MF/V3/Settings/CopyProject.py @@ -0,0 +1,9 @@ +class CopyProject: + # Copy project settings. + def __init__(self, index: int, copyName: str = None): + # The index of the project to copy. + self.index = index + # The name of project copy. If unspecified a default copy name is generated. + self.copyName = copyName + + diff --git a/maf_three/MF/V3/Settings/Export.py b/maf_three/MF/V3/Settings/Export.py index 46ea8ee..22a82ae 100644 --- a/maf_three/MF/V3/Settings/Export.py +++ b/maf_three/MF/V3/Settings/Export.py @@ -14,7 +14,7 @@ class Format(Enum): stl = "stl" # Stereolithography format. xyz = "xyz" # Chemical format. - def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: 'Format' = None): + def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: 'Format' = None, scale: float = None): # The scan selection. self.selection = selection # Export textures. @@ -23,5 +23,7 @@ def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, self.merge = merge # The export format. self.format = format + # Scale factor of the exported geometry. + self.scale = scale diff --git a/maf_three/MF/V3/Settings/__init__.py b/maf_three/MF/V3/Settings/__init__.py index a3259aa..096cbc0 100644 --- a/maf_three/MF/V3/Settings/__init__.py +++ b/maf_three/MF/V3/Settings/__init__.py @@ -4,6 +4,7 @@ from MF.V3.Settings.BoundingBox import * from MF.V3.Settings.Camera import * from MF.V3.Settings.Capture import * +from MF.V3.Settings.CopyProject import * from MF.V3.Settings.Export import * from MF.V3.Settings.Group import * from MF.V3.Settings.I18n import * diff --git a/maf_three/MF/V3/Task.py b/maf_three/MF/V3/Task.py index 52494d0..b2dbb98 100644 --- a/maf_three/MF/V3/Task.py +++ b/maf_three/MF/V3/Task.py @@ -1,4 +1,3 @@ -from MF.V3.Descriptors.Progress import Progress as MF_V3_Descriptors_Progress_Progress from enum import Enum from google.protobuf import any_pb2 as _any_pb2 @@ -61,7 +60,17 @@ class Task: } ``` """ - def __init__(self, Index: int, Type: str, Input: _any_pb2 = None, Output: _any_pb2 = None, State: 'TaskState' = None, Error: str = None, Progress: MF_V3_Descriptors_Progress_Progress = None): + class Progress: + # V3 Task Progress Descriptor + def __init__(self, current: int, step: str, total: int): + # The current step of the scan. + self.current = current + # The string description of the current step. + self.step = step + # The total steps in the progress. + self.total = total + + def __init__(self, Index: int, Type: str, Input: _any_pb2 = None, Output: _any_pb2 = None, State: 'TaskState' = None, Error: str = None, Progress: _any_pb2 = None): # A unique identifier generated by the client. This identifier associates all incoming and outgoing task messages with a specific task requested by the client. self.Index = Index # The string identifying the task type. See task definitions for the list of valid task strings. diff --git a/maf_three/MF/V3/Three.py b/maf_three/MF/V3/Three.py index b9fc123..f0cf259 100644 --- a/maf_three/MF/V3/Three.py +++ b/maf_three/MF/V3/Three.py @@ -725,7 +725,7 @@ def list_export_formats(self) -> Task: return task -def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: +def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None, scale: float = None) -> Task: # Export a group of scans. export_request = MF_V3_Tasks_Export.Request( Index=0, @@ -735,6 +735,7 @@ def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, t texture=texture, merge=merge, format=format, + scale=scale, ) ) export_response = MF_V3_Tasks_Export.Response( @@ -745,6 +746,7 @@ def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, t texture=texture, merge=merge, format=format, + scale=scale, ) ) task = Task(Index=0, Type="Export", Input=export_request, Output=export_response) @@ -752,7 +754,7 @@ def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, t return task -def export_merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None) -> Task: +def export_merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None, scale: float = None) -> Task: # Export a merged scan. export_merge_request = MF_V3_Tasks_ExportMerge.Request( Index=0, @@ -762,6 +764,7 @@ def export_merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = N texture=texture, merge=merge, format=format, + scale=scale, ) ) export_merge_response = MF_V3_Tasks_ExportMerge.Response( @@ -772,6 +775,7 @@ def export_merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = N texture=texture, merge=merge, format=format, + scale=scale, ) ) task = Task(Index=0, Type="ExportMerge", Input=export_merge_request, Output=export_merge_response) diff --git a/maf_three/examples/simpleScanner.py b/maf_three/examples/simpleScanner.py index 26543c4..06b0dae 100644 --- a/maf_three/examples/simpleScanner.py +++ b/maf_three/examples/simpleScanner.py @@ -1,27 +1,33 @@ # Simple Scanner import numpy as np +import json # Three library from maf_three.scanner import Scanner -from maf_three.MF.V3.Settings import Camera, Projector, Turntable, Scan, Capture +from maf_three.MF.V3.Settings import Camera, Projector, Turntable, Scan, ScanSelection, Export from maf_three.MF.V3.Descriptors import Project from maf_three.MF.V3.Descriptors.Settings import Scanner as ScannerDescriptor, Camera as CameraDescriptor, Projector as ProjectorDescriptor, Turntable as TurntableDescriptor + from maf_three.MF.V3 import Task, TaskState # Two frames for the video stream frame0 = np.zeros((0,0,3), np.uint8) frame1 = np.zeros((0,0,3), np.uint8) + # Camera/Projector settings camera = Camera(exposure=50000, digitalGain=256, analogGain=256.0) projector = Projector(on=True, brightness=0.5) turntable = Turntable(8,360,False) +scanTaskIndex = -1 + def main(): # OpenCV try: import cv2 + except ModuleNotFoundError as error: print('###############################################') print('This example required OpenCV for Python') @@ -37,36 +43,25 @@ def main(): # Task update def OnTask(task:Task): - + # print(json.dumps(task, default=lambda o: o.__dict__, indent=4)) if task.Progress: - print(task.Progress) + print(f"{int((task.Progress.current/task.Progress.total)*100)} %") else: print(task.State) - # if task.State == TaskState.Completed: - # New Test Scan - # if(task.Type == V3Task.NewTestScan): - # if task.Output: - # print('Scan Completed -> Requesting the data') - # index = task.Output[0] - # filePath = f'TestScans/Scan-{index}/Scan-{index}.ply' - # scanner.SendTask(1, V3Task.DownloadFile, filePath ) - - # elif task.State == TaskState.Failed: - # print('Failed Task: ', task) # Buffer received def OnBuffer(descriptor, buffer:bytes): global frame0, frame1 # Video task - if descriptor['Task']['Index'] == -1: - if descriptor['Index'] == 0: + if descriptor.Task['Index'] == -1: + if descriptor.Index == 0: frame0 = cv2.imdecode(np.frombuffer(buffer, np.uint8), cv2.IMREAD_COLOR) else: frame1 = cv2.imdecode(np.frombuffer(buffer, np.uint8), cv2.IMREAD_COLOR) # DownloadFile - elif descriptor['Task']['Index'] == 1: + elif descriptor.Task['Index'] == 1: with open('scan.ply', 'wb') as binary_file: binary_file.write(buffer) print('Scan saved into scan.ply') @@ -174,9 +169,11 @@ def OnTrackbarFocus(value): elif key == 115: # 's' => Create a new Test Scan if turntable.use: - scanner.new_scan(camera=camera, projector=projector, turntable=turntable) + scanTask = scanner.new_scan(camera=camera, projector=projector, turntable=turntable) + scanTaskIndex = scanTask.Index else: scanner.new_scan(camera=camera, projector=projector) + scanner.export(selection=ScanSelection(ScanSelection.Mode.all) ,merge=True, texture=True, format=Export.Format.ply) except Exception as error: print('Error: ', error) diff --git a/maf_three/scanner.py b/maf_three/scanner.py index c69f880..036fa75 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -14,7 +14,7 @@ import inspect import types -from MF.V3 import Task, TaskState +from MF.V3 import Task, TaskState, Buffer from maf_three import __version__ from maf_three.serialization import TO_JSON @@ -33,6 +33,7 @@ class Scanner: """ __bufferDescriptor = None + __buffer = None __error = None __taskIndex:int = 0 __tasks:List[Task] = [] @@ -199,8 +200,15 @@ def __OnMessage(self, ws, message) -> None: # Bytes ? if isinstance(message, bytes): if self.OnBuffer: - self.OnBuffer(self.__bufferDescriptor, message) - self.__bufferDescriptor = None + + if self.__buffer: + self.__buffer += message + else: + self.__buffer = message + if self.__bufferDescriptor.Size == len(self.__buffer): + self.OnBuffer(self.__bufferDescriptor, message) + self.__bufferDescriptor = None + self.__buffer = None else: obj = json.loads(message) @@ -208,6 +216,9 @@ def __OnMessage(self, ws, message) -> None: if 'Task' in obj: # Create the task from the message task = Task(**obj['Task']) + if (task.Progress): + progress_data = next(iter(task.Progress.values())) + task.Progress = Task.Progress(**progress_data) # Find the original task for reference inputTask = self.__FindTaskWithIndex(task.Index) @@ -235,7 +246,8 @@ def __OnMessage(self, ws, message) -> None: # Buffer elif 'Buffer' in obj: - self.__bufferDescriptor = obj['Buffer'] + self.__bufferDescriptor = Buffer(**obj['Buffer']) + self.__buffer = None # Message elif 'Message' in obj: if self.OnMessage: diff --git a/maf_three/scanner.pyi b/maf_three/scanner.pyi index c88c209..4af9e37 100644 --- a/maf_three/scanner.pyi +++ b/maf_three/scanner.pyi @@ -117,9 +117,9 @@ class Scanner: def depth_map(self, camera: MF.V3.Settings.Camera.Camera = None, projector: MF.V3.Settings.Projector.Projector = None, turntable: MF.V3.Settings.Turntable.Turntable = None, capture: MF.V3.Settings.Capture.Capture = None, processing: MF.V3.Settings.Scan.Scan.Processing = None) -> MF.V3.Task.Task: ... def detect_calibration_card(self, Input: int) -> MF.V3.Task.Task: ... def download_project(self, Input: int) -> MF.V3.Task.Task: ... - def export(self, selection: MF.V3.Settings.ScanSelection.ScanSelection = None, texture: bool = None, merge: bool = None, format: MF.V3.Settings.Export.Export.Format = None) -> MF.V3.Task.Task: ... + def export(self, selection: MF.V3.Settings.ScanSelection.ScanSelection = None, texture: bool = None, merge: bool = None, format: MF.V3.Settings.Export.Export.Format = None, scale: float = None) -> MF.V3.Task.Task: ... def export_logs(self, Input: bool = None) -> MF.V3.Task.Task: ... - def export_merge(self, selection: MF.V3.Settings.ScanSelection.ScanSelection = None, texture: bool = None, merge: bool = None, format: MF.V3.Settings.Export.Export.Format = None) -> MF.V3.Task.Task: ... + def export_merge(self, selection: MF.V3.Settings.ScanSelection.ScanSelection = None, texture: bool = None, merge: bool = None, format: MF.V3.Settings.Export.Export.Format = None, scale: float = None) -> MF.V3.Task.Task: ... def flatten_group(self, Input: int) -> MF.V3.Task.Task: ... def forget_wifi(self) -> MF.V3.Task.Task: ... def has_cameras(self) -> MF.V3.Task.Task: ... From 768d31ddfc09e885e9f3577a04da9b6363abf52a Mon Sep 17 00:00:00 2001 From: drewsipher Date: Tue, 19 Nov 2024 12:41:51 -0500 Subject: [PATCH 65/86] Casts progresses --- .vscode/launch.json | 9 +++++++++ maf_three/scanner.py | 15 +++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 35298e1..4271258 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,6 +9,15 @@ "console": "integratedTerminal", "cwd": "${workspaceFolder}", "justMyCode": true + }, + { + "name": "Python: Simple Scanner", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/maf_three/examples/simpleScanner.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}", + "justMyCode": true } ] } diff --git a/maf_three/scanner.py b/maf_three/scanner.py index 036fa75..255ab92 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -15,6 +15,7 @@ import types from MF.V3 import Task, TaskState, Buffer +from MF.V3.Descriptors import Progress from maf_three import __version__ from maf_three.serialization import TO_JSON @@ -139,7 +140,7 @@ def IsConnected(self)-> bool: def __callback(self, callback, *args) -> None: if callback: callback(self, *args) - + # Called when the connection is opened def __OnOpen(self, ws) -> None: """ @@ -217,9 +218,15 @@ def __OnMessage(self, ws, message) -> None: # Create the task from the message task = Task(**obj['Task']) if (task.Progress): - progress_data = next(iter(task.Progress.values())) - task.Progress = Task.Progress(**progress_data) - + # Extract the first (and only) item from the task.Progress dictionary + # TODO Duct tape fix due to schema weirdness + key, process = next(iter(task.Progress.items())) + task.Progress = Progress.ScanProgress( + current=process["current"], + step=process["step"], + total=process["total"] + ) + # Find the original task for reference inputTask = self.__FindTaskWithIndex(task.Index) if inputTask == None: From 2a9ff4a347937e8716564ad37ecdfb6ae4089f8d Mon Sep 17 00:00:00 2001 From: drewsipher Date: Tue, 19 Nov 2024 15:50:32 -0500 Subject: [PATCH 66/86] Update to new Schema --- V3Schema | 2 +- maf_three/MF/V3/Descriptors/Progress.py | 16 ------- .../MF/V3/Descriptors/Settings/Scanner.py | 2 +- .../MF/V3/Descriptors/Settings/Software.py | 10 ++--- maf_three/MF/V3/Descriptors/Software.py | 19 +++++++++ maf_three/MF/V3/Descriptors/System.py | 42 +------------------ maf_three/MF/V3/Descriptors/__init__.py | 1 + maf_three/MF/V3/Settings/CopyGroup.py | 25 +++++++++++ maf_three/MF/V3/Settings/Scanner.py | 2 +- maf_three/MF/V3/Settings/Software.py | 23 +++------- maf_three/MF/V3/Settings/Upgrade.py | 9 ---- maf_three/MF/V3/Settings/__init__.py | 2 +- maf_three/MF/V3/Three.py | 7 ++-- maf_three/scanner.py | 5 +-- maf_three/scanner.pyi | 2 +- scripts/transpileProto.py | 2 + 16 files changed, 69 insertions(+), 100 deletions(-) delete mode 100644 maf_three/MF/V3/Descriptors/Progress.py create mode 100644 maf_three/MF/V3/Descriptors/Software.py create mode 100644 maf_three/MF/V3/Settings/CopyGroup.py delete mode 100644 maf_three/MF/V3/Settings/Upgrade.py diff --git a/V3Schema b/V3Schema index da52790..9edef30 160000 --- a/V3Schema +++ b/V3Schema @@ -1 +1 @@ -Subproject commit da52790aeee335fe2f6b9f602c6144c7929e78d1 +Subproject commit 9edef307182fa13a1cac87968a9b342f5ba09194 diff --git a/maf_three/MF/V3/Descriptors/Progress.py b/maf_three/MF/V3/Descriptors/Progress.py deleted file mode 100644 index e76b025..0000000 --- a/maf_three/MF/V3/Descriptors/Progress.py +++ /dev/null @@ -1,16 +0,0 @@ -class Progress: - # V3 Task Progress Descriptor - class ScanProgress: - # The Scan Progress descriptor - def __init__(self, current: int, step: str, total: int): - # The current step of the scan. - self.current = current - # The string description of the current step. - self.step = step - # The total steps in the progress. - self.total = total - - def __init__(self, ScanProgress: 'ScanProgress' = None): - self.ScanProgress = ScanProgress - - diff --git a/maf_three/MF/V3/Descriptors/Settings/Scanner.py b/maf_three/MF/V3/Descriptors/Settings/Scanner.py index faa0f0d..f0d2e6a 100644 --- a/maf_three/MF/V3/Descriptors/Settings/Scanner.py +++ b/maf_three/MF/V3/Descriptors/Settings/Scanner.py @@ -31,7 +31,7 @@ def __init__(self, advanced: MF_V3_Descriptors_Settings_Advanced_Advanced, camer self.tutorials = tutorials # Viewer settings descriptor. self.viewer = viewer - # Style settings descriptor. + # Software settings descriptor. self.software = software diff --git a/maf_three/MF/V3/Descriptors/Settings/Software.py b/maf_three/MF/V3/Descriptors/Settings/Software.py index de56143..2bcc7bb 100644 --- a/maf_three/MF/V3/Descriptors/Settings/Software.py +++ b/maf_three/MF/V3/Descriptors/Settings/Software.py @@ -1,13 +1,13 @@ class Software: # Software settings descriptor. - class NightlyIncluded: - # Nightly releases included descriptor. + class UpdateMajor: + # Enable major version updates which can have breaking API changes. def __init__(self, value: bool, default: bool): self.value = value self.default = default - def __init__(self, nightlyIncluded: 'NightlyIncluded'): - # Nightly releases included. - self.nightlyIncluded = nightlyIncluded + def __init__(self, updateMajor: 'UpdateMajor'): + # Enable major version updates which can have breaking API changes. + self.updateMajor = updateMajor diff --git a/maf_three/MF/V3/Descriptors/Software.py b/maf_three/MF/V3/Descriptors/Software.py new file mode 100644 index 0000000..4042713 --- /dev/null +++ b/maf_three/MF/V3/Descriptors/Software.py @@ -0,0 +1,19 @@ +class Software: + # Software descriptor. + class Package: + # Software package descriptor. + def __init__(self, installed: str, update: str, changelog: str): + # The package installed version. + self.installed = installed + # The package update version. Empty if no update is available. + self.update = update + # The package changelog. Empty if no update is available or the update is a downgrade. + self.changelog = changelog + + def __init__(self, frontend: 'Package', server: 'Package'): + # Frontend software package. + self.frontend = frontend + # Server software package. + self.server = server + + diff --git a/maf_three/MF/V3/Descriptors/System.py b/maf_three/MF/V3/Descriptors/System.py index a1f4780..3c8b3a4 100644 --- a/maf_three/MF/V3/Descriptors/System.py +++ b/maf_three/MF/V3/Descriptors/System.py @@ -1,7 +1,3 @@ -from MF.V3.Settings.Software import Software -from typing import List - - class System: # System descriptor. class DiskSpace: @@ -12,47 +8,11 @@ def __init__(self, capacity: int, available: int): # Available disk space in bytes. self.available = available - class Software: - # Software descriptor. - class Version: - # Software version descriptor. - def __init__(self, major: int, minor: int, patch: int, suffix: str, string: str): - # The major version. - self.major = major - # The minor version. - self.minor = minor - # The patch version. - self.patch = patch - # The alphanumeric suffix. e.g. "rc0" - self.suffix = suffix - # The version string. e.g. "1.2.3-rc0" - self.string = string - - class Package: - # Software package descriptor. - def __init__(self, name: Software.Package, version: 'System.Software.Version', changelog: str): - # The package name. - self.name = name - # The package version. - self.version = version - # The package changelog. - self.changelog = changelog - - def __init__(self, nightlyIncluded: bool, installed: List['Package'] = None, available: List['Package'] = None): - # Nightly releases are included. - self.nightlyIncluded = nightlyIncluded - # Installed software versions. - self.installed = installed - # Available software versions. - self.available = available - - def __init__(self, serialNumber: str, diskSpace: 'DiskSpace', software: 'Software', publicKey: str): + def __init__(self, serialNumber: str, diskSpace: 'DiskSpace', publicKey: str): # Serial number; self.serialNumber = serialNumber # Used and available disk space. self.diskSpace = diskSpace - # Software descriptor. - self.software = software # GPG public key. self.publicKey = publicKey diff --git a/maf_three/MF/V3/Descriptors/__init__.py b/maf_three/MF/V3/Descriptors/__init__.py index 859bf4d..0914107 100644 --- a/maf_three/MF/V3/Descriptors/__init__.py +++ b/maf_three/MF/V3/Descriptors/__init__.py @@ -6,6 +6,7 @@ from MF.V3.Descriptors.ProjectActions import * from MF.V3.Descriptors.RemoveVertices import * from MF.V3.Descriptors.ScanData import * +from MF.V3.Descriptors.Software import * from MF.V3.Descriptors.System import * from MF.V3.Descriptors.Transform import * from MF.V3.Descriptors.VideoFrame import * diff --git a/maf_three/MF/V3/Settings/CopyGroup.py b/maf_three/MF/V3/Settings/CopyGroup.py new file mode 100644 index 0000000..1e172c9 --- /dev/null +++ b/maf_three/MF/V3/Settings/CopyGroup.py @@ -0,0 +1,25 @@ +from typing import List + + +class CopyGroup: + # Copy scan group settings. + def __init__(self, sourceIndexes: List[int] = None, targetIndex: int = None, childPosition: int = None, nameSuffix: str = None): + # The indexes of the groups to copy. + self.sourceIndexes = sourceIndexes + """ + The index of the group into which the source group are copied. + If unspecified the copied groups are added to the root of the group tree. + """ + self.targetIndex = targetIndex + """ + The position among the target group's children where the copied groups are inserted. + If unspecified the copied groups are appended to the end of the target group's children. + """ + self.childPosition = childPosition + """ + Optional name suffix to append to the copied group names. + If unspecified the names are unchanged. + """ + self.nameSuffix = nameSuffix + + diff --git a/maf_three/MF/V3/Settings/Scanner.py b/maf_three/MF/V3/Settings/Scanner.py index b6d4a73..402d3fe 100644 --- a/maf_three/MF/V3/Settings/Scanner.py +++ b/maf_three/MF/V3/Settings/Scanner.py @@ -31,7 +31,7 @@ def __init__(self, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF self.tutorials = tutorials # Viewer settings. self.viewer = viewer - # Software settings. + # Software update settings. self.software = software diff --git a/maf_three/MF/V3/Settings/Software.py b/maf_three/MF/V3/Settings/Software.py index b014fd1..1ebb23c 100644 --- a/maf_three/MF/V3/Settings/Software.py +++ b/maf_three/MF/V3/Settings/Software.py @@ -1,20 +1,9 @@ -from enum import Enum -from typing import List - - class Software: - # V3 software settings. - # Software package types. - class Package(Enum): - server = "server" # The server software package. - frontend = "frontend" # The frontend software package. - - def __init__(self, installed: List['Package'] = None, available: List['Package'] = None, nightlyIncluded: bool = None): - # Request installed software packages. If undefined all installed packages are returned. - self.installed = installed - # Request available software packages. If undefined all available packages are returned. - self.available = available - # Permit nightly release upgrades. - self.nightlyIncluded = nightlyIncluded + # Software settings. + def __init__(self, updateMajor: bool = None, updateNightly: bool = None): + # Enable major version updates which can have breaking API changes. + self.updateMajor = updateMajor + # Enable nightly release candidate updates. + self.updateNightly = updateNightly diff --git a/maf_three/MF/V3/Settings/Upgrade.py b/maf_three/MF/V3/Settings/Upgrade.py deleted file mode 100644 index 3015efa..0000000 --- a/maf_three/MF/V3/Settings/Upgrade.py +++ /dev/null @@ -1,9 +0,0 @@ -class Upgrade: - # Upgrade settings. - def __init__(self, majorVersion: bool = None, stable: bool = None): - # Upgrade major version which can have breaking API changes. - self.majorVersion = majorVersion - # Install the latest stable version. - self.stable = stable - - diff --git a/maf_three/MF/V3/Settings/__init__.py b/maf_three/MF/V3/Settings/__init__.py index 096cbc0..9fadccd 100644 --- a/maf_three/MF/V3/Settings/__init__.py +++ b/maf_three/MF/V3/Settings/__init__.py @@ -4,6 +4,7 @@ from MF.V3.Settings.BoundingBox import * from MF.V3.Settings.Camera import * from MF.V3.Settings.Capture import * +from MF.V3.Settings.CopyGroup import * from MF.V3.Settings.CopyProject import * from MF.V3.Settings.Export import * from MF.V3.Settings.Group import * @@ -24,7 +25,6 @@ from MF.V3.Settings.Style import * from MF.V3.Settings.Turntable import * from MF.V3.Settings.Tutorials import * -from MF.V3.Settings.Upgrade import * from MF.V3.Settings.Video import * from MF.V3.Settings.Viewer import * from MF.V3.Settings.Wifi import * diff --git a/maf_three/MF/V3/Three.py b/maf_three/MF/V3/Three.py index f0cf259..150a228 100644 --- a/maf_three/MF/V3/Three.py +++ b/maf_three/MF/V3/Three.py @@ -844,15 +844,14 @@ def has_turntable(self) -> Task: return task -def system_info(self, installed: List[MF_V3_Settings_Software_Software.Package] = None, available: List[MF_V3_Settings_Software_Software.Package] = None, nightlyIncluded: bool = None) -> Task: +def system_info(self, updateMajor: bool = None, updateNightly: bool = None) -> Task: # Get system information. system_info_request = MF_V3_Tasks_SystemInfo.Request( Index=0, Type="SystemInfo", Input=MF_V3_Settings_Software_Software( - installed=installed, - available=available, - nightlyIncluded=nightlyIncluded, + updateMajor=updateMajor, + updateNightly=updateNightly, ) ) system_info_response = MF_V3_Tasks_SystemInfo.Response( diff --git a/maf_three/scanner.py b/maf_three/scanner.py index 255ab92..016cc52 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -15,7 +15,6 @@ import types from MF.V3 import Task, TaskState, Buffer -from MF.V3.Descriptors import Progress from maf_three import __version__ from maf_three.serialization import TO_JSON @@ -221,12 +220,12 @@ def __OnMessage(self, ws, message) -> None: # Extract the first (and only) item from the task.Progress dictionary # TODO Duct tape fix due to schema weirdness key, process = next(iter(task.Progress.items())) - task.Progress = Progress.ScanProgress( + task.Progress = Task.Progress( current=process["current"], step=process["step"], total=process["total"] ) - + # Find the original task for reference inputTask = self.__FindTaskWithIndex(task.Index) if inputTask == None: diff --git a/maf_three/scanner.pyi b/maf_three/scanner.pyi index 4af9e37..68f442e 100644 --- a/maf_three/scanner.pyi +++ b/maf_three/scanner.pyi @@ -155,7 +155,7 @@ class Scanner: def split_group(self, Input: int) -> MF.V3.Task.Task: ... def start_video(self) -> MF.V3.Task.Task: ... def stop_video(self) -> MF.V3.Task.Task: ... - def system_info(self, installed: List[MF.V3.Settings.Software.Software.Package] = None, available: List[MF.V3.Settings.Software.Software.Package] = None, nightlyIncluded: bool = None) -> MF.V3.Task.Task: ... + def system_info(self, updateMajor: bool = None, updateNightly: bool = None) -> MF.V3.Task.Task: ... def transform_group(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> MF.V3.Task.Task: ... def turntable_calibration(self) -> MF.V3.Task.Task: ... def update_settings(self, advanced: MF.V3.Settings.Advanced.Advanced = None, camera: MF.V3.Settings.Camera.Camera = None, capture: MF.V3.Settings.Capture.Capture = None, i18n: MF.V3.Settings.I18n.I18n = None, projector: MF.V3.Settings.Projector.Projector = None, style: MF.V3.Settings.Style.Style = None, turntable: MF.V3.Settings.Turntable.Turntable = None, tutorials: MF.V3.Settings.Tutorials.Tutorials = None, viewer: MF.V3.Settings.Viewer.Viewer = None, software: MF.V3.Settings.Software.Software = None) -> MF.V3.Task.Task: ... diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 8b55526..980a36a 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -449,6 +449,8 @@ def generate_class_code(current_node:TreeNode) -> str: for prop in properties: # Add comments with spaces if prop.comment: + # TODO Check for types that are not python types and add a isinstance call to cast to that type. This will help unwrapping + class_code += f"{add_indents(prop.comment,2)}" class_code += add_indents(f"self.{prop.name} = {prop.name}\n",2) else: From f2e5d66032f84dd1bcadad5a5b292f69e8706d68 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Tue, 19 Nov 2024 15:53:36 -0500 Subject: [PATCH 67/86] update readme and remove old files when compiling new files --- README.md | 5 +++++ scripts/build-proto.py | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/README.md b/README.md index 71b4404..97006f9 100644 --- a/README.md +++ b/README.md @@ -44,3 +44,8 @@ python3 ./scripts/build-doc.py +## Updating to new Schema +Update the schema subrepo, then run this to compile new files +``` +python3 ./scripts/build-proto.py +``` diff --git a/scripts/build-proto.py b/scripts/build-proto.py index ba382eb..9748273 100644 --- a/scripts/build-proto.py +++ b/scripts/build-proto.py @@ -6,6 +6,7 @@ import transpileProto from flake8.api import legacy as flake8 +import shutil def get_imports_from_file(file_path): @@ -109,6 +110,10 @@ def check_files(directory): raise Exception("Formatting Or Linting Issues Found") if __name__ == "__main__": + # Remove the folder maf_three/MF if it exists + mf_folder = "./maf_three/MF" + if os.path.exists(mf_folder): + shutil.rmtree(mf_folder) print("Building python files...") transpileProto.transpile("./V3Schema/", "./maf_three/") print("Checking python files...") From 8b3c8744668b43640f06a20396c55759d792673f Mon Sep 17 00:00:00 2001 From: drewsipher Date: Tue, 19 Nov 2024 16:48:18 -0500 Subject: [PATCH 68/86] Exporting working --- maf_three/examples/simpleScanner.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/maf_three/examples/simpleScanner.py b/maf_three/examples/simpleScanner.py index 06b0dae..4e37da4 100644 --- a/maf_three/examples/simpleScanner.py +++ b/maf_three/examples/simpleScanner.py @@ -2,6 +2,7 @@ import numpy as np import json +from typing import List # Three library from maf_three.scanner import Scanner @@ -54,17 +55,17 @@ def OnBuffer(descriptor, buffer:bytes): global frame0, frame1 # Video task - if descriptor.Task['Index'] == -1: + if descriptor.Task['Type'] == 'Video': if descriptor.Index == 0: frame0 = cv2.imdecode(np.frombuffer(buffer, np.uint8), cv2.IMREAD_COLOR) else: frame1 = cv2.imdecode(np.frombuffer(buffer, np.uint8), cv2.IMREAD_COLOR) # DownloadFile - elif descriptor.Task['Index'] == 1: - with open('scan.ply', 'wb') as binary_file: + elif descriptor.Task['Type'] == "Export": + with open('scan.zip', 'wb') as binary_file: binary_file.write(buffer) - print('Scan saved into scan.ply') + print('Scan saved into scan.zip') def OnTrackbarExposure(value): @@ -174,6 +175,16 @@ def OnTrackbarFocus(value): else: scanner.new_scan(camera=camera, projector=projector) scanner.export(selection=ScanSelection(ScanSelection.Mode.all) ,merge=True, texture=True, format=Export.Format.ply) + elif key == 101: # e for export project + scanner.open_project(3) + scanner.export(selection=ScanSelection(ScanSelection.Mode.all) ,merge=True, texture=True, format=Export.Format.ply) + elif key == 108: # 'l' => List all scans in the current project + list_project_return = scanner.list_projects() + project_list: List[Project.Brief] = [] + for proj in list_project_return.Output: + project_list.append(Project.Brief(**proj)) + for proj in project_list: + print(f"Project Index: {proj.index}, Project Name: {proj.name}") except Exception as error: print('Error: ', error) From d937d0b22d28daf051959c686042553f39502214 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 20 Nov 2024 16:07:01 -0500 Subject: [PATCH 69/86] Fix to completion without outputs. Add Texturing to example --- maf_three/examples/simpleScanner.py | 45 ++++++++++++++++++++++++----- maf_three/scanner.py | 7 +++-- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/maf_three/examples/simpleScanner.py b/maf_three/examples/simpleScanner.py index 4e37da4..9656d09 100644 --- a/maf_three/examples/simpleScanner.py +++ b/maf_three/examples/simpleScanner.py @@ -6,9 +6,9 @@ # Three library from maf_three.scanner import Scanner -from maf_three.MF.V3.Settings import Camera, Projector, Turntable, Scan, ScanSelection, Export +from maf_three.MF.V3.Settings import Capture, Camera, Projector, Turntable, ScanSelection, Export, Quality from maf_three.MF.V3.Descriptors import Project -from maf_three.MF.V3.Descriptors.Settings import Scanner as ScannerDescriptor, Camera as CameraDescriptor, Projector as ProjectorDescriptor, Turntable as TurntableDescriptor +from maf_three.MF.V3.Descriptors.Settings import Scanner as ScannerDescriptor, Camera as CameraDescriptor, Projector as ProjectorDescriptor, Turntable as TurntableDescriptor, Capture as CaptureDescriptor from maf_three.MF.V3 import Task, TaskState # Two frames for the video stream @@ -20,6 +20,7 @@ camera = Camera(exposure=50000, digitalGain=256, analogGain=256.0) projector = Projector(on=True, brightness=0.5) turntable = Turntable(8,360,False) +capture = Capture(Quality.Low,False) scanTaskIndex = -1 @@ -48,7 +49,7 @@ def OnTask(task:Task): if task.Progress: print(f"{int((task.Progress.current/task.Progress.total)*100)} %") else: - print(task.State) + print(task.Type,task.Index,task.State) # Buffer received def OnBuffer(descriptor, buffer:bytes): @@ -97,12 +98,35 @@ def OnTrackbarTurntableSweep(value): def OnTrackbarTurntableSteps(value): global turntable - turntable.steps = value + turntable.scans = value def OnTrackbarFocus(value): camera.focus = value scanner.set_cameras(focus=value) + def OnTrackbarQuality(value): + global capture + capture.quality = getQualityFromInt(value) + + def OnTrackbarTexture(value): + global capture + capture.texture = value == 1 + + def getIntFromQuality(quality:Quality) -> int: + if quality == Quality.Low.value: + return 0 + elif quality == Quality.Medium.value: + return 1 + elif quality == Quality.High.value: + return 2 + + def getQualityFromInt(quality:int) -> Quality: + if quality == 0: + return Quality.Low + elif quality == 1: + return Quality.Medium + elif quality == 2: + return Quality.High try: global camera, projector, turntable @@ -111,10 +135,12 @@ def OnTrackbarFocus(value): scanner = Scanner(OnTask=OnTask, OnBuffer=OnBuffer, OnMessage=None) scanner.Connect("ws://matterandform.local:8081") + # Get the settings stored on the scanner and apply them to the UI scanSettingsTask = scanner.list_settings() cameraDescriptor = CameraDescriptor(**scanSettingsTask.Output["camera"]) projectorDescriptor = ProjectorDescriptor(**scanSettingsTask.Output["projector"]) turntableDescriptor = TurntableDescriptor(**scanSettingsTask.Output["turntable"]) + captureDescriptor = CaptureDescriptor(**scanSettingsTask.Output["capture"]) camera.exposure = cameraDescriptor.exposure["value"] camera.analogGain = cameraDescriptor.analogGain["value"] @@ -124,6 +150,8 @@ def OnTrackbarFocus(value): turntable.use = False turntable.sweep = turntableDescriptor.sweep["value"] turntable.scans = turntableDescriptor.scans["value"] + capture.quality = captureDescriptor.quality["value"] + capture.texture = captureDescriptor.texture["value"] # Create the UI cv2.namedWindow(ControlsWindow) @@ -140,7 +168,8 @@ def OnTrackbarFocus(value): cv2.createTrackbar('Use Turntable', ControlsWindow, 1 if turntable.use else 0, 1, OnTrackbarUseTurntable) cv2.createTrackbar('Turntable Sweep', ControlsWindow, int(turntable.sweep), int(turntableDescriptor.sweep["max"]), OnTrackbarTurntableSweep) cv2.createTrackbar('Turntable Scans', ControlsWindow, int(turntable.scans), int(turntableDescriptor.scans["max"]), OnTrackbarTurntableSteps) - + cv2.createTrackbar('Capture Quality', ControlsWindow, getIntFromQuality(capture.quality), 2, OnTrackbarQuality) + cv2.createTrackbar('Capture Texture', ControlsWindow, 1 if capture.texture else 0, 1, OnTrackbarTexture) new_project_return = scanner.new_project('SimpleScanner') project:Project = Project(**new_project_return.Output) @@ -160,7 +189,6 @@ def OnTrackbarFocus(value): cv2.imshow(Camera0Window,frame0) if frame1.size > 0: cv2.imshow(Camera1Window,frame1) - # User input key = cv2.waitKey(1) if(key != -1): @@ -170,10 +198,11 @@ def OnTrackbarFocus(value): elif key == 115: # 's' => Create a new Test Scan if turntable.use: - scanTask = scanner.new_scan(camera=camera, projector=projector, turntable=turntable) + scanTask = scanner.new_scan(camera=camera, projector=projector, turntable=turntable, capture=capture) scanTaskIndex = scanTask.Index + scanner.export(selection=ScanSelection(ScanSelection.Mode.all) ,merge=True, texture=True, format=Export.Format.ply) else: - scanner.new_scan(camera=camera, projector=projector) + scanner.new_scan(camera=camera, projector=projector, capture=capture) scanner.export(selection=ScanSelection(ScanSelection.Mode.all) ,merge=True, texture=True, format=Export.Format.ply) elif key == 101: # e for export project scanner.open_project(3) diff --git a/maf_three/scanner.py b/maf_three/scanner.py index 016cc52..8fa7134 100644 --- a/maf_three/scanner.py +++ b/maf_three/scanner.py @@ -216,9 +216,10 @@ def __OnMessage(self, ws, message) -> None: if 'Task' in obj: # Create the task from the message task = Task(**obj['Task']) + if (task.Progress): # Extract the first (and only) item from the task.Progress dictionary - # TODO Duct tape fix due to schema weirdness + # TODO Duct tape fix due to schema weirdness for progress key, process = next(iter(task.Progress.items())) task.Progress = Task.Progress( current=process["current"], @@ -245,7 +246,7 @@ def __OnMessage(self, ws, message) -> None: if (task.State == TaskState.Completed.value): if task.Output: inputTask.Output = task.Output - self.__task_return_event.set() + self.__task_return_event.set() elif (task.State == TaskState.Failed.value): inputTask.Error = task.Error self.__task_return_event @@ -312,7 +313,7 @@ def __SendTask(self, task): # Build and send the message message = '{"Task":' + message + '}' print('Message: ', message) - #print('Message: ', message) + self.websocket.send(message) # Send a task with its buffer to the scanner From 1e30df109772b7895bc38c67486e94d1463291d4 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 20 Nov 2024 16:10:23 -0500 Subject: [PATCH 70/86] Cleanup on example --- maf_three/examples/simpleScanner.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/maf_three/examples/simpleScanner.py b/maf_three/examples/simpleScanner.py index 9656d09..c114457 100644 --- a/maf_three/examples/simpleScanner.py +++ b/maf_three/examples/simpleScanner.py @@ -197,16 +197,9 @@ def getQualityFromInt(quality:int) -> Quality: break elif key == 115: # 's' => Create a new Test Scan - if turntable.use: - scanTask = scanner.new_scan(camera=camera, projector=projector, turntable=turntable, capture=capture) - scanTaskIndex = scanTask.Index - scanner.export(selection=ScanSelection(ScanSelection.Mode.all) ,merge=True, texture=True, format=Export.Format.ply) - else: - scanner.new_scan(camera=camera, projector=projector, capture=capture) - scanner.export(selection=ScanSelection(ScanSelection.Mode.all) ,merge=True, texture=True, format=Export.Format.ply) - elif key == 101: # e for export project - scanner.open_project(3) - scanner.export(selection=ScanSelection(ScanSelection.Mode.all) ,merge=True, texture=True, format=Export.Format.ply) + scanner.new_scan(camera=camera, projector=projector, turntable=turntable if turntable.use else None, capture=capture) + scanner.export(selection=ScanSelection(ScanSelection.Mode.all) ,merge=True, texture=True, format=Export.Format.ply) + elif key == 108: # 'l' => List all scans in the current project list_project_return = scanner.list_projects() project_list: List[Project.Brief] = [] From 09d2758ebe1afb800172b84e126fc92424401f68 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 20 Nov 2024 16:14:45 -0500 Subject: [PATCH 71/86] Fixed Task example --- .vscode/launch.json | 11 ++++++++++- maf_three/examples/task.py | 34 ++++++++++------------------------ 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 4271258..a4da933 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,7 @@ "justMyCode": true }, { - "name": "Python: Simple Scanner", + "name": "Python: Simple Scanner Example", "type": "debugpy", "request": "launch", "program": "${workspaceFolder}/maf_three/examples/simpleScanner.py", @@ -19,5 +19,14 @@ "cwd": "${workspaceFolder}", "justMyCode": true } + { + "name": "Python: Task Example", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/maf_three/examples/task.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}", + "justMyCode": true + } ] } diff --git a/maf_three/examples/task.py b/maf_three/examples/task.py index c98aa76..0385d7c 100644 --- a/maf_three/examples/task.py +++ b/maf_three/examples/task.py @@ -1,14 +1,12 @@ -# Task -import time +import numpy as np +import json +from typing import List +# Three library from maf_three.scanner import Scanner -from maf_three.task import Task, TaskState -from maf_three.V3Task import V3Task - -from MF.V3.Settings.Camera import Camera -from MF.V3.Settings.Capture import Capture -from MF.V3.Settings.Projector import Projector -from MF.V3.Settings.Scan import Scan +from maf_three.MF.V3.Settings import Capture, Camera, Projector +from maf_three.MF.V3.Descriptors import Project +from maf_three.MF.V3 import Task, TaskState done = False @@ -16,9 +14,8 @@ def main(): global done + # Task update def OnTask(task:Task): - global done - # Inspect Task State match task.State: @@ -50,20 +47,9 @@ def OnTask(task:Task): scanner.Connect("ws://matterandform.local:8081") # Try to scan without input => Will trigger an error - scanner.SendTask(0, V3Task.NewTestScan) - - # Scan - scan = Scan( - camera=Camera(analogGain=256,digitalGain=256,exposure=50000), - capture=Capture(), - projector=Projector(brightness=0.5) - ) - scanner.SendTask(1, V3Task.NewTestScan, scan) - - # Wait for the tasks to finish - while not done: - time.sleep(0.1) + scanner.new_scan() + scanner.list_settings() except Exception as error: print('Error: ', error) From 3945411f4d9d439ca8420b53966bfee785a14bdb Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 20 Nov 2024 16:55:32 -0500 Subject: [PATCH 72/86] Turntable Calibration Example --- .vscode/launch.json | 9 +++ maf_three/examples/turntable.py | 70 ------------------- maf_three/examples/turntableCalibration.py | 80 +++++++++++----------- 3 files changed, 48 insertions(+), 111 deletions(-) delete mode 100644 maf_three/examples/turntable.py diff --git a/.vscode/launch.json b/.vscode/launch.json index a4da933..17411f5 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -27,6 +27,15 @@ "console": "integratedTerminal", "cwd": "${workspaceFolder}", "justMyCode": true + }, + { + "name": "Python: Calibrate Turntable Example", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/maf_three/examples/turntableCalibration.py", + "console": "integratedTerminal", + "cwd": "${workspaceFolder}", + "justMyCode": true } ] } diff --git a/maf_three/examples/turntable.py b/maf_three/examples/turntable.py deleted file mode 100644 index 2f03fc6..0000000 --- a/maf_three/examples/turntable.py +++ /dev/null @@ -1,70 +0,0 @@ -# Turntable - -from maf_three.scanner import Scanner -from maf_three.task import Task, TaskState -from maf_three.V3Task import V3Task - -import time - -hasTurntable = None -rotating = False - -def main(): - global hasTurntable, rotating - - def OnTask(task:Task): - global hasTurntable, rotating - - # HasTurntable - if task.Type == V3Task.HasTurntable and task.State == TaskState.Completed: - print('Completed : ', task.Output) - hasTurntable = task.Output - - # RotateTurntable - elif task.Type == V3Task.RotateTurntable: - if task.State == TaskState.Started: - rotating = True - elif task.State == TaskState.Completed: - rotating = False - - try: - scanner = Scanner(OnTask=OnTask, OnMessage=None, OnBuffer=None) - scanner.Connect("ws://matterandform.local:8081") - - # Check if a Turntable is connected to the scanner - scanner.SendTask(0, V3Task.HasTurntable) - while hasTurntable == None: - #print(hasTurntable) - pass - if hasTurntable == False: - raise Exception('There is no turntable connected to the scanner') - - while True: - - while rotating: - time.sleep(0.1) - - userInput = input('Enter an angle or "q" to quit\n') - - if userInput.lower() == 'q': - break - - try: - angle = float(userInput) - rotating = True - scanner.SendTask(0, V3Task.RotateTurntable, angle) - except: - pass - - - except Exception as error: - print('Error: ', error) - except: - print('Error') - - finally: - if scanner.IsConnected(): - scanner.Disconnect() - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/maf_three/examples/turntableCalibration.py b/maf_three/examples/turntableCalibration.py index d89fd38..399009a 100644 --- a/maf_three/examples/turntableCalibration.py +++ b/maf_three/examples/turntableCalibration.py @@ -1,10 +1,13 @@ -# Turntable calibration - +from typing import List import time +# Three library from maf_three.scanner import Scanner -from maf_three.task import Task, TaskState -from maf_three.V3Task import V3Task +from maf_three.MF.V3.Settings import Capture, Camera, Projector, Turntable, ScanSelection, Export, Quality +from maf_three.MF.V3.Descriptors import Calibration +from maf_three.MF.V3.Descriptors.Settings import Scanner as ScannerDescriptor, Camera as CameraDescriptor, Projector as ProjectorDescriptor, Turntable as TurntableDescriptor, Capture as CaptureDescriptor + +from maf_three.MF.V3 import Task, TaskState done = False @@ -16,44 +19,43 @@ def main(): def OnTask(task:Task): global done - - # Calibrate turntable task - if task.Type == V3Task.CalibrateTurntable: - # Task progress - if task.Progress != None: - progress = task.Progress['CalibrateTurntable'] - print(progress['current'] , '/', progress['total'], '-', progress['step']) - - # Task completed ? - if task.State == TaskState.Completed: - print('Calibration Completed') - print(task.Output) + # print(json.dumps(task, default=lambda o: o.__dict__, indent=4)) + if task.Progress: + print(f"{int((task.Progress.current/task.Progress.total)*100)} %") + else: + print(task.Type,task.Index,task.State) + if task.Type == "CalibrateTurntable": + if task.State == "Completed": + print('Calibration Completed') + elif task.State == "Failed": + print('Calibration Failed:', task.Error) done = True - # Task failed ? - elif task.State == TaskState.Failed: - print('Calibration Failed') - print('Calibration error:', task.Error) + elif task.Type == "DetectCalibrationCard": + if task.State == "Completed": + print('Calibration Card Detected') + elif task.State == "Failed": + print('Calibration Card Detection Failed:', task.Error) done = True - def OnBuffer(descriptor, buffer:bytes): + def OnBuffer(bufferObject, buffer:bytes): global cornersDetected_0, cornersDetected_1, cornersTotal # Video task ? - if descriptor['Task']['Index'] == -1: + if bufferObject.Task['Type'] == "Video": + # Calibration card present in the descriptor - if "calibrationCard" in descriptor['Descriptor']: - calibrationCard = descriptor['Descriptor']['calibrationCard'] - + if "calibrationCard" in bufferObject.Descriptor: + calibrationCard = Calibration.DetectedCard(**bufferObject.Descriptor['calibrationCard']) + # Total amount of corners if cornersTotal == 0: - cardWidth = calibrationCard['size'][0] - cardHeight = calibrationCard['size'][1] + cardWidth = calibrationCard.size[0] + cardHeight = calibrationCard.size[1] cornersTotal = (cardWidth - 1) * (cardHeight - 1) - - detectedCorners = len(calibrationCard['corners']) + detectedCorners = int(len(calibrationCard.corners) / 2) # Camera 0 - if descriptor['Index'] == 0: + if bufferObject.Index == 0: cornersDetected_0 = detectedCorners # Camera 1 else: @@ -61,12 +63,11 @@ def OnBuffer(descriptor, buffer:bytes): # No calibration card in the descriptor else: - if descriptor['Index'] == 0: + if bufferObject.Index == 0: cornersDetected_0 = 0 else: cornersDetected_1 = 0 - - print(f'Camera 0: {cornersDetected_0}/{cornersTotal} ; Camera 1: {cornersDetected_1}/{cornersTotal} ', end="\r", flush=True) + print(f'Camera 0: {cornersDetected_0}/{cornersTotal} ; Camera 1: {cornersDetected_1}/{cornersTotal}') try: # Connect @@ -74,11 +75,11 @@ def OnBuffer(descriptor, buffer:bytes): scanner.Connect("ws://matterandform.local:8081") # Start the video - scanner.SendTask(-1, V3Task.StartVideo) + scanner.start_video() # Detect the calibration card print('******* Detecting the calibration card') - scanner.SendTask(0, V3Task.DetectCalibrationCard, 3) + scanner.detect_calibration_card(3) # left camera only, 2 = Right camera only, 3 = Both cameras # Wait for the calibration card to be detected while cornersTotal == 0: @@ -88,16 +89,13 @@ def OnBuffer(descriptor, buffer:bytes): time.sleep(5) # Stop the video - scanner.SendTask(-1, V3Task.StopVideo) - time.sleep(1) + scanner.detect_calibration_card(0) # Stop the detection + scanner.stop_video() # Calibration the turntable print('\n******* Calibrating the turntable') - scanner.SendTask(1, V3Task.CalibrateTurntable) + scanner.calibrate_turntable() - # Wait for the tasks to finish - while not done: - time.sleep(0.1) except Exception as error: From 8057d5aba608cdf21e733e75e24dd75eec2b1f65 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 20 Nov 2024 17:06:47 -0500 Subject: [PATCH 73/86] Draft of Readme and License --- LICENSE | 21 ++++++++ README.md | 121 +++++++++++++++++++++++++++++++++++++---------- requirements.txt | 62 ++++++++++++++++++++++-- 3 files changed, 175 insertions(+), 29 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0cd4f3a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Matter and Form + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 97006f9..43a3508 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,122 @@ +# Matter and Form THREE Library -# Setup +## Overview +The Matter and Form THREE library provides a comprehensive API for controlling and interacting with the Matter and Form THREE scanner. This library allows developers to build custom integrations, automate tasks, and create new front-end systems for 3D scanning. -## Install required packages +## Setup -``` -sudo apt install python3 python3-pip python3.12-venv -``` +### Install Required Packages +Ensure you have Python 3.10 or newer installed. You can download it from [python.org](https://www.python.org). -## Start and activate a virtual Python environment with the build dependencies +### Initialize Git Submodules +If you haven't already initialized the git submodules, run the following command: +```sh +git submodule update --init --recursive ``` -python3 -m venv .venv -source .venv/bin/activate -pip3 install -r requirements.txt + +### Start and Activate a Virtual Python Environment +Create and activate a virtual environment: + +```sh +python -m venv .venv +source .venv/bin/activate # On Windows use `venv\Scripts\activate` ``` -# Build +### Install Requirements +Install the required packages listed in the `requirements.txt` file: -## Build python source from proto files +```sh +pip install -r requirements.txt ``` -python3 ./scripts/build-proto.py + +### Build + +#### Build Python Source from Proto Files +This is only necessary if you have an update the schema. Keep in mind that schema's are tied to THREE server releases. Generated files are commited to this repo.To generate the Python source files again from the Schema files, run: + +```sh +python3 ./scipts/build-proto.py ``` -## Package Build +#### Package Build +To build the package, run: + +```sh +python setup.py sdist bdist_wheel ``` -python3 -m build + +#### Install the Package Locally in Editable Mode +To install the package locally in editable mode, run: + +```sh +pip install -e . ``` -## Install the package locally in editable mode +#### Run the Tests +At the moment there are no unit tests + +#### Build the Documentation +To build the documentation, run: + +```sh +TODO ``` -pip3 install --editable . + +## How to Use the Library + +### Installation from PyPI +To install the library from PyPI, run: + +```sh +pip install matter-and-form-three ``` -## Run the tests +### Connect to the Scanner +To connect to the scanner, you can use the provided examples. For instance, to run the connection example, execute: + +```sh +python examples/connect.py ``` -python3 -m pytest + +### Example Usage +Here is an example of how to use the library to connect to the scanner and control the projector: + +```python +from matter_and_form_three import Scanner + +scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) +scanner.Connect("ws://matterandform.local:8081") + +# Do some tasks +scanner.list_settings() ``` -## Build the documentation +### Available Examples +The library comes with several pre-made examples. To list the available examples, run: + +```sh +ls examples/ ``` -python3 ./scripts/build-doc.py + +To run a specific example, use: + +```sh +python examples/.py ``` +## Documentation +For detailed documentation, visit the TODO -> [official documentation](TODO). +## Contributing +We welcome contributions! Please follow the standard GitHub workflow: -## Updating to new Schema -Update the schema subrepo, then run this to compile new files -``` -python3 ./scripts/build-proto.py -``` +1. Fork the repository. +2. Create a new branch (`git checkout -b feature-branch`). +3. Make your changes. +4. Commit your changes (`git commit -am 'Add new feature'`). +5. Push to the branch (`git push origin feature-branch`). +6. Create a new Pull Request. + +## License +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index c68b7d6..beda535 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,28 @@ alabaster==0.7.16 +astroid==3.3.4 +asttokens==2.4.1 +attrs==23.2.0 Babel==2.15.0 +backcall==0.2.0 +beautifulsoup4==4.12.3 betterproto==2.0.0b6 black==24.4.2 +bleach==6.1.0 build==1.2.1 certifi==2024.2.2 charset-normalizer==3.3.2 click==8.1.7 +decorator==5.1.1 +defusedxml==0.7.1 +dill==0.3.8 +docopt==0.6.2 docutils==0.20.1 exceptiongroup==1.2.1 -grpcio==1.63.0 -grpcio-tools==1.62.0 +executing==2.0.1 +fastjsonschema==2.19.1 +flake8==7.1.1 +grpcio==1.66.0 +grpcio-tools==1.66.0 grpclib==0.4.7 h2==4.1.0 hpack==4.0.0 @@ -17,29 +30,60 @@ hyperframe==6.0.1 idna==3.7 imagesize==1.4.1 iniconfig==2.0.0 +ipython==8.12.3 isort==5.13.2 +jedi==0.19.1 Jinja2==3.1.4 +jsonschema==4.22.0 +jsonschema-specifications==2023.12.1 +jupyter_client==8.6.1 +jupyter_core==5.7.2 +jupyterlab_pygments==0.3.0 +-e git+ssh://git@github.com/Matter-and-Form/three-python-library.git@3945411f4d9d439ca8420b53966bfee785a14bdb#egg=maf_three markdown-it-py==3.0.0 MarkupSafe==2.1.5 +matplotlib-inline==0.1.7 +mccabe==0.7.0 mdit-py-plugins==0.4.0 mdurl==0.1.2 +mistune==3.0.2 multidict==6.0.5 +mypy==1.11.2 mypy-extensions==1.0.0 myst-parser==3.0.1 +nbclient==0.10.0 +nbconvert==7.16.4 +nbformat==5.10.4 +numpy==1.26.4 +opencv-python==4.10.0.84 packaging==24.0 +pandocfilters==1.5.1 +parso==0.8.4 pathspec==0.12.1 +pexpect==4.9.0 +pickleshare==0.7.5 +pipreqs==0.5.0 platformdirs==4.2.1 pluggy==1.5.0 -protobuf==4.25.3 +prompt-toolkit==3.0.43 +protobuf==5.27.3 +ptyprocess==0.7.0 +pure-eval==0.2.2 +pycodestyle==2.12.1 +pyflakes==3.2.0 Pygments==2.18.0 +pylint==3.3.1 pyproject_hooks==1.1.0 pytest==8.2.0 python-dateutil==2.9.0.post0 PyYAML==6.0.1 +pyzmq==26.0.3 +referencing==0.35.1 requests==2.31.0 +rpds-py==0.18.1 six==1.16.0 snowballstemmer==2.2.0 -setuptools==69.5.1 +soupsieve==2.5 Sphinx==7.3.7 sphinx-rtd-theme==2.0.0 sphinxcontrib-applehelp==1.0.8 @@ -49,6 +93,16 @@ sphinxcontrib-jquery==4.1 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.7 sphinxcontrib-serializinghtml==1.1.10 +stack-data==0.6.3 +tinycss2==1.3.0 tomli==2.0.1 +tomlkit==0.13.2 +tornado==6.4 +traitlets==5.14.3 +types-protobuf==5.27.0.20240626 typing_extensions==4.11.0 urllib3==2.2.1 +wcwidth==0.2.13 +webencodings==0.5.1 +websocket-client==1.8.0 +yarg==0.1.9 From c37bae5aa7a24b8d86914287120fca86db0b115a Mon Sep 17 00:00:00 2001 From: drewsipher Date: Wed, 20 Nov 2024 17:09:06 -0500 Subject: [PATCH 74/86] Fix examples link in readme --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 43a3508..b3f0979 100644 --- a/README.md +++ b/README.md @@ -93,16 +93,13 @@ scanner.list_settings() ``` ### Available Examples -The library comes with several pre-made examples. To list the available examples, run: - -```sh -ls examples/ -``` +### Available Examples +The library comes with several pre-made examples. You can find them in the [examples directory](https://github.com/Matter-and-Form/three-python-library/tree/develop/maf_three/examples). To run a specific example, use: ```sh -python examples/.py +python maf_three/examples/.py ``` ## Documentation From 1a179ae431a6ea9827cf60bedaa491bca3328fdc Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 21 Nov 2024 09:03:58 -0500 Subject: [PATCH 75/86] Update version to match server --- maf_three/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maf_three/__init__.py b/maf_three/__init__.py index 0f607a5..73d4c8b 100644 --- a/maf_three/__init__.py +++ b/maf_three/__init__.py @@ -1 +1 @@ -__version__ = "6.0.0" +__version__ = "8.0.0" From f43c39c0d4105968ff9b1e219a46e3be9814f4d8 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 21 Nov 2024 14:41:01 -0500 Subject: [PATCH 76/86] Fixes build-proto from scratch --- .github/workflows/CD.yml | 2 +- .github/workflows/CI.yml | 6 +- README.md | 2 +- doc/source/_static/css/custom.css | 7 -- doc/source/conf.py | 41 -------- doc/source/index.rst | 19 ---- doc/source/pages/examples.md | 47 ---------- doc/source/pages/modules.rst | 63 ------------- doc/source/pages/quickStart.md | 11 --- maf_three/__init__.py | 2 +- maf_three/examples/simpleScanner.py | 2 +- maf_three/examples/task.py | 6 +- maf_three/setup.py | 41 ++++++++ requirements.txt | 104 --------------------- scripts/{build-doc.py => build_doc.py} | 0 scripts/build_proto.py | 32 +++++++ scripts/checkFiles.py | 32 +++++++ scripts/{build-proto.py => generatePyi.py} | 52 +++-------- scripts/transpileProto.py | 4 +- 19 files changed, 131 insertions(+), 342 deletions(-) delete mode 100644 doc/source/_static/css/custom.css delete mode 100644 doc/source/conf.py delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/pages/examples.md delete mode 100644 doc/source/pages/modules.rst delete mode 100644 doc/source/pages/quickStart.md create mode 100644 maf_three/setup.py rename scripts/{build-doc.py => build_doc.py} (100%) create mode 100644 scripts/build_proto.py create mode 100644 scripts/checkFiles.py rename scripts/{build-proto.py => generatePyi.py} (68%) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 0ed6440..de6d7d8 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -77,7 +77,7 @@ jobs: # Build proto files - name: Build proto files - run: python3 ./scripts/build-proto.py + run: python3 ./scripts/build_proto.py # Build - name: Build diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index a424e3e..2e725ae 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -44,11 +44,13 @@ jobs: # Set version - name: Set Version - run: echo "__version__ = \"0.0.0\"" > maf_three/__init__.py + run: | + VERSION=$(python3 setup.py --version) + echo "__version__ = \"$VERSION\"" > maf_three/__init__.py # Build proto files - name: Build proto files - run: python3 ./scripts/build-proto.py + run: python3 ./scripts/build_proto.py # Build - name: Build diff --git a/README.md b/README.md index b3f0979..237268b 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ pip install -r requirements.txt This is only necessary if you have an update the schema. Keep in mind that schema's are tied to THREE server releases. Generated files are commited to this repo.To generate the Python source files again from the Schema files, run: ```sh -python3 ./scipts/build-proto.py +python3 ./scipts/build_proto.py ``` #### Package Build diff --git a/doc/source/_static/css/custom.css b/doc/source/_static/css/custom.css deleted file mode 100644 index 6f0d66c..0000000 --- a/doc/source/_static/css/custom.css +++ /dev/null @@ -1,7 +0,0 @@ - - -/* Override css for the toctree items generated by autodoc. */ -.rst-content code,.rst-content tt,code { - font-size: 100%; - font-family: SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, Courier, monospace; -} \ No newline at end of file diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index f4a62bb..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,41 +0,0 @@ - - -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -project = 'maf_three library' -copyright = '2024, Matter and Form' -author = 'Matter and Form' - -# Add the path to maf_three (see autodoc can find it) -import os -import sys -sys.path.insert(0, os.path.abspath('../..')) - - -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration -extensions = [ - 'myst_parser', - 'sphinx.ext.doctest', - 'sphinx.ext.autodoc', - 'sphinx.ext.autosummary', - #'sphinx.ext.napoleon' -] - -# Keep the member order as defined in the source -autodoc_member_order='bysource' - -source_suffix = ['.rst', '.md'] - - -# -- Options for HTML output ------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output -html_theme = 'sphinx_rtd_theme' - -# These folders are copied to the documentation's HTML output -html_static_path = ['_static'] - -# These paths are relative to html_static_path -html_css_files = [ - 'css/custom.css', -] \ No newline at end of file diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index a7bc641..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,19 +0,0 @@ - -Welcome to maf_three library's documentation! -============================================= - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - ./pages/quickStart.md - ./pages/examples.md - ./pages/modules.rst - - -.. Indices and tables -.. ================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/doc/source/pages/examples.md b/doc/source/pages/examples.md deleted file mode 100644 index 2d93dad..0000000 --- a/doc/source/pages/examples.md +++ /dev/null @@ -1,47 +0,0 @@ - -# Examples - -**maf_three** comes with pre made examples. To list the available examples, call: - -`python3 -m maf_three.examples list` - -To run a specific example call: - -`python3 -m maf_three.examples example_name` - -## connection -```{eval-rst} -.. literalinclude:: ../../../maf_three/examples/connection.py - :linenos: -``` - -## projector -```{eval-rst} -.. literalinclude:: ../../../maf_three/examples/projector.py - :linenos: -``` - -## turntable -```{eval-rst} -.. literalinclude:: ../../../maf_three/examples/turntable.py - :linenos: -``` - -## task -```{eval-rst} -.. literalinclude:: ../../../maf_three/examples/task.py - :linenos: -``` -## turntableCalibration -```{eval-rst} -.. literalinclude:: ../../../maf_three/examples/turntableCalibration.py - :linenos: -``` - -## simpleScanner -```{eval-rst} -.. literalinclude:: ../../../maf_three/examples/simpleScanner.py - :linenos: -``` - - diff --git a/doc/source/pages/modules.rst b/doc/source/pages/modules.rst deleted file mode 100644 index 80bf817..0000000 --- a/doc/source/pages/modules.rst +++ /dev/null @@ -1,63 +0,0 @@ - -============================================= -Modules -============================================= - - ----------------------------- - maf_three ----------------------------- -.. automodule:: maf_three.scanner - :members: - :undoc-members: - -.. automodule:: maf_three.V3Task - :members: - :undoc-members: - -.. automodule:: maf_three.task - :members: - :undoc-members: - -.. automodule:: maf_three.buffer - :members: - :undoc-members: - -.. automodule:: maf_three.serialization - :members: - - ----------------------------- -MF.V3.Settings ----------------------------- -.. automodule:: maf_three.MF.V3.Settings - :members: - :undoc-members: - - ----------------------------- -MF.V3.Descriptors ----------------------------- -.. automodule:: maf_three.MF.V3.Descriptors - :members: - :undoc-members: - -.. automodule:: maf_three.MF.V3.Descriptors.Calibration - :members: - :undoc-members: - -.. automodule:: maf_three.MF.V3.Descriptors.Network - :members: - :undoc-members: - - ----------------------------- -MF.V3.Descriptors.Settings ----------------------------- - -.. automodule:: maf_three.MF.V3.Descriptors.Settings - :members: - :undoc-members: - - - diff --git a/doc/source/pages/quickStart.md b/doc/source/pages/quickStart.md deleted file mode 100644 index d3c64fb..0000000 --- a/doc/source/pages/quickStart.md +++ /dev/null @@ -1,11 +0,0 @@ - - - -# Quick start - -## Installation - -`pip install maf_three` - -## Connect to the scanner -`python3 -m maf_three.examples connection` \ No newline at end of file diff --git a/maf_three/__init__.py b/maf_three/__init__.py index 73d4c8b..5400bb9 100644 --- a/maf_three/__init__.py +++ b/maf_three/__init__.py @@ -1 +1 @@ -__version__ = "8.0.0" +__version__ = '8.20.0' \ No newline at end of file diff --git a/maf_three/examples/simpleScanner.py b/maf_three/examples/simpleScanner.py index c114457..63ab33a 100644 --- a/maf_three/examples/simpleScanner.py +++ b/maf_three/examples/simpleScanner.py @@ -56,7 +56,7 @@ def OnBuffer(descriptor, buffer:bytes): global frame0, frame1 # Video task - if descriptor.Task['Type'] == 'Video': + if descriptor.Task['Type'] == 'Video': if descriptor.Index == 0: frame0 = cv2.imdecode(np.frombuffer(buffer, np.uint8), cv2.IMREAD_COLOR) else: diff --git a/maf_three/examples/task.py b/maf_three/examples/task.py index 0385d7c..5df1541 100644 --- a/maf_three/examples/task.py +++ b/maf_three/examples/task.py @@ -49,7 +49,11 @@ def OnTask(task:Task): # Try to scan without input => Will trigger an error scanner.new_scan() - scanner.list_settings() + projectTask = scanner.list_projects() + + for project_obj in projectTask.Output: + project = Project.Brief(**project_obj) + print('Project index:', project.index, ' - Name:', project.name) except Exception as error: print('Error: ', error) diff --git a/maf_three/setup.py b/maf_three/setup.py new file mode 100644 index 0000000..f55da86 --- /dev/null +++ b/maf_three/setup.py @@ -0,0 +1,41 @@ +from setuptools import setup, find_packages +import os + +# Function to read the version from maf_three/__init__.py +def get_version(): + version_file = os.path.join('maf_three', '__init__.py') + with open(version_file, 'r') as f: + exec(f.read(), globals()) + return __version__ + +# Read the requirements from requirements.txt +with open('requirements.txt', 'r') as f: + requirements = f.read().splitlines() + +# Read the long description from README.md +with open('README.md', 'r', encoding='utf-8') as f: + long_description = f.read() + +setup( + name='maf_three', + version=get_version(), + description='Matter and Form - THREE - Library', + long_description=long_description, + long_description_content_type='text/markdown', + author='Matter and Form', + author_email='info@matterandform.net', + url='https://github.com/Matter-and-Form/three-python-library', + packages=find_packages(exclude=['tests', 'scripts', 'examples']), + include_package_data=True, + install_requires=requirements, + python_requires='>=3.10', + classifiers=[ + 'Programming Language :: Python :: 3', + 'Operating System :: OS Independent', + ], + entry_points={ + 'console_scripts': [ + 'examples=maf_three.examples:main_cli', + ], + }, +) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index beda535..11f31c2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,108 +1,4 @@ -alabaster==0.7.16 -astroid==3.3.4 -asttokens==2.4.1 -attrs==23.2.0 -Babel==2.15.0 -backcall==0.2.0 -beautifulsoup4==4.12.3 -betterproto==2.0.0b6 -black==24.4.2 -bleach==6.1.0 -build==1.2.1 -certifi==2024.2.2 -charset-normalizer==3.3.2 -click==8.1.7 -decorator==5.1.1 -defusedxml==0.7.1 -dill==0.3.8 -docopt==0.6.2 -docutils==0.20.1 -exceptiongroup==1.2.1 -executing==2.0.1 -fastjsonschema==2.19.1 flake8==7.1.1 -grpcio==1.66.0 -grpcio-tools==1.66.0 -grpclib==0.4.7 -h2==4.1.0 -hpack==4.0.0 -hyperframe==6.0.1 -idna==3.7 -imagesize==1.4.1 -iniconfig==2.0.0 -ipython==8.12.3 -isort==5.13.2 -jedi==0.19.1 -Jinja2==3.1.4 -jsonschema==4.22.0 -jsonschema-specifications==2023.12.1 -jupyter_client==8.6.1 -jupyter_core==5.7.2 -jupyterlab_pygments==0.3.0 --e git+ssh://git@github.com/Matter-and-Form/three-python-library.git@3945411f4d9d439ca8420b53966bfee785a14bdb#egg=maf_three -markdown-it-py==3.0.0 -MarkupSafe==2.1.5 -matplotlib-inline==0.1.7 mccabe==0.7.0 -mdit-py-plugins==0.4.0 -mdurl==0.1.2 -mistune==3.0.2 -multidict==6.0.5 -mypy==1.11.2 -mypy-extensions==1.0.0 -myst-parser==3.0.1 -nbclient==0.10.0 -nbconvert==7.16.4 -nbformat==5.10.4 -numpy==1.26.4 -opencv-python==4.10.0.84 -packaging==24.0 -pandocfilters==1.5.1 -parso==0.8.4 -pathspec==0.12.1 -pexpect==4.9.0 -pickleshare==0.7.5 -pipreqs==0.5.0 -platformdirs==4.2.1 -pluggy==1.5.0 -prompt-toolkit==3.0.43 -protobuf==5.27.3 -ptyprocess==0.7.0 -pure-eval==0.2.2 pycodestyle==2.12.1 pyflakes==3.2.0 -Pygments==2.18.0 -pylint==3.3.1 -pyproject_hooks==1.1.0 -pytest==8.2.0 -python-dateutil==2.9.0.post0 -PyYAML==6.0.1 -pyzmq==26.0.3 -referencing==0.35.1 -requests==2.31.0 -rpds-py==0.18.1 -six==1.16.0 -snowballstemmer==2.2.0 -soupsieve==2.5 -Sphinx==7.3.7 -sphinx-rtd-theme==2.0.0 -sphinxcontrib-applehelp==1.0.8 -sphinxcontrib-devhelp==1.0.6 -sphinxcontrib-htmlhelp==2.0.5 -sphinxcontrib-jquery==4.1 -sphinxcontrib-jsmath==1.0.1 -sphinxcontrib-qthelp==1.0.7 -sphinxcontrib-serializinghtml==1.1.10 -stack-data==0.6.3 -tinycss2==1.3.0 -tomli==2.0.1 -tomlkit==0.13.2 -tornado==6.4 -traitlets==5.14.3 -types-protobuf==5.27.0.20240626 -typing_extensions==4.11.0 -urllib3==2.2.1 -wcwidth==0.2.13 -webencodings==0.5.1 -websocket-client==1.8.0 -yarg==0.1.9 diff --git a/scripts/build-doc.py b/scripts/build_doc.py similarity index 100% rename from scripts/build-doc.py rename to scripts/build_doc.py diff --git a/scripts/build_proto.py b/scripts/build_proto.py new file mode 100644 index 0000000..e5ac168 --- /dev/null +++ b/scripts/build_proto.py @@ -0,0 +1,32 @@ +import subprocess +import os +import sys +import shutil + +from transpileProto import transpile +from checkFiles import check_files + +if __name__ == "__main__": + # Remove the folder maf_three/MF if it exists + mf_folder = "./maf_three/MF" + if os.path.exists(mf_folder): + shutil.rmtree(mf_folder) + + # Transpile the proto files + transpile('./V3Schema','./maf_three/') + + # Check the python files for formatting and linting issues + check_files('./maf_three/MF/V3/') + + # These have to be done in subprocesses because the imports are not available in the current process. Chicken and egg problem + # Add the scripts folder to the system path + scripts_folder = os.path.abspath(os.path.dirname(__file__)) + sys.path.insert(0, scripts_folder) + + # Install the package in editable mode + subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-e', '.']) + + # Generate the proto files + subprocess.check_call([sys.executable, f'{scripts_folder}/generatePyi.py']) + + exit(0) \ No newline at end of file diff --git a/scripts/checkFiles.py b/scripts/checkFiles.py new file mode 100644 index 0000000..fa160d9 --- /dev/null +++ b/scripts/checkFiles.py @@ -0,0 +1,32 @@ +import os +import argparse + +from flake8.api import legacy as flake8 + +def run_flake8(file_path): + style_guide = flake8.get_style_guide(select=['E', 'F'], ignore=['E501']) + report = style_guide.check_files([file_path]) + return report.get_statistics('E') + report.get_statistics('F') + +def check_files(directory): + print("Checking python files...") + hasError = False + for root, _, files in os.walk(directory): + for file in files: + if file.endswith('.py') and file != '__init__.py': + filepath = os.path.join(root, file) + # print(f"Running flake8 on {filepath}...") + flake8_output = run_flake8(filepath) + if flake8_output: + print(f"flake8 issues in {filepath}:\n{flake8_output}") + hasError = True + else: + print(f"Clean: {filepath}") + if hasError: + raise Exception("Formatting Or Linting Issues Found") + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Check python files for formatting and linting issues.") + parser.add_argument('input_dir', type=str, nargs='?', default='./maf_three/MF/V3/', help='The directory to check for python files.') + args = parser.parse_args() + check_files(args.input_dir) \ No newline at end of file diff --git a/scripts/build-proto.py b/scripts/generatePyi.py similarity index 68% rename from scripts/build-proto.py rename to scripts/generatePyi.py index 9748273..b5a99c7 100644 --- a/scripts/build-proto.py +++ b/scripts/generatePyi.py @@ -1,13 +1,7 @@ -import subprocess -import os import inspect import importlib import ast - -import transpileProto -from flake8.api import legacy as flake8 -import shutil - +import argparse def get_imports_from_file(file_path): with open(file_path, 'r') as file: @@ -33,9 +27,10 @@ def adjust_signature(signature): return signature.replace('NoneType', 'None') def generate_pyi(scanner_module_name, three_module_name, output_file): + print("Generating .pyi file...") # Import the modules - scanner_module = importlib.import_module(scanner_module_name) three_module = importlib.import_module(three_module_name) + scanner_module = importlib.import_module(scanner_module_name) # Get the class from scanner.py scanner_class = getattr(scanner_module, 'Scanner') @@ -86,39 +81,14 @@ def generate_pyi(scanner_module_name, three_module_name, output_file): # Write to the output file with open(output_file, 'w') as f: f.write('\n'.join(pyi_content)) - - -def run_flake8(file_path): - style_guide = flake8.get_style_guide(select=['E', 'F'], ignore=['E501']) - report = style_guide.check_files([file_path]) - return report.get_statistics('E') + report.get_statistics('F') - -def check_files(directory): - hasError = False - for root, _, files in os.walk(directory): - for file in files: - if file.endswith('.py') and file != '__init__.py': - filepath = os.path.join(root, file) - # print(f"Running flake8 on {filepath}...") - flake8_output = run_flake8(filepath) - if flake8_output: - print(f"flake8 issues in {filepath}:\n{flake8_output}") - hasError = True - else: - print(f"Clean: {filepath}") - if hasError: - raise Exception("Formatting Or Linting Issues Found") + print("Completed!") if __name__ == "__main__": - # Remove the folder maf_three/MF if it exists - mf_folder = "./maf_three/MF" - if os.path.exists(mf_folder): - shutil.rmtree(mf_folder) - print("Building python files...") - transpileProto.transpile("./V3Schema/", "./maf_three/") - print("Checking python files...") - check_files("./maf_three/MF/V3/") - print("Generating .pyi file...") - generate_pyi('maf_three.scanner', 'maf_three.MF.V3.Three', './maf_three/scanner.pyi') - print("Completed!") + parser = argparse.ArgumentParser(description="Generate .pyi file for a given module.") + parser.add_argument('scanner_module', type=str, nargs='?', default='maf_three.scanner', help='The module name for the scanner class.') + parser.add_argument('three_module', type=str, nargs='?', default='maf_three.MF.V3.Three', help='The module name for the three functions.') + parser.add_argument('output_file', type=str, nargs='?', default='./maf_three/scanner.pyi', help='The output file for the .pyi content.') + args = parser.parse_args() + + generate_pyi(args.scanner_module, args.three_module, args.output_file) exit(0) \ No newline at end of file diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index 980a36a..c069e5d 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -676,6 +676,7 @@ def generate_init_files(paths: set, tree: Tree, output_dir: str): def transpile(input_dir:str, output_dir:str): + print("Building python files...") # Check to see if input_dir and output_dir contain a trailing slash if input_dir[-1] == '/': input_dir = input_dir[:-1] @@ -687,11 +688,10 @@ def transpile(input_dir:str, output_dir:str): paths = generate_python_code(output_dir, tree) generate_init_files(paths, tree, output_dir) - if __name__ == "__main__": parser = argparse.ArgumentParser(description="Generate Python classes and enums from protobuf schema objects.") - parser.add_argument('input_dir', type=str, nargs='?', default='./V3Schema', help='The input directory containing the protobuf schema objects.') + parser.add_argument('input_dir', type=str, nargs='?', default= './V3Schema', help='The input directory containing the protobuf schema objects.') parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three/', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() transpile(args.input_dir, args.output_dir) From 1fc5dcbcf31c0ba2593107f5a300f1d7d4bd127f Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 21 Nov 2024 14:43:52 -0500 Subject: [PATCH 77/86] update to requirements and task for examples --- maf_three/examples/task.py | 5 ++++- requirements.txt | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/maf_three/examples/task.py b/maf_three/examples/task.py index 5df1541..6ffd3f6 100644 --- a/maf_three/examples/task.py +++ b/maf_three/examples/task.py @@ -50,7 +50,10 @@ def OnTask(task:Task): scanner.new_scan() projectTask = scanner.list_projects() - + if projectTask.Error: + print('Error:', projectTask.Error) + return + for project_obj in projectTask.Output: project = Project.Brief(**project_obj) print('Project index:', project.index, ' - Name:', project.name) diff --git a/requirements.txt b/requirements.txt index 11f31c2..b006088 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,7 @@ flake8==7.1.1 mccabe==0.7.0 +numpy==2.1.3 +protobuf==5.28.3 pycodestyle==2.12.1 pyflakes==3.2.0 +websocket-client==1.8.0 From 1dac70a1af2f8028d948bf457edf42929a374cee Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 21 Nov 2024 14:46:13 -0500 Subject: [PATCH 78/86] Small fixes to projector and task --- maf_three/examples/projector.py | 2 +- maf_three/examples/task.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/maf_three/examples/projector.py b/maf_three/examples/projector.py index 71ccb2f..8916b96 100644 --- a/maf_three/examples/projector.py +++ b/maf_three/examples/projector.py @@ -50,7 +50,7 @@ def main(): ### Project an image print('Project Image') - width = 640 + width = 512 height = 480 img = np.zeros([height, width, 3], np.uint8) for y in range(height): diff --git a/maf_three/examples/task.py b/maf_three/examples/task.py index 6ffd3f6..703a69b 100644 --- a/maf_three/examples/task.py +++ b/maf_three/examples/task.py @@ -1,4 +1,3 @@ -import numpy as np import json from typing import List From bf22a6afe8a4fd51dd4a19258c80d37ddec1a322 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 21 Nov 2024 20:13:23 -0500 Subject: [PATCH 79/86] Movemanifest Changes and readme updates --- README.md | 22 ++++++++++++++++------ maf_three/MANIFEST.in | 5 +++++ requirements.txt | 1 + 3 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 maf_three/MANIFEST.in diff --git a/README.md b/README.md index 237268b..e4f2091 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ pip install -r requirements.txt This is only necessary if you have an update the schema. Keep in mind that schema's are tied to THREE server releases. Generated files are commited to this repo.To generate the Python source files again from the Schema files, run: ```sh -python3 ./scipts/build_proto.py +python3 ./scripts/build_proto.py ``` #### Package Build @@ -85,21 +85,31 @@ Here is an example of how to use the library to connect to the scanner and contr ```python from matter_and_form_three import Scanner +# Create and connect to the scanner scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) +# Use the Zeroconf address or replace with the ip scanner.Connect("ws://matterandform.local:8081") -# Do some tasks -scanner.list_settings() +# Simple request to list all projects +projectTask = scanner.list_projects() + +# Check the output from the task for errors +if projectTask.Error: + print('Error:', projectTask.Error) + return +# Do something with the output +for project_obj in projectTask.Output: + project = Project.Brief(**project_obj) + print('Project index:', project.index, ' - Name:', project.name) ``` ### Available Examples -### Available Examples -The library comes with several pre-made examples. You can find them in the [examples directory](https://github.com/Matter-and-Form/three-python-library/tree/develop/maf_three/examples). +The library comes with several pre-made examples. You can find them in the [examples directory](https://github.com/Matter-and-Form/three-python-library/tree/develop/three/examples). To run a specific example, use: ```sh -python maf_three/examples/.py +python three/examples/.py ``` ## Documentation diff --git a/maf_three/MANIFEST.in b/maf_three/MANIFEST.in new file mode 100644 index 0000000..b9081f5 --- /dev/null +++ b/maf_three/MANIFEST.in @@ -0,0 +1,5 @@ +include README.md +include LICENSE +include requirements.txt +recursive-include your_package_name *.py +recursive-include your_package_name *.pyi \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index b006088..5932c5a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ protobuf==5.28.3 pycodestyle==2.12.1 pyflakes==3.2.0 websocket-client==1.8.0 +wheel \ No newline at end of file From 8a9dd5926509cdc3cebb737377ee027450d79aa3 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 21 Nov 2024 20:15:48 -0500 Subject: [PATCH 80/86] Include other examples in toml --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index b2d281d..67939a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,5 +39,7 @@ version = {attr = "maf_three.__version__"} # python3 -m maf_three.examples connection # python3 -m maf_three.examples projector # python3 -m maf_three.examples simpleScanner +# python3 -m maf_three.examples task +# python3 -m maf_three.examples turntableCalibration [project.scripts] examples = "maf_three.examples:main_cli" \ No newline at end of file From 320fb00931961ff28512ee66bdbc418a5c209bd3 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 21 Nov 2024 20:22:44 -0500 Subject: [PATCH 81/86] renamed project to three --- .github/workflows/CD.yml | 4 +- .github/workflows/CI.yml | 4 +- .vscode/launch.json | 6 +- pyproject.toml | 20 +- scripts/build_doc.py | 8 +- scripts/build_proto.py | 8 +- scripts/checkFiles.py | 2 +- scripts/generatePyi.py | 6 +- scripts/transpileProto.py | 2 +- {maf_three => three}/MANIFEST.in | 0 three/MF/V3/Buffer.py | 66 + three/MF/V3/Descriptors/BoundingBox.py | 24 + three/MF/V3/Descriptors/Calibration.py | 79 ++ three/MF/V3/Descriptors/Export.py | 38 + three/MF/V3/Descriptors/Image.py | 13 + three/MF/V3/Descriptors/Merge.py | 34 + three/MF/V3/Descriptors/Network.py | 11 + three/MF/V3/Descriptors/Project.py | 47 + three/MF/V3/Descriptors/ProjectActions.py | 37 + three/MF/V3/Descriptors/RemoveVertices.py | 26 + three/MF/V3/Descriptors/ScanData.py | 53 + three/MF/V3/Descriptors/Settings/Advanced.py | 284 ++++ three/MF/V3/Descriptors/Settings/Camera.py | 71 + three/MF/V3/Descriptors/Settings/Capture.py | 46 + three/MF/V3/Descriptors/Settings/I18n.py | 16 + three/MF/V3/Descriptors/Settings/Projector.py | 23 + three/MF/V3/Descriptors/Settings/Scanner.py | 37 + three/MF/V3/Descriptors/Settings/Software.py | 13 + three/MF/V3/Descriptors/Settings/Style.py | 16 + three/MF/V3/Descriptors/Settings/Turntable.py | 33 + three/MF/V3/Descriptors/Settings/Tutorials.py | 30 + three/MF/V3/Descriptors/Settings/Viewer.py | 15 + three/MF/V3/Descriptors/Settings/__init__.py | 11 + three/MF/V3/Descriptors/Software.py | 19 + three/MF/V3/Descriptors/System.py | 19 + three/MF/V3/Descriptors/Transform.py | 16 + three/MF/V3/Descriptors/VideoFrame.py | 27 + three/MF/V3/Descriptors/Wifi.py | 26 + three/MF/V3/Descriptors/__init__.py | 13 + three/MF/V3/Settings/Advanced.py | 185 +++ three/MF/V3/Settings/Align.py | 82 ++ three/MF/V3/Settings/AutoFocus.py | 24 + three/MF/V3/Settings/BoundingBox.py | 15 + three/MF/V3/Settings/Camera.py | 20 + three/MF/V3/Settings/Capture.py | 25 + three/MF/V3/Settings/CopyGroup.py | 25 + three/MF/V3/Settings/CopyProject.py | 9 + three/MF/V3/Settings/Export.py | 29 + three/MF/V3/Settings/Group.py | 26 + three/MF/V3/Settings/I18n.py | 16 + three/MF/V3/Settings/Merge.py | 85 ++ three/MF/V3/Settings/NewGroup.py | 32 + three/MF/V3/Settings/Project.py | 10 + three/MF/V3/Settings/Projector.py | 58 + three/MF/V3/Settings/Quality.py | 10 + three/MF/V3/Settings/Rectangle.py | 13 + three/MF/V3/Settings/Remesh.py | 36 + three/MF/V3/Settings/RemoveVertices.py | 10 + three/MF/V3/Settings/Scan.py | 157 +++ three/MF/V3/Settings/ScanData.py | 40 + three/MF/V3/Settings/ScanSelection.py | 22 + three/MF/V3/Settings/Scanner.py | 37 + three/MF/V3/Settings/Software.py | 9 + three/MF/V3/Settings/Style.py | 15 + three/MF/V3/Settings/Turntable.py | 11 + three/MF/V3/Settings/Tutorials.py | 18 + three/MF/V3/Settings/Video.py | 31 + three/MF/V3/Settings/Viewer.py | 7 + three/MF/V3/Settings/Wifi.py | 9 + three/MF/V3/Settings/__init__.py | 30 + three/MF/V3/Task.py | 89 ++ three/MF/V3/Tasks/AddMergeToProject.py | 66 + three/MF/V3/Tasks/Align.py | 77 ++ three/MF/V3/Tasks/AutoFocus.py | 94 ++ three/MF/V3/Tasks/BoundingBox.py | 82 ++ three/MF/V3/Tasks/CalibrateCameras.py | 58 + three/MF/V3/Tasks/CalibrateTurntable.py | 61 + .../MF/V3/Tasks/CalibrationCaptureTargets.py | 66 + three/MF/V3/Tasks/CameraCalibration.py | 60 + three/MF/V3/Tasks/CloseProject.py | 53 + three/MF/V3/Tasks/ConnectWifi.py | 67 + three/MF/V3/Tasks/DepthMap.py | 141 ++ three/MF/V3/Tasks/DetectCalibrationCard.py | 65 + three/MF/V3/Tasks/DownloadProject.py | 89 ++ three/MF/V3/Tasks/Export.py | 103 ++ three/MF/V3/Tasks/ExportLogs.py | 87 ++ three/MF/V3/Tasks/ExportMerge.py | 97 ++ three/MF/V3/Tasks/FlattenGroup.py | 72 + three/MF/V3/Tasks/ForgetWifi.py | 53 + three/MF/V3/Tasks/HasCameras.py | 56 + three/MF/V3/Tasks/HasProjector.py | 56 + three/MF/V3/Tasks/HasTurntable.py | 56 + three/MF/V3/Tasks/ListExportFormats.py | 86 ++ three/MF/V3/Tasks/ListGroups.py | 85 ++ three/MF/V3/Tasks/ListNetworkInterfaces.py | 61 + three/MF/V3/Tasks/ListProjects.py | 61 + three/MF/V3/Tasks/ListScans.py | 77 ++ three/MF/V3/Tasks/ListSettings.py | 86 ++ three/MF/V3/Tasks/ListWifi.py | 64 + three/MF/V3/Tasks/Merge.py | 104 ++ three/MF/V3/Tasks/MergeData.py | 239 ++++ three/MF/V3/Tasks/MoveGroup.py | 79 ++ three/MF/V3/Tasks/NewGroup.py | 77 ++ three/MF/V3/Tasks/NewProject.py | 69 + three/MF/V3/Tasks/NewScan.py | 82 ++ three/MF/V3/Tasks/OpenProject.py | 66 + three/MF/V3/Tasks/PopSettings.py | 92 ++ three/MF/V3/Tasks/PushSettings.py | 86 ++ three/MF/V3/Tasks/Reboot.py | 53 + three/MF/V3/Tasks/RemoveGroups.py | 64 + three/MF/V3/Tasks/RemoveProjects.py | 68 + .../MF/V3/Tasks/RestoreFactoryCalibration.py | 53 + three/MF/V3/Tasks/RotateTurntable.py | 59 + three/MF/V3/Tasks/ScanData.py | 239 ++++ three/MF/V3/Tasks/SetCameras.py | 76 ++ three/MF/V3/Tasks/SetGroup.py | 104 ++ three/MF/V3/Tasks/SetProject.py | 80 ++ three/MF/V3/Tasks/SetProjector.py | 75 ++ three/MF/V3/Tasks/Shutdown.py | 53 + three/MF/V3/Tasks/SplitGroup.py | 74 ++ three/MF/V3/Tasks/StartVideo.py | 64 + three/MF/V3/Tasks/StopVideo.py | 53 + three/MF/V3/Tasks/SystemInfo.py | 92 ++ three/MF/V3/Tasks/TransformGroup.py | 81 ++ three/MF/V3/Tasks/TurntableCalibration.py | 61 + three/MF/V3/Tasks/UpdateSettings.py | 105 ++ three/MF/V3/Tasks/UploadProject.py | 79 ++ three/MF/V3/Tasks/__init__.py | 56 + three/MF/V3/Three.py | 1160 +++++++++++++++++ three/MF/V3/__init__.py | 3 + {maf_three => three}/__init__.py | 0 {maf_three => three}/examples/__main__.py | 4 +- {maf_three => three}/examples/connection.py | 2 +- {maf_three => three}/examples/projector.py | 14 +- .../examples/simpleScanner.py | 10 +- {maf_three => three}/examples/task.py | 8 +- .../examples/turntableCalibration.py | 10 +- {maf_three => three}/scanner.py | 10 +- {maf_three => three}/scanner.pyi | 12 +- {maf_three => three}/serialization.py | 0 {maf_three => three}/setup.py | 8 +- .../tests/test_proto_camera.py | 0 .../tests/test_proto_turntable.py | 0 143 files changed, 8122 insertions(+), 69 deletions(-) rename {maf_three => three}/MANIFEST.in (100%) create mode 100644 three/MF/V3/Buffer.py create mode 100644 three/MF/V3/Descriptors/BoundingBox.py create mode 100644 three/MF/V3/Descriptors/Calibration.py create mode 100644 three/MF/V3/Descriptors/Export.py create mode 100644 three/MF/V3/Descriptors/Image.py create mode 100644 three/MF/V3/Descriptors/Merge.py create mode 100644 three/MF/V3/Descriptors/Network.py create mode 100644 three/MF/V3/Descriptors/Project.py create mode 100644 three/MF/V3/Descriptors/ProjectActions.py create mode 100644 three/MF/V3/Descriptors/RemoveVertices.py create mode 100644 three/MF/V3/Descriptors/ScanData.py create mode 100644 three/MF/V3/Descriptors/Settings/Advanced.py create mode 100644 three/MF/V3/Descriptors/Settings/Camera.py create mode 100644 three/MF/V3/Descriptors/Settings/Capture.py create mode 100644 three/MF/V3/Descriptors/Settings/I18n.py create mode 100644 three/MF/V3/Descriptors/Settings/Projector.py create mode 100644 three/MF/V3/Descriptors/Settings/Scanner.py create mode 100644 three/MF/V3/Descriptors/Settings/Software.py create mode 100644 three/MF/V3/Descriptors/Settings/Style.py create mode 100644 three/MF/V3/Descriptors/Settings/Turntable.py create mode 100644 three/MF/V3/Descriptors/Settings/Tutorials.py create mode 100644 three/MF/V3/Descriptors/Settings/Viewer.py create mode 100644 three/MF/V3/Descriptors/Settings/__init__.py create mode 100644 three/MF/V3/Descriptors/Software.py create mode 100644 three/MF/V3/Descriptors/System.py create mode 100644 three/MF/V3/Descriptors/Transform.py create mode 100644 three/MF/V3/Descriptors/VideoFrame.py create mode 100644 three/MF/V3/Descriptors/Wifi.py create mode 100644 three/MF/V3/Descriptors/__init__.py create mode 100644 three/MF/V3/Settings/Advanced.py create mode 100644 three/MF/V3/Settings/Align.py create mode 100644 three/MF/V3/Settings/AutoFocus.py create mode 100644 three/MF/V3/Settings/BoundingBox.py create mode 100644 three/MF/V3/Settings/Camera.py create mode 100644 three/MF/V3/Settings/Capture.py create mode 100644 three/MF/V3/Settings/CopyGroup.py create mode 100644 three/MF/V3/Settings/CopyProject.py create mode 100644 three/MF/V3/Settings/Export.py create mode 100644 three/MF/V3/Settings/Group.py create mode 100644 three/MF/V3/Settings/I18n.py create mode 100644 three/MF/V3/Settings/Merge.py create mode 100644 three/MF/V3/Settings/NewGroup.py create mode 100644 three/MF/V3/Settings/Project.py create mode 100644 three/MF/V3/Settings/Projector.py create mode 100644 three/MF/V3/Settings/Quality.py create mode 100644 three/MF/V3/Settings/Rectangle.py create mode 100644 three/MF/V3/Settings/Remesh.py create mode 100644 three/MF/V3/Settings/RemoveVertices.py create mode 100644 three/MF/V3/Settings/Scan.py create mode 100644 three/MF/V3/Settings/ScanData.py create mode 100644 three/MF/V3/Settings/ScanSelection.py create mode 100644 three/MF/V3/Settings/Scanner.py create mode 100644 three/MF/V3/Settings/Software.py create mode 100644 three/MF/V3/Settings/Style.py create mode 100644 three/MF/V3/Settings/Turntable.py create mode 100644 three/MF/V3/Settings/Tutorials.py create mode 100644 three/MF/V3/Settings/Video.py create mode 100644 three/MF/V3/Settings/Viewer.py create mode 100644 three/MF/V3/Settings/Wifi.py create mode 100644 three/MF/V3/Settings/__init__.py create mode 100644 three/MF/V3/Task.py create mode 100644 three/MF/V3/Tasks/AddMergeToProject.py create mode 100644 three/MF/V3/Tasks/Align.py create mode 100644 three/MF/V3/Tasks/AutoFocus.py create mode 100644 three/MF/V3/Tasks/BoundingBox.py create mode 100644 three/MF/V3/Tasks/CalibrateCameras.py create mode 100644 three/MF/V3/Tasks/CalibrateTurntable.py create mode 100644 three/MF/V3/Tasks/CalibrationCaptureTargets.py create mode 100644 three/MF/V3/Tasks/CameraCalibration.py create mode 100644 three/MF/V3/Tasks/CloseProject.py create mode 100644 three/MF/V3/Tasks/ConnectWifi.py create mode 100644 three/MF/V3/Tasks/DepthMap.py create mode 100644 three/MF/V3/Tasks/DetectCalibrationCard.py create mode 100644 three/MF/V3/Tasks/DownloadProject.py create mode 100644 three/MF/V3/Tasks/Export.py create mode 100644 three/MF/V3/Tasks/ExportLogs.py create mode 100644 three/MF/V3/Tasks/ExportMerge.py create mode 100644 three/MF/V3/Tasks/FlattenGroup.py create mode 100644 three/MF/V3/Tasks/ForgetWifi.py create mode 100644 three/MF/V3/Tasks/HasCameras.py create mode 100644 three/MF/V3/Tasks/HasProjector.py create mode 100644 three/MF/V3/Tasks/HasTurntable.py create mode 100644 three/MF/V3/Tasks/ListExportFormats.py create mode 100644 three/MF/V3/Tasks/ListGroups.py create mode 100644 three/MF/V3/Tasks/ListNetworkInterfaces.py create mode 100644 three/MF/V3/Tasks/ListProjects.py create mode 100644 three/MF/V3/Tasks/ListScans.py create mode 100644 three/MF/V3/Tasks/ListSettings.py create mode 100644 three/MF/V3/Tasks/ListWifi.py create mode 100644 three/MF/V3/Tasks/Merge.py create mode 100644 three/MF/V3/Tasks/MergeData.py create mode 100644 three/MF/V3/Tasks/MoveGroup.py create mode 100644 three/MF/V3/Tasks/NewGroup.py create mode 100644 three/MF/V3/Tasks/NewProject.py create mode 100644 three/MF/V3/Tasks/NewScan.py create mode 100644 three/MF/V3/Tasks/OpenProject.py create mode 100644 three/MF/V3/Tasks/PopSettings.py create mode 100644 three/MF/V3/Tasks/PushSettings.py create mode 100644 three/MF/V3/Tasks/Reboot.py create mode 100644 three/MF/V3/Tasks/RemoveGroups.py create mode 100644 three/MF/V3/Tasks/RemoveProjects.py create mode 100644 three/MF/V3/Tasks/RestoreFactoryCalibration.py create mode 100644 three/MF/V3/Tasks/RotateTurntable.py create mode 100644 three/MF/V3/Tasks/ScanData.py create mode 100644 three/MF/V3/Tasks/SetCameras.py create mode 100644 three/MF/V3/Tasks/SetGroup.py create mode 100644 three/MF/V3/Tasks/SetProject.py create mode 100644 three/MF/V3/Tasks/SetProjector.py create mode 100644 three/MF/V3/Tasks/Shutdown.py create mode 100644 three/MF/V3/Tasks/SplitGroup.py create mode 100644 three/MF/V3/Tasks/StartVideo.py create mode 100644 three/MF/V3/Tasks/StopVideo.py create mode 100644 three/MF/V3/Tasks/SystemInfo.py create mode 100644 three/MF/V3/Tasks/TransformGroup.py create mode 100644 three/MF/V3/Tasks/TurntableCalibration.py create mode 100644 three/MF/V3/Tasks/UpdateSettings.py create mode 100644 three/MF/V3/Tasks/UploadProject.py create mode 100644 three/MF/V3/Tasks/__init__.py create mode 100644 three/MF/V3/Three.py create mode 100644 three/MF/V3/__init__.py rename {maf_three => three}/__init__.py (100%) rename {maf_three => three}/examples/__main__.py (83%) rename {maf_three => three}/examples/connection.py (91%) rename {maf_three => three}/examples/projector.py (87%) rename {maf_three => three}/examples/simpleScanner.py (95%) rename {maf_three => three}/examples/task.py (90%) rename {maf_three => three}/examples/turntableCalibration.py (89%) rename {maf_three => three}/scanner.py (98%) rename {maf_three => three}/scanner.pyi (98%) rename {maf_three => three}/serialization.py (100%) rename {maf_three => three}/setup.py (85%) rename {maf_three => three}/tests/test_proto_camera.py (100%) rename {maf_three => three}/tests/test_proto_turntable.py (100%) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index de6d7d8..9cc556f 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -73,7 +73,7 @@ jobs: # Set version - name: Set Version - run: echo "__version__ = \"${{ env.PACKAGE_VERSION }}\"" > maf_three/__init__.py + run: echo "__version__ = \"${{ env.PACKAGE_VERSION }}\"" > three/__init__.py # Build proto files - name: Build proto files @@ -85,7 +85,7 @@ jobs: # Install our package (required for the tests to find the namespace : MF.V3) - name: Install - run: pip3 install ./dist/maf_three-${{ env.PACKAGE_VERSION }}-py3-none-any.whl + run: pip3 install ./dist/three-${{ env.PACKAGE_VERSION }}-py3-none-any.whl # Run the tests - name: Test diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 2e725ae..4862d44 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -46,7 +46,7 @@ jobs: - name: Set Version run: | VERSION=$(python3 setup.py --version) - echo "__version__ = \"$VERSION\"" > maf_three/__init__.py + echo "__version__ = \"$VERSION\"" > three/__init__.py # Build proto files - name: Build proto files @@ -58,7 +58,7 @@ jobs: # Install our package (required for the tests to find the namespace : MF.V3) - name: Install - run: pip3 install ./dist/maf_three-0.0.0-py3-none-any.whl + run: pip3 install ./dist/three-0.0.0-py3-none-any.whl # Run the tests - name: Test diff --git a/.vscode/launch.json b/.vscode/launch.json index 17411f5..160af0c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,7 +14,7 @@ "name": "Python: Simple Scanner Example", "type": "debugpy", "request": "launch", - "program": "${workspaceFolder}/maf_three/examples/simpleScanner.py", + "program": "${workspaceFolder}/three/examples/simpleScanner.py", "console": "integratedTerminal", "cwd": "${workspaceFolder}", "justMyCode": true @@ -23,7 +23,7 @@ "name": "Python: Task Example", "type": "debugpy", "request": "launch", - "program": "${workspaceFolder}/maf_three/examples/task.py", + "program": "${workspaceFolder}/three/examples/task.py", "console": "integratedTerminal", "cwd": "${workspaceFolder}", "justMyCode": true @@ -32,7 +32,7 @@ "name": "Python: Calibrate Turntable Example", "type": "debugpy", "request": "launch", - "program": "${workspaceFolder}/maf_three/examples/turntableCalibration.py", + "program": "${workspaceFolder}/three/examples/turntableCalibration.py", "console": "integratedTerminal", "cwd": "${workspaceFolder}", "justMyCode": true diff --git a/pyproject.toml b/pyproject.toml index 67939a8..4f95b67 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" # Package info and dependencies [project] -name = "maf_three" +name = "three" description = "Matter and Form - THREE - Library" dynamic = ["version"] classifiers = [ @@ -27,19 +27,19 @@ Documentation = "https://github.com/Matter-and-Form/three-python-library/wiki" # Package source [tool.setuptools.package-dir] -maf_three = "maf_three" -"MF" = "maf_three/MF" +three = "three" +"MF" = "three/MF" # Dynamic input [tool.setuptools.dynamic] -version = {attr = "maf_three.__version__"} +version = {attr = "three.__version__"} # Command line accessible scripts # Usage: -# python3 -m maf_three.examples connection -# python3 -m maf_three.examples projector -# python3 -m maf_three.examples simpleScanner -# python3 -m maf_three.examples task -# python3 -m maf_three.examples turntableCalibration +# python3 -m three.examples connection +# python3 -m three.examples projector +# python3 -m three.examples simpleScanner +# python3 -m three.examples task +# python3 -m three.examples turntableCalibration [project.scripts] -examples = "maf_three.examples:main_cli" \ No newline at end of file +examples = "three.examples:main_cli" \ No newline at end of file diff --git a/scripts/build_doc.py b/scripts/build_doc.py index ddf03b8..1559aa5 100644 --- a/scripts/build_doc.py +++ b/scripts/build_doc.py @@ -8,7 +8,7 @@ # Paths scriptPath = os.path.dirname(os.path.realpath(__file__)) protoInputPath = scriptPath + '/../V3Schema/' -protoOutputPath = scriptPath + '/../maf_three' +protoOutputPath = scriptPath + '/../three' docInputPath = scriptPath + '/../doc/source/' docOutputPath = scriptPath + '/../doc/build/' @@ -58,9 +58,9 @@ def CleanUpGeneratedInit(file): if badImport and ')' in line: badImport = False -# Save the maf_three/__init__.py +# Save the three/__init__.py # It will be overridden by the betterprotoc compiler -initFilePath = scriptPath + "/../maf_three/__init__.py" +initFilePath = scriptPath + "/../three/__init__.py" initFilePathBack = initFilePath+'.back' os.rename(initFilePath, initFilePathBack) @@ -68,7 +68,7 @@ def CleanUpGeneratedInit(file): protoFiles = glob.glob(protoInputPath+"/**/*.proto", recursive=True) result = BuildProtoFiles(protoFiles, protoInputPath, protoOutputPath) -# Restore maf_three/__init__.py +# Restore three/__init__.py os.rename(initFilePathBack, initFilePath) # Inspect the results diff --git a/scripts/build_proto.py b/scripts/build_proto.py index e5ac168..d8e3b27 100644 --- a/scripts/build_proto.py +++ b/scripts/build_proto.py @@ -7,16 +7,16 @@ from checkFiles import check_files if __name__ == "__main__": - # Remove the folder maf_three/MF if it exists - mf_folder = "./maf_three/MF" + # Remove the folder three/MF if it exists + mf_folder = "./three/MF" if os.path.exists(mf_folder): shutil.rmtree(mf_folder) # Transpile the proto files - transpile('./V3Schema','./maf_three/') + transpile('./V3Schema','./three/') # Check the python files for formatting and linting issues - check_files('./maf_three/MF/V3/') + check_files('./three/MF/V3/') # These have to be done in subprocesses because the imports are not available in the current process. Chicken and egg problem # Add the scripts folder to the system path diff --git a/scripts/checkFiles.py b/scripts/checkFiles.py index fa160d9..5b96e95 100644 --- a/scripts/checkFiles.py +++ b/scripts/checkFiles.py @@ -27,6 +27,6 @@ def check_files(directory): if __name__ == "__main__": parser = argparse.ArgumentParser(description="Check python files for formatting and linting issues.") - parser.add_argument('input_dir', type=str, nargs='?', default='./maf_three/MF/V3/', help='The directory to check for python files.') + parser.add_argument('input_dir', type=str, nargs='?', default='./three/MF/V3/', help='The directory to check for python files.') args = parser.parse_args() check_files(args.input_dir) \ No newline at end of file diff --git a/scripts/generatePyi.py b/scripts/generatePyi.py index b5a99c7..ffac677 100644 --- a/scripts/generatePyi.py +++ b/scripts/generatePyi.py @@ -85,9 +85,9 @@ def generate_pyi(scanner_module_name, three_module_name, output_file): if __name__ == "__main__": parser = argparse.ArgumentParser(description="Generate .pyi file for a given module.") - parser.add_argument('scanner_module', type=str, nargs='?', default='maf_three.scanner', help='The module name for the scanner class.') - parser.add_argument('three_module', type=str, nargs='?', default='maf_three.MF.V3.Three', help='The module name for the three functions.') - parser.add_argument('output_file', type=str, nargs='?', default='./maf_three/scanner.pyi', help='The output file for the .pyi content.') + parser.add_argument('scanner_module', type=str, nargs='?', default='three.scanner', help='The module name for the scanner class.') + parser.add_argument('three_module', type=str, nargs='?', default='three.MF.V3.Three', help='The module name for the three functions.') + parser.add_argument('output_file', type=str, nargs='?', default='./three/scanner.pyi', help='The output file for the .pyi content.') args = parser.parse_args() generate_pyi(args.scanner_module, args.three_module, args.output_file) diff --git a/scripts/transpileProto.py b/scripts/transpileProto.py index c069e5d..2940b4f 100644 --- a/scripts/transpileProto.py +++ b/scripts/transpileProto.py @@ -692,7 +692,7 @@ def transpile(input_dir:str, output_dir:str): if __name__ == "__main__": parser = argparse.ArgumentParser(description="Generate Python classes and enums from protobuf schema objects.") parser.add_argument('input_dir', type=str, nargs='?', default= './V3Schema', help='The input directory containing the protobuf schema objects.') - parser.add_argument('output_dir', type=str, nargs='?', default='./maf_three/', help='The output directory to write the generated Python classes and enums.') + parser.add_argument('output_dir', type=str, nargs='?', default='./three/', help='The output directory to write the generated Python classes and enums.') args = parser.parse_args() transpile(args.input_dir, args.output_dir) exit(0) \ No newline at end of file diff --git a/maf_three/MANIFEST.in b/three/MANIFEST.in similarity index 100% rename from maf_three/MANIFEST.in rename to three/MANIFEST.in diff --git a/three/MF/V3/Buffer.py b/three/MF/V3/Buffer.py new file mode 100644 index 0000000..9927532 --- /dev/null +++ b/three/MF/V3/Buffer.py @@ -0,0 +1,66 @@ +from MF.V3.Task import Task as MF_V3_Task_Task +from google.protobuf import any_pb2 as _any_pb2 + + +class Buffer: + """* + Generic buffer message for the Three Scanner. + + Some tasks require the server and/or client to transfer binary data. In such cases the _buffer message_ is sent to inform the server/client what the data is and what task it belongs to. The binary data it refers to is sent immediately following the buffer message. + + For example, `DownloadProject` requires the server to transfer a ZIP file containing the project data to the client. + + > First, the client sends the task request to the server: + + ```json + { + "Task":{ + "Index":1, + "Type":"DownloadProject", + "Input":5 + } + } + ``` + + > The server sends the buffer message telling the client to expect a binary data transfer and what to do with it. Note that the buffer message `Task` field echoes the task request, making it clear which request this data is a response to. + + ```json + { + "Buffer":{ + "Descriptor":"Project-5.zip", + "Index":0, + "Size":15682096, + "Task":{ + "Index":1, + "Type":"DownloadProject", + "Input":5 + } + } + } + ``` + + > The server then sends the 15682096 byte data buffer of the project ZIP file. + > Finally, the server sends a task completion message. + + ```json + { + "Task":{ + "Index":1, + "Type":"DownloadProject" + "Input":5, + "State":"Completed" + } + } + ``` + """ + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: _any_pb2 = None): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The task associated with the data buffer. This informs the client which request this data buffer corresponds to. + self.Task = Task + # Optional data buffer descriptor. See each task definition for details. + self.Descriptor = Descriptor + + diff --git a/three/MF/V3/Descriptors/BoundingBox.py b/three/MF/V3/Descriptors/BoundingBox.py new file mode 100644 index 0000000..c7652ec --- /dev/null +++ b/three/MF/V3/Descriptors/BoundingBox.py @@ -0,0 +1,24 @@ +from typing import List + + +class BoundingBox: + # BoundingBox descriptor. + def __init__(self, center: List[float] = None, size: List[float] = None, rotation: List[float] = None, transform: List[float] = None): + # The center of the bounding box. + self.center = center + # The size of the bounding box. + self.size = size + """ + The 3x3 rotation matrix of the bounding box. + The first, second and third column vectors are the x, y and z axes of the bounding box. + """ + self.rotation = rotation + """ + The 4x4 matrix that transforms the canonical cube with corners [±1, ±1, ±1] to the + bounding box in world coordinates. + The transform can be used as the model matrix for rendering the bounding box with an + OpenGL shader. + """ + self.transform = transform + + diff --git a/three/MF/V3/Descriptors/Calibration.py b/three/MF/V3/Descriptors/Calibration.py new file mode 100644 index 0000000..3df31dc --- /dev/null +++ b/three/MF/V3/Descriptors/Calibration.py @@ -0,0 +1,79 @@ +from enum import Enum +from typing import List + + +# Calibration quality. +class Quality(Enum): + Empty = "None" # The calibration does not exist. + Poor = "Poor" # Poor calibration quality. + Fair = "Fair" # Fair calibration quality. + Good = "Good" # Good calibration quality. + Excellent = "Excellent" # Excellent calibration quality. + + +class Camera: + # Camera calibration descriptor. + def __init__(self, quality: 'Quality', date: List[int] = None): + # Calibration quality. + self.quality = quality + # Calibration date and time [year, month, day, hour, minute, second]. + self.date = date + + +class Turntable: + # Turntable calibration descriptor. + def __init__(self, quality: 'Quality', date: List[int] = None, focus: List[int] = None): + # Calibration quality. + self.quality = quality + # Calibration date and time [year, month, day, hour, minute, second]. + self.date = date + # Focus values of each camera during calibration. + self.focus = focus + + +class CaptureTarget: + """ + Calibration capture target. + + The camera calibration capture targets are used to draw quad overlays on the video stream to guide a user as to where to position the calibration card for each capture during camera calibration. + """ + def __init__(self, camera: int, quads: List[float] = None): + # Index of the camera that is displayed to the user for this capture. + self.camera = camera + """ + The target quad for each camera. + This is a set of 16 numbers defining the quad coordinates on the left and right camera. + The first 4 pairs of numbers define the quad on the left camera. + The last 4 pairs of numbers define the quad on the right camera. + """ + self.quads = quads + + +class DetectedCard: + # Detected calibration card descriptor. + class Target: + # Calibration capture target properties. + def __init__(self, match: float, hold: float): + """ + A normalized value indicating how closely the calibration card matches the target + overlay. 0 indicates a poor match. 1 indicates a good match. + """ + self.match = match + """ + A normalized value indicating how long the user has held the calibration card steady over + the target overlay. When the value reaches 1, the user has held the calibration card + steady for the complete required duration. + """ + self.hold = hold + + def __init__(self, size: List[int] = None, quad: List[float] = None, corners: List[float] = None, target: 'Target' = None): + # The calibration card columns and rows. + self.size = size + # The calibration card bounding quadrilateral. + self.quad = quad + # The detected corners of the calibration card. + self.corners = corners + # The capture target properties, if a capture target is specified. + self.target = target + + diff --git a/three/MF/V3/Descriptors/Export.py b/three/MF/V3/Descriptors/Export.py new file mode 100644 index 0000000..258340c --- /dev/null +++ b/three/MF/V3/Descriptors/Export.py @@ -0,0 +1,38 @@ +from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export +from enum import Enum +from typing import List + + +class Export: + # Scan data descriptor. + # Geometry face types. + class Face(Enum): + NoFace = "NoFace" # No faces. + Point = "Point" # Point faces. + Line = "Line" # Line faces. + Triangle = "Triangle" # Triangle faces. + Quad = "Quad" # Quad faces. + + # Texture support types. + class Texture(Enum): + Empty = "None" # The format does not support textures. + Single = "Single" # The format supports a single texture only. + Multiple = "Multiple" # The format supports multiple textures. + + def __init__(self, format: MF_V3_Settings_Export_Export.Format, extension: str, description: str, normals: bool, colors: bool, textures: 'Texture', faces: List['Face'] = None): + # Export format. + self.format = format + # Export file extension. e.g. ".ply" + self.extension = extension + # Export format description. e.g. "Polygon format" + self.description = description + # Vertex normal support. + self.normals = normals + # Vertex color support. + self.colors = colors + # Texture (UV) support. + self.textures = textures + # Types of supported faces. + self.faces = faces + + diff --git a/three/MF/V3/Descriptors/Image.py b/three/MF/V3/Descriptors/Image.py new file mode 100644 index 0000000..1e830d4 --- /dev/null +++ b/three/MF/V3/Descriptors/Image.py @@ -0,0 +1,13 @@ +class Image: + # Image descriptor. + def __init__(self, width: int, height: int, step: int, type: int): + # Image width. + self.width = width + # Image height. + self.height = height + # Image row step in bytes. + self.step = step + # OpenCV image [type](https:gist.github.com/yangcha/38f2fa630e223a8546f9b48ebbb3e61a). + self.type = type + + diff --git a/three/MF/V3/Descriptors/Merge.py b/three/MF/V3/Descriptors/Merge.py new file mode 100644 index 0000000..2ebdd84 --- /dev/null +++ b/three/MF/V3/Descriptors/Merge.py @@ -0,0 +1,34 @@ +from typing import List + + +class Merge: + # Merge descriptor. + class Mesh: + # Mesh descriptor. + def __init__(self, name: str, triangles: int, quads: int, positions: int, normals: int, uvs: int, size: int): + # The mesh name. + self.name = name + # Number of mesh triangle faces. + self.triangles = triangles + # Number of quad faces. + self.quads = quads + # Number of vertex positions. + self.positions = positions + # Number of vertex normals. + self.normals = normals + # Number of UV coordinates. + self.uvs = uvs + # Total mesh size in bytes. + self.size = size + + def __init__(self, scans: int, textures: int, maxSimplifyCount: int, meshes: List['Mesh'] = None): + # The number of input scans. + self.scans = scans + # The number of input textures. + self.textures = textures + # The maximum number of faces for the simplify merge step. + self.maxSimplifyCount = maxSimplifyCount + # The set of merged mesh descriptors. + self.meshes = meshes + + diff --git a/three/MF/V3/Descriptors/Network.py b/three/MF/V3/Descriptors/Network.py new file mode 100644 index 0000000..9f5ce91 --- /dev/null +++ b/three/MF/V3/Descriptors/Network.py @@ -0,0 +1,11 @@ +class Interface: + # Network interface descriptor. + def __init__(self, name: str, ip: str, ssid: str): + # The name of the interface. + self.name = name + # The address associated with the interface. + self.ip = ip + # The ssid or name of the network. + self.ssid = ssid + + diff --git a/three/MF/V3/Descriptors/Project.py b/three/MF/V3/Descriptors/Project.py new file mode 100644 index 0000000..90e35bc --- /dev/null +++ b/three/MF/V3/Descriptors/Project.py @@ -0,0 +1,47 @@ +from typing import List + + +class Project: + # V3 project descriptor. + class Brief: + # V3 project brief descriptor. + def __init__(self, index: int, name: str, size: int, modified: List[int] = None): + # Project index. + self.index = index + # Project name. + self.name = name + # Size in bytes. + self.size = size + # Project last modified date and time [year, month, day, hour, minute, second]. + self.modified = modified + + class Group: + # V3 project scan group tree descriptor. + def __init__(self, index: int, name: str, visible: bool, collapsed: bool, color: List[float] = None, rotation: List[float] = None, translation: List[float] = None, scan: int = None, groups: List['Project.Group'] = None): + # Group index. + self.index = index + # Group name. + self.name = name + # Visibility in the renderer. + self.visible = visible + # Collapsed state in the group tree. + self.collapsed = collapsed + # Color in the renderer. + self.color = color + # Axis-angle rotation vector. The direction of the vector is the rotation axis. The magnitude of the vector is rotation angle in radians. + self.rotation = rotation + # Translation vector. + self.translation = translation + # The scan index. If defined this group is a scan and cannot have subgroups. + self.scan = scan + # Subgroups. + self.groups = groups + + def __init__(self, index: int, name: str, groups: 'Group'): + # Project index. + self.index = index + # Project name. + self.name = name + self.groups = groups + + diff --git a/three/MF/V3/Descriptors/ProjectActions.py b/three/MF/V3/Descriptors/ProjectActions.py new file mode 100644 index 0000000..57485bc --- /dev/null +++ b/three/MF/V3/Descriptors/ProjectActions.py @@ -0,0 +1,37 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from typing import List + + +class ProjectAction: + # Descriptor for a project undo/redo action. + class Scan: + # Scan vertices removal/insertion metadata. + def __init__(self, index: int, vertices: int, triangles: int): + # The scan index. + self.index = index + # The number of vertices after undo or redo. + self.vertices = vertices + # The number of triangles after undo or redo. + self.triangles = triangles + + def __init__(self, task: str, project: MF_V3_Descriptors_Project_Project = None, scans: List['Scan'] = None): + # The original websocket task that the action is undoing or redoing. + self.task = task + """ + The updated project data after undo or redo. + If undefined, then there was no change to the project. + """ + self.project = project + # The list of scans whose vertex/triangle elements were changed by the undo/redo action. + self.scans = scans + + +class ProjectActions: + # Project undo and redo action descriptors. + def __init__(self, undo: List[str] = None, redo: List[str] = None): + # Project undo action descriptors. + self.undo = undo + # Project redo action descriptors. + self.redo = redo + + diff --git a/three/MF/V3/Descriptors/RemoveVertices.py b/three/MF/V3/Descriptors/RemoveVertices.py new file mode 100644 index 0000000..2aa3ac3 --- /dev/null +++ b/three/MF/V3/Descriptors/RemoveVertices.py @@ -0,0 +1,26 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from typing import List + + +class RemoveVertices: + # Descriptor a remove vertices task. + class Scan: + # Scan vertex and triangle removal metadata. + def __init__(self, index: int, vertices: int, triangles: int): + # The scan index. + self.index = index + # The number of vertices after the removal. + self.vertices = vertices + # The number of triangles after the removal. + self.triangles = triangles + + def __init__(self, scans: List['Scan'] = None, groups: MF_V3_Descriptors_Project_Project.Group = None): + # The list of scans whose vertices were removed. + self.scans = scans + """ + The updated project data after undo or redo. + If undefined, then there was no change to the project. + """ + self.groups = groups + + diff --git a/three/MF/V3/Descriptors/ScanData.py b/three/MF/V3/Descriptors/ScanData.py new file mode 100644 index 0000000..0442683 --- /dev/null +++ b/three/MF/V3/Descriptors/ScanData.py @@ -0,0 +1,53 @@ +from enum import Enum +from typing import List + + +class ScanData: + # Scan data descriptor. + class Buffer: + # Scan buffer descriptor. + class Component: + # Scan buffer component descriptor. + # Scan buffer component types. + class Type(Enum): + Position = "Position" # Vertex position. + Normal = "Normal" # Vertex normal. + Color = "Color" # Vertex color. + UV = "UV" # Vertex texture coordinate. + Triangle = "Triangle" # Triangle index. + Texture = "Texture" # Texture. + + def __init__(self, type: 'Type', size: int, offset: int, normalized: bool): + # Scan buffer component type. + self.type = type + # Scan buffer component size (ie. the number of elements). + self.size = size + """ + Scan buffer component offset. + This is the starting element for this component at every stride of the buffer. + """ + self.offset = offset + # Indicates if the data is normalized. + self.normalized = normalized + + def __init__(self, stride: int, components: List['Component'] = None): + # Scan buffer stride. This should be greater or equal to the sum of the component sizes. + self.stride = stride + # Scan buffer components. + self.components = components + + def __init__(self, index: int, name: str, buffers: List['Buffer'] = None, mean: List[float] = None, stddev: List[float] = None, axisAlignedBoundingBox: List[float] = None): + # Scan index. + self.index = index + # Scan name. + self.name = name + # Scan buffer descriptors. + self.buffers = buffers + # The mean (centroid) of the vertex positions. + self.mean = mean + # The standard deviation of the vertex positions. + self.stddev = stddev + # The axis-aligned bounding box of the vertex positions. + self.axisAlignedBoundingBox = axisAlignedBoundingBox + + diff --git a/three/MF/V3/Descriptors/Settings/Advanced.py b/three/MF/V3/Descriptors/Settings/Advanced.py new file mode 100644 index 0000000..423fb3e --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/Advanced.py @@ -0,0 +1,284 @@ +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from typing import List + + +class Advanced: + # Advanced settings descriptor. + class Use: + # Use advanced settings. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + class Capture: + # Capture settings descriptor. + class HorizontalFrequencies: + def __init__(self, min: int, max: int, value: List[int] = None, default: List[int] = None): + self.min = min + self.max = max + self.value = value + self.default = default + + class VerticalFrequencies: + def __init__(self, min: int, max: int, value: List[int] = None, default: List[int] = None): + self.min = min + self.max = max + self.value = value + self.default = default + + def __init__(self, use: 'Advanced.Use', horizontalFrequencies: 'HorizontalFrequencies', verticalFrequencies: 'VerticalFrequencies'): + self.use = use + self.horizontalFrequencies = horizontalFrequencies + self.verticalFrequencies = verticalFrequencies + + class Sampling: + # Sampling settings descriptor. + class ProjectorSampleRate: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class ImageSampleRate: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, use: 'Advanced.Use', projectorSampleRate: 'ProjectorSampleRate', imageSampleRate: 'ImageSampleRate'): + # Use sampling settings. + self.use = use + self.projectorSampleRate = projectorSampleRate + self.imageSampleRate = imageSampleRate + + class EdgeDetection: + # Edge detection settings descriptor. + class Threshold: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class LaplacianKernelRadius: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class GaussianBlurRadius: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class GaussianBlurStdDev: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class MaximumWidthForProcessing: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, use: 'Advanced.Use', threshold: 'Threshold', laplacianKernelRadius: 'LaplacianKernelRadius', gaussianBlurRadius: 'GaussianBlurRadius', gaussianBlurStdDev: 'GaussianBlurStdDev', maximumWidthForProcessing: 'MaximumWidthForProcessing'): + self.use = use + self.threshold = threshold + self.laplacianKernelRadius = laplacianKernelRadius + self.gaussianBlurRadius = gaussianBlurRadius + self.gaussianBlurStdDev = gaussianBlurStdDev + self.maximumWidthForProcessing = maximumWidthForProcessing + + class PhaseFilter: + # Phase filter settings descriptor. + class KernelRadius: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class SpatialWeightStdDev: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, use: 'Advanced.Use', kernelRadius: 'KernelRadius', spatialWeightStdDev: 'SpatialWeightStdDev'): + self.use = use + self.kernelRadius = kernelRadius + self.spatialWeightStdDev = spatialWeightStdDev + + class AdaptiveSampling: + # Adaptive sampling settings descriptor. + class Type: + def __init__(self, value: MF_V3_Settings_Scan_Scan.Processing.AdaptiveSampling.Type, default: MF_V3_Settings_Scan_Scan.Processing.AdaptiveSampling.Type): + self.value = value + self.default = default + + class Rate: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, use: 'Advanced.Use', type: 'Type', rate: 'Rate'): + self.use = use + self.type = type + self.rate = rate + + class NormalEstimation: + # Normal estimation settings descriptor. + class Method: + def __init__(self, value: MF_V3_Settings_Scan_Scan.Processing.NormalEstimation.Method, default: MF_V3_Settings_Scan_Scan.Processing.NormalEstimation.Method): + self.value = value + self.default = default + + class MaximumNeighbourCount: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class MaximumNeighbourRadius: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class UseMaximumNeighbourCount: + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + class UseMaximumNeighbourRadius: + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, use: 'Advanced.Use', method: 'Method', maximumNeighbourCount: 'MaximumNeighbourCount', maximumNeighbourRadius: 'MaximumNeighbourRadius', useMaximumNeighbourCount: 'UseMaximumNeighbourCount', useMaximumNeighbourRadius: 'UseMaximumNeighbourRadius'): + self.use = use + self.method = method + self.maximumNeighbourCount = maximumNeighbourCount + self.maximumNeighbourRadius = maximumNeighbourRadius + self.useMaximumNeighbourCount = useMaximumNeighbourCount + self.useMaximumNeighbourRadius = useMaximumNeighbourRadius + + class OutlierRemoval: + # Outlier removal settings descriptor. + class NeighbourCount: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class NeighbourRadius: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, use: 'Advanced.Use', neighbourCount: 'NeighbourCount', neighbourRadius: 'NeighbourRadius'): + self.use = use + self.neighbourCount = neighbourCount + self.neighbourRadius = neighbourRadius + + class Remesh: + # Remesh settings descriptor. + class VoxelSize: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class Depth: + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class Scale: + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class LinearInterpolation: + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, use: 'Advanced.Use', voxelSize: 'VoxelSize', depth: 'Depth', scale: 'Scale', linearInterpolation: 'LinearInterpolation'): + self.use = use + self.voxelSize = voxelSize + self.depth = depth + self.scale = scale + self.linearInterpolation = linearInterpolation + + class Camera: + # Camera settings descriptor. + class UseContinuousExposureValues: + # Use continuous exposure values settings descriptor. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, useContinuousExposureValues: 'UseContinuousExposureValues'): + # Use continuous exposure values settings descriptor. + self.useContinuousExposureValues = useContinuousExposureValues + + class Turntable: + # Turntable settings descriptor. + class RampAngle: + # The angle in degrees to slow down the turntable at the end of a rotation. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, rampAngle: 'RampAngle'): + # The angle in degrees to slow down the turntable at the end of a rotation. + self.rampAngle = rampAngle + + def __init__(self, capture: 'Capture', sampling: 'Sampling', edgeDetection: 'EdgeDetection', phaseFilter: 'PhaseFilter', adaptiveSampling: 'AdaptiveSampling', normalEstimation: 'NormalEstimation', outlierRemoval: 'OutlierRemoval', remesh: 'Remesh', camera: 'Camera', turntable: 'Turntable'): + # Capture settings descriptor. + self.capture = capture + # Sampling settings descriptor. + self.sampling = sampling + # Edge detection settings descriptor. + self.edgeDetection = edgeDetection + # Phase filter settings descriptor. + self.phaseFilter = phaseFilter + # Adaptive sampling settings descriptor. + self.adaptiveSampling = adaptiveSampling + # Normal estimation settings descriptor. + self.normalEstimation = normalEstimation + # Outlier removal settings descriptor. + self.outlierRemoval = outlierRemoval + # Remesh settings descriptor. + self.remesh = remesh + # Camera settings descriptor. + self.camera = camera + # Turntable settings descriptor. + self.turntable = turntable + + diff --git a/three/MF/V3/Descriptors/Settings/Camera.py b/three/MF/V3/Descriptors/Settings/Camera.py new file mode 100644 index 0000000..df45cc0 --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/Camera.py @@ -0,0 +1,71 @@ +from MF.V3.Settings.Rectangle import Rectangle as MF_V3_Settings_Rectangle_Rectangle +from typing import List + + +class Camera: + # Camera settings descriptor. + class AutoExposure: + # Auto exposure. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + class Exposure: + # Exposure. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class AnalogGain: + # Analog gain. + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class DigitalGain: + # Digital gain. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class Focus: + # Focus settings descriptor. + class Value: + # Focus value. + def __init__(self, min: int, max: int, value: List[int] = None, default: List[int] = None): + self.min = min + self.max = max + self.value = value + self.default = default + + class Box: + # Auto focus box. + def __init__(self, value: List[MF_V3_Settings_Rectangle_Rectangle] = None, default: List[MF_V3_Settings_Rectangle_Rectangle] = None): + self.value = value + self.default = default + + def __init__(self, value: 'Value', box: 'Box'): + # Focus value. + self.value = value + # Auto focus box. + self.box = box + + def __init__(self, autoExposure: 'AutoExposure', exposure: 'Exposure', analogGain: 'AnalogGain', digitalGain: 'DigitalGain', focus: 'Focus'): + # Auto exposure. + self.autoExposure = autoExposure + # Exposure. + self.exposure = exposure + # Analog gain. + self.analogGain = analogGain + # Digital gain. + self.digitalGain = digitalGain + # Focus settings descriptor. + self.focus = focus + + diff --git a/three/MF/V3/Descriptors/Settings/Capture.py b/three/MF/V3/Descriptors/Settings/Capture.py new file mode 100644 index 0000000..8143c07 --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/Capture.py @@ -0,0 +1,46 @@ +from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality + + +class Capture: + # Capture settings descriptor. + class Quality: + # Capture quality preset. + def __init__(self, value: MF_V3_Settings_Quality_Quality, default: MF_V3_Settings_Quality_Quality): + self.value = value + self.default = default + + class Texture: + # Capture texture. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + class BlendCount: + # Capture image blend count for noise reduction. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class BlendFrequency: + # The starting frequency for which multiple capture images are blended. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, quality: 'Quality', texture: 'Texture', blendCount: 'BlendCount', horizontalBlendFrequency: 'BlendFrequency', verticalBlendFrequency: 'BlendFrequency'): + # Capture quality preset. + self.quality = quality + # Capture texture. + self.texture = texture + # Capture blend count. + self.blendCount = blendCount + # Starting horizontal blend frequency. + self.horizontalBlendFrequency = horizontalBlendFrequency + # Starting vertical blend frequency. + self.verticalBlendFrequency = verticalBlendFrequency + + diff --git a/three/MF/V3/Descriptors/Settings/I18n.py b/three/MF/V3/Descriptors/Settings/I18n.py new file mode 100644 index 0000000..f6ece28 --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/I18n.py @@ -0,0 +1,16 @@ +from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n + + +class I18n: + # I18n language settings descriptor. + class Language: + # Language settings descriptor. + def __init__(self, value: MF_V3_Settings_I18n_I18n.Language, default: MF_V3_Settings_I18n_I18n.Language): + self.value = value + self.default = default + + def __init__(self, language: 'Language'): + # Language settings descriptor. + self.language = language + + diff --git a/three/MF/V3/Descriptors/Settings/Projector.py b/three/MF/V3/Descriptors/Settings/Projector.py new file mode 100644 index 0000000..60310dc --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/Projector.py @@ -0,0 +1,23 @@ +class Projector: + # Projector settings descriptor. + class Brightness: + # Projector brightness. + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + class On: + # Projector on/off. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, brightness: 'Brightness', on: 'On'): + # Projector brightness. + self.brightness = brightness + # Projector on/off. + self.on = on + + diff --git a/three/MF/V3/Descriptors/Settings/Scanner.py b/three/MF/V3/Descriptors/Settings/Scanner.py new file mode 100644 index 0000000..f0d2e6a --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/Scanner.py @@ -0,0 +1,37 @@ +from MF.V3.Descriptors.Settings.Advanced import Advanced as MF_V3_Descriptors_Settings_Advanced_Advanced +from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera +from MF.V3.Descriptors.Settings.Capture import Capture as MF_V3_Descriptors_Settings_Capture_Capture +from MF.V3.Descriptors.Settings.I18n import I18n as MF_V3_Descriptors_Settings_I18n_I18n +from MF.V3.Descriptors.Settings.Projector import Projector as MF_V3_Descriptors_Settings_Projector_Projector +from MF.V3.Descriptors.Settings.Software import Software as MF_V3_Descriptors_Settings_Software_Software +from MF.V3.Descriptors.Settings.Style import Style as MF_V3_Descriptors_Settings_Style_Style +from MF.V3.Descriptors.Settings.Turntable import Turntable as MF_V3_Descriptors_Settings_Turntable_Turntable +from MF.V3.Descriptors.Settings.Tutorials import Tutorials as MF_V3_Descriptors_Settings_Tutorials_Tutorials +from MF.V3.Descriptors.Settings.Viewer import Viewer as MF_V3_Descriptors_Settings_Viewer_Viewer + + +class Scanner: + # Scanner settings descriptor. + def __init__(self, advanced: MF_V3_Descriptors_Settings_Advanced_Advanced, camera: MF_V3_Descriptors_Settings_Camera_Camera, capture: MF_V3_Descriptors_Settings_Capture_Capture, projector: MF_V3_Descriptors_Settings_Projector_Projector, i18n: MF_V3_Descriptors_Settings_I18n_I18n, style: MF_V3_Descriptors_Settings_Style_Style, turntable: MF_V3_Descriptors_Settings_Turntable_Turntable, tutorials: MF_V3_Descriptors_Settings_Tutorials_Tutorials, viewer: MF_V3_Descriptors_Settings_Viewer_Viewer, software: MF_V3_Descriptors_Settings_Software_Software): + # Advanced settings descriptor. + self.advanced = advanced + # Camera settings descriptor. + self.camera = camera + # Capture settings descriptor. + self.capture = capture + # Projector settings descriptor. + self.projector = projector + # Internalization setting descriptor. + self.i18n = i18n + # Style settings descriptor. + self.style = style + # Turntable settings descriptor. + self.turntable = turntable + # Tutorials settings descriptor. + self.tutorials = tutorials + # Viewer settings descriptor. + self.viewer = viewer + # Software settings descriptor. + self.software = software + + diff --git a/three/MF/V3/Descriptors/Settings/Software.py b/three/MF/V3/Descriptors/Settings/Software.py new file mode 100644 index 0000000..2bcc7bb --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/Software.py @@ -0,0 +1,13 @@ +class Software: + # Software settings descriptor. + class UpdateMajor: + # Enable major version updates which can have breaking API changes. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, updateMajor: 'UpdateMajor'): + # Enable major version updates which can have breaking API changes. + self.updateMajor = updateMajor + + diff --git a/three/MF/V3/Descriptors/Settings/Style.py b/three/MF/V3/Descriptors/Settings/Style.py new file mode 100644 index 0000000..274447f --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/Style.py @@ -0,0 +1,16 @@ +from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style + + +class Style: + # Style settings descriptor. + class Theme: + # Theme settings descriptor. + def __init__(self, value: MF_V3_Settings_Style_Style.Theme, default: MF_V3_Settings_Style_Style.Theme): + self.value = value + self.default = default + + def __init__(self, theme: 'Theme'): + # Theme settings descriptor. + self.theme = theme + + diff --git a/three/MF/V3/Descriptors/Settings/Turntable.py b/three/MF/V3/Descriptors/Settings/Turntable.py new file mode 100644 index 0000000..1655db7 --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/Turntable.py @@ -0,0 +1,33 @@ +class Turntable: + # Turntable settings descriptor. + class Scans: + # The number of turntable scans. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class Sweep: + # Turntable angle sweep in degrees. + def __init__(self, value: int, default: int, min: int, max: int): + self.value = value + self.default = default + self.min = min + self.max = max + + class Use: + # Use the turntable. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + def __init__(self, scans: 'Scans', sweep: 'Sweep', use: 'Use'): + # The number of turntable scans. + self.scans = scans + # Turntable angle sweep in degrees. + self.sweep = sweep + # Use the turntable. + self.use = use + + diff --git a/three/MF/V3/Descriptors/Settings/Tutorials.py b/three/MF/V3/Descriptors/Settings/Tutorials.py new file mode 100644 index 0000000..ea01eea --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/Tutorials.py @@ -0,0 +1,30 @@ +from typing import List + + +class Tutorials: + # Tutorials settings descriptor. + class Show: + # Tutorials to show. + def __init__(self, value: bool, default: bool): + self.value = value + self.default = default + + class Viewed: + # Viewed tutorials. + class Pages: + # Viewed tutorials pages. + def __init__(self, value: List[str] = None, default: List[str] = None): + self.value = value + self.default = default + + def __init__(self, pages: 'Pages'): + # Viewed tutorials pages. + self.pages = pages + + def __init__(self, show: 'Show', viewed: 'Viewed'): + # Show tutorials. + self.show = show + # Viewed tutorials. + self.viewed = viewed + + diff --git a/three/MF/V3/Descriptors/Settings/Viewer.py b/three/MF/V3/Descriptors/Settings/Viewer.py new file mode 100644 index 0000000..296fead --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/Viewer.py @@ -0,0 +1,15 @@ +class Viewer: + # 3D Viewer settings descriptor. + class TextureOpacity: + # Texture opacity. + def __init__(self, value: float, default: float, min: float, max: float): + self.value = value + self.default = default + self.min = min + self.max = max + + def __init__(self, textureOpacity: 'TextureOpacity'): + # Texture opacity. + self.textureOpacity = textureOpacity + + diff --git a/three/MF/V3/Descriptors/Settings/__init__.py b/three/MF/V3/Descriptors/Settings/__init__.py new file mode 100644 index 0000000..03ad69e --- /dev/null +++ b/three/MF/V3/Descriptors/Settings/__init__.py @@ -0,0 +1,11 @@ +from MF.V3.Descriptors.Settings.Advanced import * +from MF.V3.Descriptors.Settings.Camera import * +from MF.V3.Descriptors.Settings.Capture import * +from MF.V3.Descriptors.Settings.I18n import * +from MF.V3.Descriptors.Settings.Projector import * +from MF.V3.Descriptors.Settings.Scanner import * +from MF.V3.Descriptors.Settings.Software import * +from MF.V3.Descriptors.Settings.Style import * +from MF.V3.Descriptors.Settings.Turntable import * +from MF.V3.Descriptors.Settings.Tutorials import * +from MF.V3.Descriptors.Settings.Viewer import * diff --git a/three/MF/V3/Descriptors/Software.py b/three/MF/V3/Descriptors/Software.py new file mode 100644 index 0000000..4042713 --- /dev/null +++ b/three/MF/V3/Descriptors/Software.py @@ -0,0 +1,19 @@ +class Software: + # Software descriptor. + class Package: + # Software package descriptor. + def __init__(self, installed: str, update: str, changelog: str): + # The package installed version. + self.installed = installed + # The package update version. Empty if no update is available. + self.update = update + # The package changelog. Empty if no update is available or the update is a downgrade. + self.changelog = changelog + + def __init__(self, frontend: 'Package', server: 'Package'): + # Frontend software package. + self.frontend = frontend + # Server software package. + self.server = server + + diff --git a/three/MF/V3/Descriptors/System.py b/three/MF/V3/Descriptors/System.py new file mode 100644 index 0000000..3c8b3a4 --- /dev/null +++ b/three/MF/V3/Descriptors/System.py @@ -0,0 +1,19 @@ +class System: + # System descriptor. + class DiskSpace: + # Disk space descriptor. + def __init__(self, capacity: int, available: int): + # Disk space capacity in bytes. + self.capacity = capacity + # Available disk space in bytes. + self.available = available + + def __init__(self, serialNumber: str, diskSpace: 'DiskSpace', publicKey: str): + # Serial number; + self.serialNumber = serialNumber + # Used and available disk space. + self.diskSpace = diskSpace + # GPG public key. + self.publicKey = publicKey + + diff --git a/three/MF/V3/Descriptors/Transform.py b/three/MF/V3/Descriptors/Transform.py new file mode 100644 index 0000000..8638d74 --- /dev/null +++ b/three/MF/V3/Descriptors/Transform.py @@ -0,0 +1,16 @@ +from typing import List + + +class Transform: + # V3 transform descriptor. + def __init__(self, rotation: List[float] = None, translation: List[float] = None): + """ + Axis-angle rotation vector. + The direction of the vector is the rotation axis. + The magnitude of the vector is rotation angle in radians. + """ + self.rotation = rotation + # Translation vector. + self.translation = translation + + diff --git a/three/MF/V3/Descriptors/VideoFrame.py b/three/MF/V3/Descriptors/VideoFrame.py new file mode 100644 index 0000000..286925c --- /dev/null +++ b/three/MF/V3/Descriptors/VideoFrame.py @@ -0,0 +1,27 @@ +from MF.V3.Descriptors.Calibration import DetectedCard as MF_V3_Descriptors_Calibration_DetectedCard +from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video + + +class VideoFrame: + # Video frame descriptor. + def __init__(self, codec: MF_V3_Settings_Video_Video.Codec, format: MF_V3_Settings_Video_Video.Format, width: int, height: int, step: int, number: int, timestamp: int, duration: int, calibrationCard: MF_V3_Descriptors_Calibration_DetectedCard): + # Video codec. + self.codec = codec + # Pixel format. + self.format = format + # Image width. + self.width = width + # Image height. + self.height = height + # Image row step in bytes. + self.step = step + # Frame number. + self.number = number + # Frame timestamp. + self.timestamp = timestamp + # Frame duration. + self.duration = duration + # Calibration card detection. + self.calibrationCard = calibrationCard + + diff --git a/three/MF/V3/Descriptors/Wifi.py b/three/MF/V3/Descriptors/Wifi.py new file mode 100644 index 0000000..b2fe4b8 --- /dev/null +++ b/three/MF/V3/Descriptors/Wifi.py @@ -0,0 +1,26 @@ +from typing import List + + +class Wifi: + # The wifi descriptor. + class Network: + # The wifi network descriptor. + def __init__(self, ssid: str, isPublic: bool, isActive: bool, password: str = None, quality: int = None): + # The service set identifier. + self.ssid = ssid + # Is the network public? + self.isPublic = isPublic + # Is the network active? + self.isActive = isActive + # The network password. + self.password = password + # Signal quality [0 ; 100]. + self.quality = quality + + def __init__(self, ssid: str, networks: List['Network'] = None): + # The wifi ssid. + self.ssid = ssid + # The list of wifi networks. + self.networks = networks + + diff --git a/three/MF/V3/Descriptors/__init__.py b/three/MF/V3/Descriptors/__init__.py new file mode 100644 index 0000000..0914107 --- /dev/null +++ b/three/MF/V3/Descriptors/__init__.py @@ -0,0 +1,13 @@ +from MF.V3.Descriptors.BoundingBox import * +from MF.V3.Descriptors.Export import * +from MF.V3.Descriptors.Image import * +from MF.V3.Descriptors.Merge import * +from MF.V3.Descriptors.Project import * +from MF.V3.Descriptors.ProjectActions import * +from MF.V3.Descriptors.RemoveVertices import * +from MF.V3.Descriptors.ScanData import * +from MF.V3.Descriptors.Software import * +from MF.V3.Descriptors.System import * +from MF.V3.Descriptors.Transform import * +from MF.V3.Descriptors.VideoFrame import * +from MF.V3.Descriptors.Wifi import * diff --git a/three/MF/V3/Settings/Advanced.py b/three/MF/V3/Settings/Advanced.py new file mode 100644 index 0000000..a54ba9b --- /dev/null +++ b/three/MF/V3/Settings/Advanced.py @@ -0,0 +1,185 @@ +from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from typing import List + + +class Advanced: + # Advanced settings. + class Capture: + # Capture settings. + def __init__(self, horizontalFrequencies: List[int] = None, verticalFrequencies: List[int] = None, use: bool = None): + # Projector sample rate. + self.horizontalFrequencies = horizontalFrequencies + # Image sample rate. + self.verticalFrequencies = verticalFrequencies + # Use the capture settings. + self.use = use + + class Sampling: + # Sampling settings. + def __init__(self, projectorSampleRate: float = None, imageSampleRate: float = None, use: bool = None): + # Projector sample rate. + self.projectorSampleRate = projectorSampleRate + # Image sample rate. + self.imageSampleRate = imageSampleRate + # Use the sampling settings. + self.use = use + + class EdgeDetection: + # Edge detection settings. + def __init__(self, threshold: float = None, laplacianKernelRadius: int = None, gaussianBlurRadius: int = None, gaussianBlurStdDev: float = None, maximumWidthForProcessing: int = None, use: bool = None): + # The edge detection threshold. + self.threshold = threshold + # The Laplacian kernel radius. This must be in the range [1..5]. + self.laplacianKernelRadius = laplacianKernelRadius + """ + Gaussian blur kernel radius. (Optional) To disable, set to 0. + + The phase images can optionally blurred before taking the Laplacian to reduce noise. + However as a result, the detected edges are wider. + """ + self.gaussianBlurRadius = gaussianBlurRadius + """ + Gaussian blur kernel standard deviation. This parameter is ignored if + \p gaussianBlurSize is zero. + """ + self.gaussianBlurStdDev = gaussianBlurStdDev + """ + The maximum image width for processing. (Optional) To disable, set to 0. + + If this value is greater than zero, the phase images are resized to the maximum + width prior to computing the Laplacian and the the detected edges are then upsampled to the + original size. + + This would be done to speed up processing or to detect edges on a larger scale. + """ + self.maximumWidthForProcessing = maximumWidthForProcessing + # Use the edge detection settings. + self.use = use + + class PhaseFilter: + # Phase filter settings. + def __init__(self, kernelRadius: int = None, spatialWeightStdDev: float = None, use: bool = None): + """ + The filter kernel radius. + + A neighboring value must be within this radius to be included in the filter. + If the kernel radius is set to zero, the phase filtering is disabled. + """ + self.kernelRadius = kernelRadius + """ + The standard deviation of the spatial weights. + + The weight of a neighboring value is \f$ exp(-(r/s)^2) \f$ where \f$ r \f$ + is the distance to the central value and \f$ s \f$ is the spatial weight + standard deviation. + + If the spatial weight standard deviation is set to zero, all the spatial + weights are uniformly set to 1. + """ + self.spatialWeightStdDev = spatialWeightStdDev + # Use the phase filter settings. + self.use = use + + class AdaptiveSampling: + """ + Adaptive sampling settings + + Adaptive sampling will downsample points in regions of low detail + and keep points in regions of high detail. + """ + def __init__(self, rate: float, type: MF_V3_Settings_Scan_Scan.Processing.AdaptiveSampling.Type = None, use: bool = None): + # The sample rate [0..1] for the regions of low detail. + self.rate = rate + # Sampling type. + self.type = type + # Use the adaptive sampling settings. + self.use = use + + class PointClipping: + # Point32 clipping settings. + def __init__(self, type: MF_V3_Settings_Scan_Scan.Processing.PointClipping.Type = None, transform: List[float] = None, use: bool = None): + # Point32 clipping type. + self.type = type + # 4x4 transform mapping 3D points to the canonical point32 clipping coordinates. + self.transform = transform + # Use the point32 clipping settings. + self.use = use + + class NormalEstimation: + # Normal estimation settings. + def __init__(self, method: MF_V3_Settings_Scan_Scan.Processing.NormalEstimation.Method = None, maximumNeighbourCount: int = None, maximumNeighbourRadius: float = None, useMaximumNeighbourCount: bool = None, useMaximumNeighbourRadius: bool = None, use: bool = None): + # Normal estimation method. + self.method = method + """ + Maximum number of nearest neighbors used to compute the normal. + This value is only used with the NORMAL_OPEN3D method. + """ + self.maximumNeighbourCount = maximumNeighbourCount + # Maximum radius for a point32 to be considered a neighbour. + self.maximumNeighbourRadius = maximumNeighbourRadius + self.useMaximumNeighbourCount = useMaximumNeighbourCount + self.useMaximumNeighbourRadius = useMaximumNeighbourRadius + # Use the normal estimation settings. + self.use = use + + class OutlierRemoval: + # Radius outlier removal settings. + def __init__(self, neighbourCount: int = None, neighbourRadius: float = None, use: bool = None): + # The minimum number of points within the radius for a point32 to be retained. + self.neighbourCount = neighbourCount + # The neighbour search radius. + self.neighbourRadius = neighbourRadius + # Use the outlier removal settings. + self.use = use + + class Remesh: + # Remesh settings. + def __init__(self, quality: MF_V3_Settings_Quality_Quality = None, voxelSize: float = None, depth: int = None, scale: float = None, linearInterpolation: bool = None, use: bool = None): + # Remesh quality preset. + self.quality = quality + # Voxel size. + self.voxelSize = voxelSize + # Depth. + self.depth = depth + # Scale. + self.scale = scale + # Linear Interpolation. + self.linearInterpolation = linearInterpolation + # Use the remesh settings. + self.use = use + + class Camera: + # Camera settings. + def __init__(self, useContinuousExposureValues: bool = None): + self.useContinuousExposureValues = useContinuousExposureValues + + class Turntable: + # Turntable settings. + def __init__(self, rampAngle: int = None): + # The angle in degrees to slow down the turntable at the end of a rotation. + self.rampAngle = rampAngle + + def __init__(self, capture: 'Capture' = None, sampling: 'Sampling' = None, edgeDetection: 'EdgeDetection' = None, phaseFilter: 'PhaseFilter' = None, adaptiveSampling: 'AdaptiveSampling' = None, normalEstimation: 'NormalEstimation' = None, outlierRemoval: 'OutlierRemoval' = None, remesh: 'Remesh' = None, camera: 'Camera' = None, turntable: 'Turntable' = None): + # Capture settings. + self.capture = capture + # Sampling settings. + self.sampling = sampling + # Edge detection settings. + self.edgeDetection = edgeDetection + # Phase filter settings. + self.phaseFilter = phaseFilter + # Adaptive sampling settings. + self.adaptiveSampling = adaptiveSampling + # Normal estimation settings. + self.normalEstimation = normalEstimation + # Radius outlier removal settings. + self.outlierRemoval = outlierRemoval + # Remesh settings. + self.remesh = remesh + # Camera settings. + self.camera = camera + # Turntable settings. + self.turntable = turntable + + diff --git a/three/MF/V3/Settings/Align.py b/three/MF/V3/Settings/Align.py new file mode 100644 index 0000000..c30616b --- /dev/null +++ b/three/MF/V3/Settings/Align.py @@ -0,0 +1,82 @@ +from enum import Enum +from typing import List + + +class Align: + # Alignment settings. + class Points: + # Point pair alignment settings. + def __init__(self, points: List[float] = None, absoluteError: float = None, relativeError: float = None, useAllPoints: bool = None): + # The set of corresponding point pairs. + self.points = points + # The maximum absolute error for a point pair to be an inlier to the model. + self.absoluteError = absoluteError + # The maximum error relative to the size of the aligned scans for a point pair to be an inlier to the model. + self.relativeError = relativeError + # Ignore alignment errors and use all selected points for alignment. + self.useAllPoints = useAllPoints + + class Ransac: + # Ransac alignment settings. + def __init__(self, downsampleVoxelSize: float = None, maximumFeatureRadius: float = None, maximumFeaturePointCount: int = None, maximumMatchDistance: float = None, minimumMatchSimilarity: float = None, mutualFilter: bool = None): + self.downsampleVoxelSize = downsampleVoxelSize + self.maximumFeatureRadius = maximumFeatureRadius + self.maximumFeaturePointCount = maximumFeaturePointCount + self.maximumMatchDistance = maximumMatchDistance + self.minimumMatchSimilarity = minimumMatchSimilarity + self.mutualFilter = mutualFilter + + class ICP: + # Iterative closest point alignment settings. + def __init__(self, matchDistance: float): + # The maximum distance for two points to be considered a match. + self.matchDistance = matchDistance + + class Rough: + # Rough alignment settings. + # Rough alignment methods. + class Method(Enum): + Empty = "None" # No rough alignment. + FastGlobal = "FastGlobal" # Fast global alignment. + Ransac = "Ransac" # Ransac alignment. + Points = "Points" # Point pair alignment. + + def __init__(self, method: 'Method', ransac: 'Align.Ransac' = None, points: 'Align.Points' = None): + # Rough alignment method. + self.method = method + # FastGlobal fastGlobal; + self.ransac = ransac + # Point pair alignment settings. + self.points = points + + class Fine: + # Fine alignment settings. + # Fine alignment methods. + class Method(Enum): + Empty = "None" # No fine alignment. + ICP = "ICP" # Iterative closest point alignment. + + class Transform: + def __init__(self, rotation: List[float] = None, translation: List[float] = None): + self.rotation = rotation + self.translation = translation + + def __init__(self, method: 'Method', icp: 'Align.ICP' = None, initialTransform: 'Transform' = None): + # Fine alignment method. + self.method = method + # Iterative closest point settings. + self.icp = icp + # The initial transform for fine alignment. + self.initialTransform = initialTransform + + def __init__(self, source: int, target: int, rough: 'Rough' = None, fine: 'Fine' = None): + # Index of the scan or group to align. + self.source = source + # Index of the scan or group to align to. + self.target = target + # Rough alignment settings. + self.rough = rough + # Fine alignment settings. + self.fine = fine + + diff --git a/three/MF/V3/Settings/AutoFocus.py b/three/MF/V3/Settings/AutoFocus.py new file mode 100644 index 0000000..8a5e494 --- /dev/null +++ b/three/MF/V3/Settings/AutoFocus.py @@ -0,0 +1,24 @@ +from MF.V3.Settings.Rectangle import Rectangle as MF_V3_Settings_Rectangle_Rectangle +from typing import List + + +class AutoFocus: + # Auto focus settings. + class Camera: + # Auto focus camera settings. + def __init__(self, index: int, box: MF_V3_Settings_Rectangle_Rectangle = None): + # The index of the camera on which to apply auto focus. + self.index = index + # The image rectangle in video image pixels on which to apply auto focus. + self.box = box + + def __init__(self, applyAll: bool, cameras: List['Camera'] = None): + """ + Apply the final focus value to both cameras. + This setting is ignored if more than one camera is selected. + """ + self.applyAll = applyAll + # The set of cameras on which to apply auto focus. + self.cameras = cameras + + diff --git a/three/MF/V3/Settings/BoundingBox.py b/three/MF/V3/Settings/BoundingBox.py new file mode 100644 index 0000000..3dd48ac --- /dev/null +++ b/three/MF/V3/Settings/BoundingBox.py @@ -0,0 +1,15 @@ +from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection + + +class BoundingBox: + # Bounding box settings. + def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool): + # The scan selection. + self.selection = selection + """ + If `true`, align the bounding box with the world axes. + Otherwise orient the bounding box with the scans. + """ + self.axisAligned = axisAligned + + diff --git a/three/MF/V3/Settings/Camera.py b/three/MF/V3/Settings/Camera.py new file mode 100644 index 0000000..3054771 --- /dev/null +++ b/three/MF/V3/Settings/Camera.py @@ -0,0 +1,20 @@ +from typing import List + + +class Camera: + # Camera settings. + def __init__(self, selection: List[int] = None, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None): + # Camera selection. Default is all cameras. + self.selection = selection + # Auto exposure. + self.autoExposure = autoExposure + # Exposure. + self.exposure = exposure + # Analog gain. + self.analogGain = analogGain + # Digital gain. + self.digitalGain = digitalGain + # Focus value. + self.focus = focus + + diff --git a/three/MF/V3/Settings/Capture.py b/three/MF/V3/Settings/Capture.py new file mode 100644 index 0000000..40834e6 --- /dev/null +++ b/three/MF/V3/Settings/Capture.py @@ -0,0 +1,25 @@ +from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality +from typing import List + + +class Capture: + # Capture settings. + def __init__(self, quality: MF_V3_Settings_Quality_Quality = None, texture: bool = None, calibrationCard: bool = None, horizontalFrequencies: List[int] = None, verticalFrequencies: List[int] = None, blendCount: int = None, horizontalBlendFrequency: int = None, verticalBlendFrequency: int = None): + # Capture quality preset. + self.quality = quality + # Capture texture. + self.texture = texture + # Detect the calibration card. + self.calibrationCard = calibrationCard + # Horizontal pattern frequencies. + self.horizontalFrequencies = horizontalFrequencies + # Vertical pattern frequencies. + self.verticalFrequencies = verticalFrequencies + # The number of capture images blended together for noise reduction. + self.blendCount = blendCount + # The starting horizontal frequency for blending capture images for noise reduction. + self.horizontalBlendFrequency = horizontalBlendFrequency + # The starting vertical frequency for blending capture images for noise reduction. + self.verticalBlendFrequency = verticalBlendFrequency + + diff --git a/three/MF/V3/Settings/CopyGroup.py b/three/MF/V3/Settings/CopyGroup.py new file mode 100644 index 0000000..1e172c9 --- /dev/null +++ b/three/MF/V3/Settings/CopyGroup.py @@ -0,0 +1,25 @@ +from typing import List + + +class CopyGroup: + # Copy scan group settings. + def __init__(self, sourceIndexes: List[int] = None, targetIndex: int = None, childPosition: int = None, nameSuffix: str = None): + # The indexes of the groups to copy. + self.sourceIndexes = sourceIndexes + """ + The index of the group into which the source group are copied. + If unspecified the copied groups are added to the root of the group tree. + """ + self.targetIndex = targetIndex + """ + The position among the target group's children where the copied groups are inserted. + If unspecified the copied groups are appended to the end of the target group's children. + """ + self.childPosition = childPosition + """ + Optional name suffix to append to the copied group names. + If unspecified the names are unchanged. + """ + self.nameSuffix = nameSuffix + + diff --git a/three/MF/V3/Settings/CopyProject.py b/three/MF/V3/Settings/CopyProject.py new file mode 100644 index 0000000..7000d81 --- /dev/null +++ b/three/MF/V3/Settings/CopyProject.py @@ -0,0 +1,9 @@ +class CopyProject: + # Copy project settings. + def __init__(self, index: int, copyName: str = None): + # The index of the project to copy. + self.index = index + # The name of project copy. If unspecified a default copy name is generated. + self.copyName = copyName + + diff --git a/three/MF/V3/Settings/Export.py b/three/MF/V3/Settings/Export.py new file mode 100644 index 0000000..22a82ae --- /dev/null +++ b/three/MF/V3/Settings/Export.py @@ -0,0 +1,29 @@ +from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection +from enum import Enum + + +class Export: + # Export settings. + # Scan export formats. + class Format(Enum): + ply = "ply" # Polygon format. + dae = "dae" # Digital asset exchange format. + fbx = "fbx" # Autodesk format. + glb = "glb" # GL transmission format. + obj = "obj" # Wavefront format. + stl = "stl" # Stereolithography format. + xyz = "xyz" # Chemical format. + + def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: 'Format' = None, scale: float = None): + # The scan selection. + self.selection = selection + # Export textures. + self.texture = texture + # Merge the scans into a single file. + self.merge = merge + # The export format. + self.format = format + # Scale factor of the exported geometry. + self.scale = scale + + diff --git a/three/MF/V3/Settings/Group.py b/three/MF/V3/Settings/Group.py new file mode 100644 index 0000000..ab28619 --- /dev/null +++ b/three/MF/V3/Settings/Group.py @@ -0,0 +1,26 @@ +from typing import List + + +class Group: + # Scan group settings. + def __init__(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None): + # The unique group index that identifies the group within the group tree. + self.index = index + # Group name. + self.name = name + # Color in the renderer. + self.color = color + # Visibility in the renderer. + self.visible = visible + # Collapsed state in the group tree. + self.collapsed = collapsed + """ + Axis-angle rotation vector. + The direction of the vector is the rotation axis. + The magnitude of the vector is rotation angle in radians. + """ + self.rotation = rotation + # Translation vector. + self.translation = translation + + diff --git a/three/MF/V3/Settings/I18n.py b/three/MF/V3/Settings/I18n.py new file mode 100644 index 0000000..b6d2957 --- /dev/null +++ b/three/MF/V3/Settings/I18n.py @@ -0,0 +1,16 @@ +from enum import Enum + + +class I18n: + # I18n language settings. + # Available languages. + class Language(Enum): + en = "en" + fr = "fr" + de = "de" + + def __init__(self, language: 'Language' = None): + # The language setting. Supported languages are ["en", "fr", "de"]. + self.language = language + + diff --git a/three/MF/V3/Settings/Merge.py b/three/MF/V3/Settings/Merge.py new file mode 100644 index 0000000..1772137 --- /dev/null +++ b/three/MF/V3/Settings/Merge.py @@ -0,0 +1,85 @@ +from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality +from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection +from enum import Enum + + +class Merge: + # Scan merge settings. + class Remesh: + # Remesh settings. + # Remesh method. + class Method(Enum): + FlowTriangles = "FlowTriangles" # Flow remesh as triangles. + FlowQuads = "FlowQuads" # Flow remesh as quads. + FlowQuadDominant = "FlowQuadDominant" # Flow remesh as quad-dominant mesh. + PoissonTriangles = "PoissonTriangles" # Poisson remesh as triangles. + + class Flow: + # Flow remesh settings + def __init__(self, scale: float = None, faceCount: int = None, vertexCount: int = None, creaseAngleThreshold: float = None, extrinsicSmoothness: bool = None, alignToBoundaries: bool = None, smoothIterations: int = None, knnPoints: int = None, deterministic: bool = None): + # Output resolution scale. Smaller means more faces. + self.scale = scale + # The approximate number of remeshed faces. + self.faceCount = faceCount + # The approximate number of remeshed vertices. + self.vertexCount = vertexCount + # The crease angle threshold. + self.creaseAngleThreshold = creaseAngleThreshold + # Use extrinsic smoothness. + self.extrinsicSmoothness = extrinsicSmoothness + # Align mesh to boundaries. + self.alignToBoundaries = alignToBoundaries + # The number of smoothing iterations. + self.smoothIterations = smoothIterations + # The number of KNN points (point cloud input only). + self.knnPoints = knnPoints + # Use deterministic (repeatable) remeshing. + self.deterministic = deterministic + + class Poisson: + def __init__(self, voxelSize: float = None, depth: int = None, scale: float = None, linearInterpolation: bool = None): + # Voxel size. + self.voxelSize = voxelSize + # Depth. + self.depth = depth + # Scale. + self.scale = scale + # Linear Interpolation. + self.linearInterpolation = linearInterpolation + + def __init__(self, method: 'Method' = None, quality: MF_V3_Settings_Quality_Quality = None, flow: 'Flow' = None, poisson: 'Poisson' = None, voxelSize: float = None, depth: int = None, scale: float = None, linearInterpolation: bool = None): + # Remesh method. + self.method = method + # Remesh quality. + self.quality = quality + # Flow remesh options (Ignored if method is 'Poison'). + self.flow = flow + # Poisson remesh options (Ignored if method is not 'Poisson'). + self.poisson = poisson + """ Temporary for backwards compatibility + Voxel size.""" + self.voxelSize = voxelSize + # Depth. + self.depth = depth + # Scale. + self.scale = scale + # Linear Interpolation. + self.linearInterpolation = linearInterpolation + + class Simplify: + # Simplify settings. + def __init__(self, triangleCount: int): + # Target triangle count. + self.triangleCount = triangleCount + + def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: 'Remesh' = None, simplify: 'Simplify' = None, texturize: bool = None): + # The scan selection. + self.selection = selection + # Remesh settings. + self.remesh = remesh + # Simplify settings. + self.simplify = simplify + # Apply textures to the merged mesh. + self.texturize = texturize + + diff --git a/three/MF/V3/Settings/NewGroup.py b/three/MF/V3/Settings/NewGroup.py new file mode 100644 index 0000000..f466965 --- /dev/null +++ b/three/MF/V3/Settings/NewGroup.py @@ -0,0 +1,32 @@ +from typing import List + + +class NewGroup: + # Scan group settings. + def __init__(self, parentIndex: int = None, baseName: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None): + """ + The index of the parent group in which the new group is created. + If unspecified the new group is added to the root of the group tree. + """ + self.parentIndex = parentIndex + """ + Group base name. + The new group name will start with the base name followed by a unique index number chosen by the backend. + """ + self.baseName = baseName + # Group color. + self.color = color + # Group visibility. + self.visible = visible + # Collapsed state in the group tree. + self.collapsed = collapsed + """ + Group axis-angle rotation vector. + The direction of the vector is the rotation axis. + The magnitude of the vector is rotation angle in radians. + """ + self.rotation = rotation + # Group translation vector. + self.translation = translation + + diff --git a/three/MF/V3/Settings/Project.py b/three/MF/V3/Settings/Project.py new file mode 100644 index 0000000..9d5f56f --- /dev/null +++ b/three/MF/V3/Settings/Project.py @@ -0,0 +1,10 @@ +class Project: + # Project settings. + def __init__(self, index: int = None, name: str = None): + """ The index identifying which project the settings applies to. + If undefined the current open project is used.""" + self.index = index + # Project name. + self.name = name + + diff --git a/three/MF/V3/Settings/Projector.py b/three/MF/V3/Settings/Projector.py new file mode 100644 index 0000000..1740927 --- /dev/null +++ b/three/MF/V3/Settings/Projector.py @@ -0,0 +1,58 @@ +from MF.V3.Settings.Rectangle import Rectangle as MF_V3_Settings_Rectangle_Rectangle +from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video +from enum import Enum +from typing import List + + +class Projector: + # Projector settings. + # Pattern orientation. + class Orientation(Enum): + Horizontal = "Horizontal" # Horizontal pattern. Image columns are identical. + Vertical = "Vertical" # Vertical pattern. Image rows are identical. + + class Pattern: + # Structured light pattern. + def __init__(self, orientation: 'Projector.Orientation', frequency: int, phase: int): + # Pattern orientation. + self.orientation = orientation + # Pattern frequency index. [0 - 8] + self.frequency = frequency + # Pattern phase. [0 - 2] + self.phase = phase + + class Image: + # Projector image settings + class Source: + # Image source. + def __init__(self, format: MF_V3_Settings_Video_Video.Format, width: int, height: int, step: int, fixAspectRatio: bool): + # Source image format + self.format = format + # Source image width. + self.width = width + # Source image height. + self.height = height + # Source image step in bytes. + self.step = step + # Fix the source aspect ratio to the target rectangle. + self.fixAspectRatio = fixAspectRatio + + def __init__(self, source: 'Source', target: MF_V3_Settings_Rectangle_Rectangle): + # Image source. + self.source = source + # Image target rectangle. + self.target = target + + def __init__(self, on: bool = None, brightness: float = None, pattern: 'Pattern' = None, image: 'Image' = None, color: List[float] = None): + # Projector on/off. + self.on = on + # Projector brightness. + self.brightness = brightness + # Structured light pattern. + self.pattern = pattern + # Image to project + self.image = image + # Solid color + self.color = color + + diff --git a/three/MF/V3/Settings/Quality.py b/three/MF/V3/Settings/Quality.py new file mode 100644 index 0000000..a1d5011 --- /dev/null +++ b/three/MF/V3/Settings/Quality.py @@ -0,0 +1,10 @@ +from enum import Enum + + +# Quality settings. +class Quality(Enum): + Low = "Low" # Low quality. + Medium = "Medium" # Medium quality. + High = "High" # High quality. + + diff --git a/three/MF/V3/Settings/Rectangle.py b/three/MF/V3/Settings/Rectangle.py new file mode 100644 index 0000000..8390e02 --- /dev/null +++ b/three/MF/V3/Settings/Rectangle.py @@ -0,0 +1,13 @@ +class Rectangle: + # Rectangle settings. + def __init__(self, x: int, y: int, width: int, height: int): + # Rectangle x offset. + self.x = x + # Rectangle y offset. + self.y = y + # Rectangle width. + self.width = width + # Rectangle height. + self.height = height + + diff --git a/three/MF/V3/Settings/Remesh.py b/three/MF/V3/Settings/Remesh.py new file mode 100644 index 0000000..832d760 --- /dev/null +++ b/three/MF/V3/Settings/Remesh.py @@ -0,0 +1,36 @@ +from enum import Enum + + +class Remesh: + # Field aligned remesh settings. + # Types of remesh output. + class Type(Enum): + triangle = "triangle" # Triangle mesh output. + quad = "quad" # Quad mesh output. + quadDominant = "quadDominant" # Quad-dominant mesh output. + + def __init__(self, scan: int, type: 'Type' = None, scale: float = None, faceCount: int = None, vertexCount: int = None, creaseAngleThreshold: float = None, extrinsicSmoothness: bool = None, alignToBoundaries: bool = None, smoothIterations: int = None, knnPoints: int = None, deterministic: bool = None): + # The scan index. + self.scan = scan + # The type of output mesh. + self.type = type + # Scale + self.scale = scale + # The approximate number of remeshed faces. + self.faceCount = faceCount + # The approximate number of remeshed vertices. + self.vertexCount = vertexCount + # The crease angle threshold. + self.creaseAngleThreshold = creaseAngleThreshold + # Use extrinsic smoothness. + self.extrinsicSmoothness = extrinsicSmoothness + # Align mesh to boundaries. + self.alignToBoundaries = alignToBoundaries + # The number of smoothing iterations. + self.smoothIterations = smoothIterations + # The number of KNN points (point cloud input only). + self.knnPoints = knnPoints + # Use deterministic (repeatable) remeshing. + self.deterministic = deterministic + + diff --git a/three/MF/V3/Settings/RemoveVertices.py b/three/MF/V3/Settings/RemoveVertices.py new file mode 100644 index 0000000..1e133de --- /dev/null +++ b/three/MF/V3/Settings/RemoveVertices.py @@ -0,0 +1,10 @@ +from typing import List + + +class RemoveVertices: + # Remove vertices. + def __init__(self, scans: List[int] = None): + # The scans indexes for which vertices are removed. + self.scans = scans + + diff --git a/three/MF/V3/Settings/Scan.py b/three/MF/V3/Settings/Scan.py new file mode 100644 index 0000000..7067b3b --- /dev/null +++ b/three/MF/V3/Settings/Scan.py @@ -0,0 +1,157 @@ +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera +from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture +from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector +from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable +from enum import Enum +from typing import List + + +class Scan: + # Scan settings. + class Processing: + # Scan processing settings. + class PhaseEdgeDetection: + """ + Phase edge detection settings. + + Phase edge detection produces a binary mask indicating the edges of a horizontal/vertical pair of phase images. Since flat geometries give a constant phase image gradient, we use the second derivative (Laplacian) of the phase image to detect edges rather than the gradient. + + The edge mask generated by phase edge detection is an input to both phase filtering and adaptive sampling. If neither of these are enabled, the phase edge detection settings have no effect on the output point cloud. + """ + def __init__(self, threshold: float, laplacianKernelRadius: int, gaussianBlurRadius: int, gaussianBlurStdDev: float, maximumWidthForProcessing: int): + # The edge detection threshold. + self.threshold = threshold + # The Laplacian kernel radius. This must be in the range [1..5]. + self.laplacianKernelRadius = laplacianKernelRadius + """ + Gaussian blur kernel radius. (Optional) To disable, set to 0. + The phase images can optionally blurred before taking the Laplacian to reduce noise. + However as a result, the detected edges are wider. + """ + self.gaussianBlurRadius = gaussianBlurRadius + """ + Gaussian blur kernel standard deviation. + This parameter is ignored if `gaussianBlurSize` is zero. + """ + self.gaussianBlurStdDev = gaussianBlurStdDev + """ + The maximum image width for processing. (Optional) To disable, set to 0. + If this value is greater than zero, the phase images are resized to the maximum width prior + to computing the Laplacian and the the detected edges are then upsampled to the original size. + This would be done to speed up processing or to detect edges on a larger scale. + """ + self.maximumWidthForProcessing = maximumWidthForProcessing + + class PhaseFilter: + # Phase filter settings. + def __init__(self, kernelRadius: int, spatialWeightStdDev: float): + """ + The filter kernel radius. + A neighboring value must be within this radius to be included in the filter. + If the kernel radius is set to zero, the phase filtering is disabled. + """ + self.kernelRadius = kernelRadius + """ + The standard deviation of the spatial weights. + The weight of a neighboring value is $\exp(-(r/s)^2)$ where $r$ is the distance + to the central value and $s$ is the spatial weight standard deviation. + If the spatial weight standard deviation is set to zero, all the spatial + weights are uniformly set to 1. + """ + self.spatialWeightStdDev = spatialWeightStdDev + + class AdaptiveSampling: + """ + Adaptive sampling settings + + Adaptive sampling will downsample points in regions of low detail + and keep points in regions of high detail. + """ + class Type(Enum): + NONE = "NONE" # Do not use adaptive sampling. + REGULAR = "REGULAR" # Use a regular sampling mask in regions of low detail. + RANDOM = "RANDOM" # Use a random sampling mask in regions of low detail. + + def __init__(self, type: 'Type', rate: float): + # Sampling type. + self.type = type + # The sample rate [0..1] for the regions of low detail. + self.rate = rate + + class PointClipping: + # Point clipping settings. + # Point clipping type. + class Type(Enum): + OutsideCube = "OutsideCube" # Clip points outside a unit cube. + OutsideCylinder = "OutsideCylinder" # Clip points outside a unit cylinder. + OutsideSphere = "OutsideSphere" # Clip points outside a unit sphere. + InsideCube = "InsideCube" # Clip points inside a unit cube. + InsideCylinder = "InsideCylinder" # Clip points inside a unit cylinder. + InsideSphere = "InsideSphere" # Clip points inside a unit sphere. + + def __init__(self, type: 'Type', transform: List[float] = None): + # Point clipping type. + self.type = type + # 4x4 transform mapping 3D points to the canonical point clipping coordinates. + self.transform = transform + + class NormalEstimation: + # Normal estimation settings. + class Method(Enum): + NORMAL_LLS = "NORMAL_LLS" # Linear least squares method + NORMAL_OPEN3D = "NORMAL_OPEN3D" # Open3D method using KD tree search for nearest neighbors + + def __init__(self, method: 'Method', maximumNeighbourCount: int, maximumNeighbourRadius: float, useMaximumNeighbourCount: bool, useMaximumNeighbourRadius: bool): + # Normal estimation method. + self.method = method + """ + Maximum number of nearest neighbors used to compute the normal. + This value is only used with the NORMAL_OPEN3D method. + """ + self.maximumNeighbourCount = maximumNeighbourCount + # Maximum radius for a point to be considered a neighbour. + self.maximumNeighbourRadius = maximumNeighbourRadius + # Use the maximum neighbour count. + self.useMaximumNeighbourCount = useMaximumNeighbourCount + # Use the maximum neighbour radius. + self.useMaximumNeighbourRadius = useMaximumNeighbourRadius + + class OutlierRemoval: + # Outlier removal settings. + def __init__(self, neighbourCount: int, neighbourRadius: float): + # The minimum number of points within the radius for a point to be retained. + self.neighbourCount = neighbourCount + # The neighbour search radius. + self.neighbourRadius = neighbourRadius + + def __init__(self, projectorSampleRate: float = None, imageSampleRate: float = None, edgeDetection: 'PhaseEdgeDetection' = None, phaseFilter: 'PhaseFilter' = None, adaptiveSampling: 'AdaptiveSampling' = None, pointClipping: List['PointClipping'] = None, normalEstimation: 'NormalEstimation' = None, outlierRemoval: 'OutlierRemoval' = None): + # Projector sample rate. + self.projectorSampleRate = projectorSampleRate + # Image sample rate. + self.imageSampleRate = imageSampleRate + # Phase edge detection settings. + self.edgeDetection = edgeDetection + # Phase filter settings. + self.phaseFilter = phaseFilter + # Adaptive sampling settings. + self.adaptiveSampling = adaptiveSampling + # Point clipping settings. + self.pointClipping = pointClipping + # Normal estimation settings. + self.normalEstimation = normalEstimation + # Outlier removal settings. + self.outlierRemoval = outlierRemoval + + def __init__(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: 'Processing' = None): + # Camera settings. + self.camera = camera + # Projector settings. + self.projector = projector + # Turntable settings. + self.turntable = turntable + # Capture settings. + self.capture = capture + # Processing settings. + self.processing = processing + + diff --git a/three/MF/V3/Settings/ScanData.py b/three/MF/V3/Settings/ScanData.py new file mode 100644 index 0000000..5bc5314 --- /dev/null +++ b/three/MF/V3/Settings/ScanData.py @@ -0,0 +1,40 @@ +from enum import Enum +from typing import List + + +class ScanData: + # Scan data request. + # Scan buffer type. + class Buffer(Enum): + Position = "Position" # Vertex position. + Normal = "Normal" # Vertex normal. + Color = "Color" # Vertex color. + UV = "UV" # Vertex UVs + Triangle = "Triangle" # Triangle index. + Texture = "Texture" # Texture. + All = "All" # All buffer types. + + # Scan metadata type. + class Metadata(Enum): + Mean = "Mean" # The mean (centroid) of the vertex positions. + StdDev = "StdDev" # The standard deviation of the vertex positions. + AxisAlignedBoundingBox = "AxisAlignedBoundingBox" # The axis-aligned bounding box of the vertex positions. + + # The merge processing step. + class MergeStep(Enum): + Combined = "Combined" # The scan meshes are simply combined into a single mesh. + Remeshed = "Remeshed" # The combined mesh is remeshed to give a single geometric surface. + Simplified = "Simplified" # The combined or remeshed mesh is simplified to a reduced number of triangles. + Textured = "Textured" # The merged mesh has been textured. + + def __init__(self, index: int, mergeStep: 'MergeStep' = None, buffers: List['Buffer'] = None, metadata: List['Metadata'] = None): + # Requested index of the scan in the current open project. + self.index = index + # The merge process step if requesting merge data. + self.mergeStep = mergeStep + # Requested scan buffers. + self.buffers = buffers + # Requested scan metadata. + self.metadata = metadata + + diff --git a/three/MF/V3/Settings/ScanSelection.py b/three/MF/V3/Settings/ScanSelection.py new file mode 100644 index 0000000..8c5977d --- /dev/null +++ b/three/MF/V3/Settings/ScanSelection.py @@ -0,0 +1,22 @@ +from enum import Enum +from typing import List + + +class ScanSelection: + # Scan selection. + # Scan selection mode. + class Mode(Enum): + selected = "selected" # Select user-selected groups. + visible = "visible" # Select visible scans. + all = "all" # Select all scans. + + def __init__(self, mode: 'Mode', groups: List[int] = None): + # The scan selection mode. + self.mode = mode + """ + The set of user-selected groups. + These are only used if the selection mode is 'selected'. + """ + self.groups = groups + + diff --git a/three/MF/V3/Settings/Scanner.py b/three/MF/V3/Settings/Scanner.py new file mode 100644 index 0000000..402d3fe --- /dev/null +++ b/three/MF/V3/Settings/Scanner.py @@ -0,0 +1,37 @@ +from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera +from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture +from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n +from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector +from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software +from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style +from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable +from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials +from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer + + +class Scanner: + # Scanner settings. + def __init__(self, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None): + # Advanced settings. + self.advanced = advanced + # Camera settings. + self.camera = camera + # Capture settings. + self.capture = capture + # I18n settings. + self.i18n = i18n + # Projector settings. + self.projector = projector + # Style settings. + self.style = style + # Turntable settings. + self.turntable = turntable + # Tutorials settings. + self.tutorials = tutorials + # Viewer settings. + self.viewer = viewer + # Software update settings. + self.software = software + + diff --git a/three/MF/V3/Settings/Software.py b/three/MF/V3/Settings/Software.py new file mode 100644 index 0000000..1ebb23c --- /dev/null +++ b/three/MF/V3/Settings/Software.py @@ -0,0 +1,9 @@ +class Software: + # Software settings. + def __init__(self, updateMajor: bool = None, updateNightly: bool = None): + # Enable major version updates which can have breaking API changes. + self.updateMajor = updateMajor + # Enable nightly release candidate updates. + self.updateNightly = updateNightly + + diff --git a/three/MF/V3/Settings/Style.py b/three/MF/V3/Settings/Style.py new file mode 100644 index 0000000..1cfdfc3 --- /dev/null +++ b/three/MF/V3/Settings/Style.py @@ -0,0 +1,15 @@ +from enum import Enum + + +class Style: + # Style settings. + # Themes. + class Theme(Enum): + Light = "Light" # Light mode. + Dark = "Dark" # Dark mode. + + def __init__(self, theme: 'Theme' = None): + # Theme setting. + self.theme = theme + + diff --git a/three/MF/V3/Settings/Turntable.py b/three/MF/V3/Settings/Turntable.py new file mode 100644 index 0000000..b3b3063 --- /dev/null +++ b/three/MF/V3/Settings/Turntable.py @@ -0,0 +1,11 @@ +class Turntable: + # Turntable settings. + def __init__(self, scans: int, sweep: int, use: bool = None): + # The number of turntable scans. + self.scans = scans + # Turntable angle sweep in degrees. + self.sweep = sweep + # Use the turntable. + self.use = use + + diff --git a/three/MF/V3/Settings/Tutorials.py b/three/MF/V3/Settings/Tutorials.py new file mode 100644 index 0000000..569d51a --- /dev/null +++ b/three/MF/V3/Settings/Tutorials.py @@ -0,0 +1,18 @@ +from typing import List + + +class Tutorials: + # Tutorials settings. + class Viewed: + # Viewed tutorials. + def __init__(self, pages: List[str] = None): + # Viewed tutorials pages. + self.pages = pages + + def __init__(self, show: bool = None, viewed: 'Viewed' = None): + # Show tutorials. + self.show = show + # Viewed tutorials. + self.viewed = viewed + + diff --git a/three/MF/V3/Settings/Video.py b/three/MF/V3/Settings/Video.py new file mode 100644 index 0000000..8a68ce2 --- /dev/null +++ b/three/MF/V3/Settings/Video.py @@ -0,0 +1,31 @@ +from enum import Enum + + +class Video: + # Video settings. + # Video codecs. + class Codec(Enum): + NoCodec = "NoCodec" # No codec specified. + RAW = "RAW" # Raw encoding. + JPEG = "JPEG" # JPEG encoding. + H264 = "H264" # H264 encoding. + + # Pixel formats. + class Format(Enum): + NoFormat = "NoFormat" # No format specified. + RGB565 = "RGB565" # RGB565 16-bit + RGB888 = "RGB888" # RGB888 24-bit. + BGR888 = "BGR888" # BGR888 24-bit. + YUV420 = "YUV420" # YUV 420 planar. + + def __init__(self, codec: 'Codec', format: 'Format', width: int, height: int): + # Video codec. + self.codec = codec + # Pixel format. + self.format = format + # Image width. + self.width = width + # Image height. + self.height = height + + diff --git a/three/MF/V3/Settings/Viewer.py b/three/MF/V3/Settings/Viewer.py new file mode 100644 index 0000000..f797ad1 --- /dev/null +++ b/three/MF/V3/Settings/Viewer.py @@ -0,0 +1,7 @@ +class Viewer: + # 3D Viewer settings. + def __init__(self, textureOpacity: float = None): + # Texture opacity. + self.textureOpacity = textureOpacity + + diff --git a/three/MF/V3/Settings/Wifi.py b/three/MF/V3/Settings/Wifi.py new file mode 100644 index 0000000..bc7b529 --- /dev/null +++ b/three/MF/V3/Settings/Wifi.py @@ -0,0 +1,9 @@ +class Wifi: + # Wifi connection settings. + def __init__(self, ssid: str, password: str): + # The wifi ssid. + self.ssid = ssid + # The wifi password. + self.password = password + + diff --git a/three/MF/V3/Settings/__init__.py b/three/MF/V3/Settings/__init__.py new file mode 100644 index 0000000..9fadccd --- /dev/null +++ b/three/MF/V3/Settings/__init__.py @@ -0,0 +1,30 @@ +from MF.V3.Settings.Advanced import * +from MF.V3.Settings.Align import * +from MF.V3.Settings.AutoFocus import * +from MF.V3.Settings.BoundingBox import * +from MF.V3.Settings.Camera import * +from MF.V3.Settings.Capture import * +from MF.V3.Settings.CopyGroup import * +from MF.V3.Settings.CopyProject import * +from MF.V3.Settings.Export import * +from MF.V3.Settings.Group import * +from MF.V3.Settings.I18n import * +from MF.V3.Settings.Merge import * +from MF.V3.Settings.NewGroup import * +from MF.V3.Settings.Project import * +from MF.V3.Settings.Projector import * +from MF.V3.Settings.Quality import * +from MF.V3.Settings.Rectangle import * +from MF.V3.Settings.Remesh import * +from MF.V3.Settings.RemoveVertices import * +from MF.V3.Settings.Scan import * +from MF.V3.Settings.ScanData import * +from MF.V3.Settings.ScanSelection import * +from MF.V3.Settings.Scanner import * +from MF.V3.Settings.Software import * +from MF.V3.Settings.Style import * +from MF.V3.Settings.Turntable import * +from MF.V3.Settings.Tutorials import * +from MF.V3.Settings.Video import * +from MF.V3.Settings.Viewer import * +from MF.V3.Settings.Wifi import * diff --git a/three/MF/V3/Task.py b/three/MF/V3/Task.py new file mode 100644 index 0000000..b2dbb98 --- /dev/null +++ b/three/MF/V3/Task.py @@ -0,0 +1,89 @@ +from enum import Enum +from google.protobuf import any_pb2 as _any_pb2 + + +class TaskState(Enum): + Empty = "None" # The task state is not defined. + Sent = "Sent" # The task has been sent by the client. + Received = "Received" # The task has been received by the server. + Started = "Started" # The task started by the server. + Completed = "Completed" # The task is completed by the server. + Cancelled = "Cancelled" # The task has been cancelled by the client. + Failed = "Failed" # The task has failed. A string describing the error is returned with the task. + Dropped = "Dropped" # The task has not been received by the server, or task IDs were sent out of sequence. + Disconnected = "Disconnected" # The client has been disconnected from the server before the task could finish. + + +class Task: + """* + Generic task message for the Three Scanner. + + The task message is the generic message used for requesting a task of the Three Scanner and receiving updates and results. + + Example: Apply camera settings with the "SetCameras" task. + + > Example request: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetCameras" + "Input":{ + "analogGain":256, + "digitalGain":128, + "exposure":18000 + }, + } + } + ``` + + > Example response: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetCameras" + "Input":{ + "analogGain":256, + "digitalGain":512, + "exposure":18000 + }, + "Output":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":512}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "State":"Completed" + } + } + ``` + """ + class Progress: + # V3 Task Progress Descriptor + def __init__(self, current: int, step: str, total: int): + # The current step of the scan. + self.current = current + # The string description of the current step. + self.step = step + # The total steps in the progress. + self.total = total + + def __init__(self, Index: int, Type: str, Input: _any_pb2 = None, Output: _any_pb2 = None, State: 'TaskState' = None, Error: str = None, Progress: _any_pb2 = None): + # A unique identifier generated by the client. This identifier associates all incoming and outgoing task messages with a specific task requested by the client. + self.Index = Index + # The string identifying the task type. See task definitions for the list of valid task strings. + self.Type = Type + # Optional input message. See each task definition for details. + self.Input = Input + # Optional output message. See each task definition for details. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + # A Progress object for tasks that give updates on long running tasks + self.Progress = Progress + + diff --git a/three/MF/V3/Tasks/AddMergeToProject.py b/three/MF/V3/Tasks/AddMergeToProject.py new file mode 100644 index 0000000..45d53ff --- /dev/null +++ b/three/MF/V3/Tasks/AddMergeToProject.py @@ -0,0 +1,66 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class AddMergeToProject: + """* + Add a merged scan to the current project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"AddMergeToProject" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"AddMergeToProject", + "Output":{ + "groups":[ + { + "index":1, + "name":"Scan-1", + "scan": 1, + "color":[0.5, 0.8, 0.3] + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `AddMergeToProject` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "AddMergeToProject" + self.Type = Type + + class Response: + # Server response for the `AddMergeToProject` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "AddMergeToProject" + self.Type = Type + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/Align.py b/three/MF/V3/Tasks/Align.py new file mode 100644 index 0000000..ba8fe37 --- /dev/null +++ b/three/MF/V3/Tasks/Align.py @@ -0,0 +1,77 @@ +from MF.V3.Descriptors.Transform import Transform as MF_V3_Descriptors_Transform_Transform +from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class Align: + """* + Align two scan groups. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Align", + "Input":{ + "source":1, + "target":2, + "rough":{"method": "FastGlobal"}, + "fine":{"method": "ICP"} + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Align", + "Input":{ + "source":1, + "target":2, + "rough":{"method": "FastGlobal"}, + "fine":{"method": "ICP"} + }, + "Output":{ + "rotation":[0.2, 0.4, 0.6], + "translation":[11, -10, 24] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `Align` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Align_Align): + # A unique identifier generated by the client. + self.Index = Index + # "Align" + self.Type = Type + # The align settings. + self.Input = Input + + class Response: + # Server response for the `Align` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Align_Align, Output: MF_V3_Descriptors_Transform_Transform, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "Align" + self.Type = Type + # The requested align settings. + self.Input = Input + # The transform that aligns the source scan group to the target scan group. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/AutoFocus.py b/three/MF/V3/Tasks/AutoFocus.py new file mode 100644 index 0000000..d21722d --- /dev/null +++ b/three/MF/V3/Tasks/AutoFocus.py @@ -0,0 +1,94 @@ +from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera +from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class AutoFocus: + """* + Auto focus one or both cameras. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"AutoFocus", + "Input":{ + "cameras":[{ + "index":1, + "box":{"x":196,"y":130,"width":64,"height":64} + }], + "applyAll":false + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"AutoFocus", + "Input":{ + "cameras":[{ + "index":1, + "box":{"x":196,"y":130,"width":64,"height":64} + }], + "applyAll":false + } + "Output":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "autoExposure":{"default":false,"value":true}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + "focus":{ + "box":{ + "default":[ + {"height":64,"width":64,"x":224,"y":158}, + {"height":64,"width":64,"x":224,"y":158} + ], + "value":[ + {"height":64,"width":64,"x":271,"y":134}, + {"height":64,"width":64,"x":196,"y":130} + ] + }, + "value":{"default":[350,350],"max":1024,"min":0,"value":[396,392]} + } + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `AutoFocus` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_AutoFocus_AutoFocus = None): + # A unique identifier generated by the client. + self.Index = Index + # "AutoFocus" + self.Type = Type + # AutoFocus settings. + self.Input = Input + + class Response: + # Server response for the `AutoFocus` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_AutoFocus_AutoFocus = None, Output: MF_V3_Descriptors_Settings_Camera_Camera = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "AutoFocus" + self.Type = Type + # Requested auto focus settings. + self.Input = Input + # Actual camera settings after auto focusing the camera(s). + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/BoundingBox.py b/three/MF/V3/Tasks/BoundingBox.py new file mode 100644 index 0000000..4a92fd2 --- /dev/null +++ b/three/MF/V3/Tasks/BoundingBox.py @@ -0,0 +1,82 @@ +from MF.V3.Descriptors.BoundingBox import BoundingBox as MF_V3_Descriptors_BoundingBox_BoundingBox +from MF.V3.Settings.BoundingBox import BoundingBox as MF_V3_Settings_BoundingBox_BoundingBox +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class BoundingBox: + """* + Get the bounding box of a set of scan groups. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"BoundingBox", + "Input":{ + "selection":{"mode":"visible"}, + "axisAligned":false + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"BoundingBox", + "Input":{ + "selection":{"mode":"visible"}, + "axisAligned":false + }, + "Output":{ + "center":[11.9,-10.1,94.5], + "rotation":[ + 0.7, -0.7, 0.0, + 0.7, 0.7, 0.0, + 0.0, 0.0, 1.0], + "size":[442.2,253.1,447.1], + "transform":[ + 221, 0.0, 0.0, 11.9, + 0.0, 126, 0.0, -10.1, + 0.0, 0.0, 223, 94.5, + 0.0, 0.0, 0.0, 1.0] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `BoundingBox` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_BoundingBox_BoundingBox): + # A unique identifier generated by the client. + self.Index = Index + # "BoundingBox" + self.Type = Type + # The bounding box settings. + self.Input = Input + + class Response: + # Server response for the `BoundingBox` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_BoundingBox_BoundingBox, Output: MF_V3_Descriptors_BoundingBox_BoundingBox, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "BoundingBox" + self.Type = Type + # The requested bounding box settings. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/CalibrateCameras.py b/three/MF/V3/Tasks/CalibrateCameras.py new file mode 100644 index 0000000..b56dfa7 --- /dev/null +++ b/three/MF/V3/Tasks/CalibrateCameras.py @@ -0,0 +1,58 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class CalibrateCameras: + """* + Calibrate the cameras. + + This task starts the camera calibration capture sequence where the user is guided to place the calibration card with a card outline drawn on the video feed. Once each calibration card pose is captured, the cameras are calibrated and the calibration results are returned as a string. If the cameras cannot be calibrated the task finishes in a `Failed` state. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrateCameras" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrateCameras", + "Output":"Camera calibration results: ...", + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `CalibrateCameras` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "CalibrateCameras" + self.Type = Type + + class Response: + # Server response for the `CalibrateCameras` task. + def __init__(self, Index: int, Type: str, Output: str = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "CalibrateCameras" + self.Type = Type + # Camera calibration results. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/CalibrateTurntable.py b/three/MF/V3/Tasks/CalibrateTurntable.py new file mode 100644 index 0000000..546383c --- /dev/null +++ b/three/MF/V3/Tasks/CalibrateTurntable.py @@ -0,0 +1,61 @@ +from MF.V3.Descriptors.Calibration import Turntable as MF_V3_Descriptors_Calibration_Turntable +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class CalibrateTurntable: + """* + Calibrate the turntable. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrateTurntable" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrateTurntable", + "Output":{ + "date":[2024,4,27,16,57,35], + "quality":"Excellent", + "focus":[300,320] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `CalibrateTurntable` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "CalibrateTurntable" + self.Type = Type + + class Response: + # Server response for the `CalibrateTurntable` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_Turntable = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "CalibrateTurntable" + self.Type = Type + # The Turntable calibration descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/CalibrationCaptureTargets.py b/three/MF/V3/Tasks/CalibrationCaptureTargets.py new file mode 100644 index 0000000..6505b0f --- /dev/null +++ b/three/MF/V3/Tasks/CalibrationCaptureTargets.py @@ -0,0 +1,66 @@ +from MF.V3.Descriptors.Calibration import CaptureTarget as MF_V3_Descriptors_Calibration_CaptureTarget +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class CalibrationCaptureTargets: + """* + Get the camera calibration targets. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrationCaptureTargets" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CalibrationCaptureTargets", + "Output":{[ + { + "camera":0, + "quads":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] + }, + { + "camera":1, + "quads":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] + }, + ]}, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `CalibrationCaptureTargets` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "CalibrationCaptureTargets" + self.Type = Type + + class Response: + # Server response for the `CalibrationCaptureTargets` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_CaptureTarget = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "CalibrationCaptureTargets" + self.Type = Type + # The calibration capture target descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/CameraCalibration.py b/three/MF/V3/Tasks/CameraCalibration.py new file mode 100644 index 0000000..cabf59a --- /dev/null +++ b/three/MF/V3/Tasks/CameraCalibration.py @@ -0,0 +1,60 @@ +from MF.V3.Descriptors.Calibration import Camera as MF_V3_Descriptors_Calibration_Camera +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class CameraCalibration: + """* + Get the camera calibration descriptor. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CameraCalibration" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CameraCalibration", + "Output":{ + "date":[2024,4,27,16,57,35], + "quality":"Excellent" + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `CameraCalibration` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "CameraCalibration" + self.Type = Type + + class Response: + # Server response for the `CameraCalibration` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_Camera = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "CameraCalibration" + self.Type = Type + # The camera calibration descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/CloseProject.py b/three/MF/V3/Tasks/CloseProject.py new file mode 100644 index 0000000..9f17ced --- /dev/null +++ b/three/MF/V3/Tasks/CloseProject.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class CloseProject: + """* + Close the current open project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CloseProject", + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"CloseProject", + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `CloseProject` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "CloseProject" + self.Type = Type + + class Response: + # Server response for the `CloseProject` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "CloseProject" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ConnectWifi.py b/three/MF/V3/Tasks/ConnectWifi.py new file mode 100644 index 0000000..911ef46 --- /dev/null +++ b/three/MF/V3/Tasks/ConnectWifi.py @@ -0,0 +1,67 @@ +from MF.V3.Settings.Wifi import Wifi as MF_V3_Settings_Wifi_Wifi +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ConnectWifi: + """* + Connect to a wifi network. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ConnectWifi", + "Input":{ + "ssid":"Network1" + "password":"password" + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ConnectWifi", + "Input":{ + { + "ssid":"Network1" + "password":"password" + } + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ConnectWifi` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Wifi_Wifi): + # A unique identifier generated by the client. + self.Index = Index + # "ConnectWifi" + self.Type = Type + # Wifi settings. + self.Input = Input + + class Response: + # Server response for the `ConnectWifi` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Wifi_Wifi, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ConnectWifi" + self.Type = Type + # The requested wifi settings. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/DepthMap.py b/three/MF/V3/Tasks/DepthMap.py new file mode 100644 index 0000000..4dfcff3 --- /dev/null +++ b/three/MF/V3/Tasks/DepthMap.py @@ -0,0 +1,141 @@ +from MF.V3.Descriptors.Image import Image as MF_V3_Descriptors_Image_Image +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task +from typing import List + + +class DepthMap: + """* + Capture a new scan. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"DepthMap" + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + }, + } + } + ``` + + > Depth map buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":13128960, + "Descriptor":{ + "cols":2104, + "rows":1560, + "step":8416, + "type":5 + }, + "Task":{ + "Index":1, + "Type":"DepthMap", + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + } + } + } + } + ``` + + > Depth map binary data transfer from server [13128960 bytes]. + + > Texture buffer message from server. + + ```json + { + "Buffer":{ + "Index":1, + "Size":9846720, + "Descriptor":{ + "cols":2104, + "rows":1560, + "step":6312, + "type":16 + }, + "Task":{ + "Index":1, + "Type":"DepthMap", + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + } + } + } + } + ``` + + > Texture binary data transfer from server [9846720 bytes]. + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"DepthMap" + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + }, + "Output":[2500,0,1052,0,2500,780,0,0,1], + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `DepthMap` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None): + # A unique identifier generated by the client. + self.Index = Index + # "DepthMap" + self.Type = Type + # Scan settings. + self.Input = Input + + class Response: + # Server response for the `DepthMap` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None, Output: List[float] = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "DepthMap" + self.Type = Type + # Requested scan settings. + self.Input = Input + # The 9 values of the camera matrix corresponding to the depth map (row-major). + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `DepthMap` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: MF_V3_Descriptors_Image_Image): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested DepthMap task. + self.Task = Task + # The image descriptor. + self.Descriptor = Descriptor + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/DetectCalibrationCard.py b/three/MF/V3/Tasks/DetectCalibrationCard.py new file mode 100644 index 0000000..1127f4f --- /dev/null +++ b/three/MF/V3/Tasks/DetectCalibrationCard.py @@ -0,0 +1,65 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class DetectCalibrationCard: + """* + Detect the calibration card on one or both cameras. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"DetectCalibrationCard", + "Input":3 + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Input":3, + "Type":"DetectCalibrationCard", + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `DetectCalibrationCard` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "DetectCalibrationCard" + self.Type = Type + """ + Flag specifying on which camera(s) to detect the calibration card. + [0: neither camera (disable), 1: left camera, 2: right camera, 3: both cameras] + """ + self.Input = Input + + class Response: + # Server response for the `DetectCalibrationCard` task. + def __init__(self, Index: int, Type: str, Input: int, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "DetectCalibrationCard" + self.Type = Type + """ + Flag sent in the request specifying on which camera(s) to detect the calibration card. + [0: neither camera (disable), 1: left camera, 2: right camera, 3: both cameras] + """ + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/DownloadProject.py b/three/MF/V3/Tasks/DownloadProject.py new file mode 100644 index 0000000..eb34bd1 --- /dev/null +++ b/three/MF/V3/Tasks/DownloadProject.py @@ -0,0 +1,89 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class DownloadProject: + """* + Download a project from the scanner. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"DownloadProject", + "Input":5 + } + } + ``` + + > Buffer message from server. + + ```json + { + "Buffer":{ + "Descriptor":"Project-5.zip", + "Index":0, + "Size":15682096, + "Task":{ + "Index":1, + "Type":"DownloadProject", + "Input":5 + } + } + } + ``` + + > Binary data transfer from server: The project zip file [15682096 bytes]. + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"DownloadProject" + "Input":5, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `DownloadProject` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "DownloadProject" + self.Type = Type + # Index of the project to download. + self.Input = Input + + class Response: + # Server response for the `DownloadProject` task. + def __init__(self, Index: int, Type: str, Input: int, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "DownloadProject" + self.Type = Type + # Requested index of the project to download. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `DownloadProject` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: str): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested DownloadProject task. + self.Task = Task + # The downloaded project filename. + self.Descriptor = Descriptor + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/Export.py b/three/MF/V3/Tasks/Export.py new file mode 100644 index 0000000..36209cc --- /dev/null +++ b/three/MF/V3/Tasks/Export.py @@ -0,0 +1,103 @@ +from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class Export: + """* + Export a group of scans. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Export", + "Input":{ + "selection":{"mode":"visible"}, + "format":"obj", + "texture":true, + "merge":false + } + } + } + ``` + + > Export file buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":8413737, + "Task":{ + "Index":1, + "Type":"Export", + "Input":{ + "selection":{"mode":"visible"}, + "format":"obj", + "texture":true, + "merge":false + } + } + } + } + ``` + + > Export file binary data transfer from server [8413737 bytes]. + + > Response from server: + + ```json + { + "Task":{ + "Index":1, + "Type":"Export" + "Input":{ + "selection":{"mode":"visible"}, + "format":"obj", + "texture":true, + "merge":false + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `Export` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export): + # A unique identifier generated by the client. + self.Index = Index + # "Export" + self.Type = Type + # Export settings. + self.Input = Input + + class Response: + # Server response for the `Export` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "Export" + self.Type = Type + # Requested export settings. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `Export` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested Export task. + self.Task = Task + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ExportLogs.py b/three/MF/V3/Tasks/ExportLogs.py new file mode 100644 index 0000000..bb933f6 --- /dev/null +++ b/three/MF/V3/Tasks/ExportLogs.py @@ -0,0 +1,87 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class ExportLogs: + """* + Export scanner logs. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ExportLogs", + "Input":true + } + } + ``` + + > Export file buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":41337, + "Task":{ + "Index":1, + "Type":"ExportLogs", + "Input":true + } + } + } + ``` + + > Export file binary data transfer from server [41337 bytes]. + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ExportLogs" + "Input":true, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ExportLogs` task. + def __init__(self, Index: int, Type: str, Input: bool = None): + # A unique identifier generated by the client. + self.Index = Index + # "ExportLogs" + self.Type = Type + # Export log images. If unspecified, log images are not exported. + self.Input = Input + + class Response: + # Server response for the `ExportLogs` task. + def __init__(self, Index: int, Type: str, Input: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ExportLogs" + self.Type = Type + # Requested export log images. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `ExportLogs` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested ExportLogs task. + self.Task = Task + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ExportMerge.py b/three/MF/V3/Tasks/ExportMerge.py new file mode 100644 index 0000000..78a1e45 --- /dev/null +++ b/three/MF/V3/Tasks/ExportMerge.py @@ -0,0 +1,97 @@ +from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class ExportMerge: + """* + Export a merged scan. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ExportMerge", + "Input":{ + "format":"obj", + "texture":true + } + } + } + ``` + + > Export file buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":8413737, + "Task":{ + "Index":1, + "Type":"ExportMerge", + "Input":{ + "format":"obj", + "texture":true + } + } + } + } + ``` + + > Export file binary data transfer from server [8413737 bytes]. + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ExportMerge" + "Input":{ + "format":"obj", + "texture":true + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ExportMerge` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export): + # A unique identifier generated by the client. + self.Index = Index + # "ExportMerge" + self.Type = Type + # Export settings. + self.Input = Input + + class Response: + # Server response for the `ExportMerge` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ExportMerge" + self.Type = Type + # Requested export settings. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `ExportMerge` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested ExportMerge task. + self.Task = Task + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/FlattenGroup.py b/three/MF/V3/Tasks/FlattenGroup.py new file mode 100644 index 0000000..c772c6a --- /dev/null +++ b/three/MF/V3/Tasks/FlattenGroup.py @@ -0,0 +1,72 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class FlattenGroup: + """* + Flatten a scan group such that it only consists of single scans. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"FlattenGroup", + "Input":0 + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"FlattenGroup", + "Input":0, + "Output":{ + "groups":[{ + "index":2, + "name":"Group 2", + "groups":[{ + "index":1, + "name":"Group 1" + }] + }], + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `FlattenGroup` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "FlattenGroup" + self.Type = Type + # The index of the group to flatten. + self.Input = Input + + class Response: + # Server response for the `FlattenGroup` task. + def __init__(self, Index: int, Type: str, Input: int, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "FlattenGroup" + self.Type = Type + # The requested index of the group to flatten. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ForgetWifi.py b/three/MF/V3/Tasks/ForgetWifi.py new file mode 100644 index 0000000..7b192ed --- /dev/null +++ b/three/MF/V3/Tasks/ForgetWifi.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ForgetWifi: + """* + Forget all wifi connections. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ForgetWifi" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ForgetWifi" + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ForgetWifi` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ForgetWifi" + self.Type = Type + + class Response: + # Server response for the `ForgetWifi` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ForgetWifi" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/HasCameras.py b/three/MF/V3/Tasks/HasCameras.py new file mode 100644 index 0000000..0bf9c8d --- /dev/null +++ b/three/MF/V3/Tasks/HasCameras.py @@ -0,0 +1,56 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class HasCameras: + """* + Check if the scanner has working cameras. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasCameras" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasCameras", + "Output":true, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `HasCameras` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "HasCameras" + self.Type = Type + + class Response: + # Server response for the `HasCameras` task. + def __init__(self, Index: int, Type: str, Output: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "HasCameras" + self.Type = Type + # The working state of the cameras. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/HasProjector.py b/three/MF/V3/Tasks/HasProjector.py new file mode 100644 index 0000000..9b40f11 --- /dev/null +++ b/three/MF/V3/Tasks/HasProjector.py @@ -0,0 +1,56 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class HasProjector: + """* + Check if the scanner has a working projector. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasProjector" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasProjector", + "Output":true, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `HasProjector` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "HasProjector" + self.Type = Type + + class Response: + # Server response for the `HasProjector` task. + def __init__(self, Index: int, Type: str, Output: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "HasProjector" + self.Type = Type + # The working state of the projector. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/HasTurntable.py b/three/MF/V3/Tasks/HasTurntable.py new file mode 100644 index 0000000..d56fc1a --- /dev/null +++ b/three/MF/V3/Tasks/HasTurntable.py @@ -0,0 +1,56 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class HasTurntable: + """* + Check if the scanner is connected to a working turntable. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasTurntable" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"HasTurntable", + "Output":true, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `HasTurntable` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "HasTurntable" + self.Type = Type + + class Response: + # Server response for the `HasTurntable` task. + def __init__(self, Index: int, Type: str, Output: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "HasTurntable" + self.Type = Type + # The working start of the connected turntable. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ListExportFormats.py b/three/MF/V3/Tasks/ListExportFormats.py new file mode 100644 index 0000000..326b812 --- /dev/null +++ b/three/MF/V3/Tasks/ListExportFormats.py @@ -0,0 +1,86 @@ +from MF.V3.Descriptors.Export import Export as MF_V3_Descriptors_Export_Export +from MF.V3.Task import TaskState as MF_V3_Task_TaskState +from typing import List + + +class ListExportFormats: + """* + List all export formats and the geometry elements they support. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListExportFormats" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListExportFormats", + "Output":{[ + { + "format": "ply", + "colors": true, + "description": "Polygon format", + "extension": ".ply", + "faces": ["Point","Triangle","Quad"], + "normals": true, + "textures": "Single" + }, + { + "format": "obj", + "colors": true, + "description": "Wavefront format", + "extension": ".obj", + "faces": ["Point","Triangle","Quad"], + "normals": true, + "textures": "Multiple" + }, + { + "format": "stl", + "colors": false, + "description": "Stereolithography format", + "extension": ".stl", + "faces": ["Point","Triangle"], + "normals": true, + "textures": "None" + } + ]}, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListExportFormats` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListExportFormats" + self.Type = Type + + class Response: + # Server response for the `ListExportFormats` task. + def __init__(self, Index: int, Type: str, Output: List[MF_V3_Descriptors_Export_Export] = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListExportFormats" + self.Type = Type + # The list of export format descriptors. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ListGroups.py b/three/MF/V3/Tasks/ListGroups.py new file mode 100644 index 0000000..10ba504 --- /dev/null +++ b/three/MF/V3/Tasks/ListGroups.py @@ -0,0 +1,85 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ListGroups: + """* + List the scan groups in the current open project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListGroups" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListGroups", + "Output":{ + "groups":[ + { + "index":1, + "scan":1, + "name":"Scan-1", + "color":[0.75,0.5,0.2,1.0], + "rotation":[0.03,0.1,-0.01], + "translation":[-101,67,-561], + "visible":true + }, + { + "index":2, + "scan":2, + "name":"Scan-2", + "color":[0.7,0.9,0.6,1.0], + "rotation":[0.1,0.2,0.5], + "translation":[-90,64,-553], + "visible":true + }, + { + "index":3, + "scan":3, + "name":"Scan-3", + "color":[0.6,0.8,0.9,1.0], + "visible":true + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListGroups` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListGroups" + self.Type = Type + + class Response: + # Server response for the `ListGroups` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListGroups" + self.Type = Type + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ListNetworkInterfaces.py b/three/MF/V3/Tasks/ListNetworkInterfaces.py new file mode 100644 index 0000000..763cb9d --- /dev/null +++ b/three/MF/V3/Tasks/ListNetworkInterfaces.py @@ -0,0 +1,61 @@ +from MF.V3.Descriptors.Network import Interface as MF_V3_Descriptors_Network_Interface +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ListNetworkInterfaces: + """* + List network interfaces. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListNetworkInterfaces" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListNetworkInterfaces", + "Output":[ + {"ip":"192.168.1.234","name":"eth0","ssid":""}, + {"ip":"127.0.0.1","name":"lo","ssid":""} + {"ip":"192.168.2.345","name":"wlan0","ssid":"Network1"} + ], + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListNetworkInterfaces` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListNetworkInterfaces" + self.Type = Type + + class Response: + # Server response for the `ListNetworkInterfaces` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Network_Interface = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListNetworkInterfaces" + self.Type = Type + # Network interface descriptors. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ListProjects.py b/three/MF/V3/Tasks/ListProjects.py new file mode 100644 index 0000000..6216681 --- /dev/null +++ b/three/MF/V3/Tasks/ListProjects.py @@ -0,0 +1,61 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ListProjects: + """* + List all projects. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListProjects" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListProjects", + "Output":[ + {"index":1,"modified":[2024,5,12,11,23,17],"name":"Project 1","size":35409834}, + {"index":2,"modified":[2024,5,12,11,2,37],"name":"Project 2","size":175025367}, + {"index":3,"modified":[2024,5,6,17,15,53],"name":"Project 3","size":24314083} + ], + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListProjects` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListProjects" + self.Type = Type + + class Response: + # Server response for the `ListProjects` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Brief = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListProjects" + self.Type = Type + # Brief project descriptors. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ListScans.py b/three/MF/V3/Tasks/ListScans.py new file mode 100644 index 0000000..8926274 --- /dev/null +++ b/three/MF/V3/Tasks/ListScans.py @@ -0,0 +1,77 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState +from typing import List + + +class ListScans: + """* + List the scans in the current open project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListScans" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListScans", + "Output":{[ + { + "color":[0.8,0.5,0.6,1.0], + "index":1, + "name":"Scan-1", + "scan":1, + "rotation":[0.2,0.8,-0.1], + "translation":[-275,-32,-134], + "visible":true + }, + { + "color":[0.5,0.7,0.2,1.0], + "index":2, + "name":"Scan-2", + "scan":2, + "rotation":[0.7,-0.5,0.3], + "translation":[75,-62,38], + "visible":true + }, + ]}, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListScans` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListScans" + self.Type = Type + + class Response: + # Server response for the `ListScans` task. + def __init__(self, Index: int, Type: str, Output: List[MF_V3_Descriptors_Project_Project.Group] = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListScans" + self.Type = Type + # The list of scans in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ListSettings.py b/three/MF/V3/Tasks/ListSettings.py new file mode 100644 index 0000000..238935c --- /dev/null +++ b/three/MF/V3/Tasks/ListSettings.py @@ -0,0 +1,86 @@ +from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ListSettings: + """* + Get scanner settings. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListSettings" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListSettings", + "Output":{ + "camera":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "autoExposure":{"default":false,"value":false}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "projector":{ + "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, + "on":{"default":false,"value":true} + }, + "turntable":{ + "scans":{"default":8,"max":24,"min":1,"value":3}, + "sweep":{"default":360,"max":360,"min":5,"value":90}, + "use":{"default":true,"value":true} + }, + "capture":{ + "quality":{"default":"Medium","value":"Medium"}, + "texture":{"default":true,"value":true} + }, + "i18n":{ + "language":{"default":"en","value":"en"} + }, + "style":{ + "theme":{"default":"Dark","value":"Dark"} + }, + "viewer":{ + "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} + } + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListSettings` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListSettings" + self.Type = Type + + class Response: + # Server response for the `ListSettings` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListSettings" + self.Type = Type + # The scanner settings descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ListWifi.py b/three/MF/V3/Tasks/ListWifi.py new file mode 100644 index 0000000..223010e --- /dev/null +++ b/three/MF/V3/Tasks/ListWifi.py @@ -0,0 +1,64 @@ +from MF.V3.Descriptors.Wifi import Wifi as MF_V3_Descriptors_Wifi_Wifi +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class ListWifi: + """* + List available wifi networks. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListWifi" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ListWifi", + "Output":{ + "networks":[ + {"ssid":"Network1","isActive":true,"isPublic":false,"quality":90}, + {"ssid":"Network2","isActive":true,"isPublic":true,"quality":50}, + {"ssid":"Network3","isActive":true,"isPublic":true,"quality":75} + ], + "ssid":"Network1" + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ListWifi` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "ListWifi" + self.Type = Type + + class Response: + # Server response for the `ListWifi` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Wifi_Wifi = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ListWifi" + self.Type = Type + # The wifi descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/Merge.py b/three/MF/V3/Tasks/Merge.py new file mode 100644 index 0000000..70ab574 --- /dev/null +++ b/three/MF/V3/Tasks/Merge.py @@ -0,0 +1,104 @@ +from MF.V3.Descriptors.Merge import Merge as MF_V3_Descriptors_Merge_Merge +from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class Merge: + """* + Merge two or more scan groups. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Merge", + "Input":{ + "selection":{"mode":"visible"}, + "remesh":{ + "method": "FlowTriangles", + "quality": "Medium" + }, + "simplify":{"triangleCount": 20000 } + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Merge", + "Input":{ + "selection":{"mode":"visible"}, + "remesh":{ + "method": "FlowTriangles", + "quality": "Medium" + }, + "simplify":{"triangleCount": 20000 } + }, + "Output":{ + "meshes":[ + { + "name":"Combined", + "positions":237757, + "normals":237757, + "triangles":459622, + "size":11221632 + }, + { + "name":"Remeshed", + "positions":34311, + "normals":0, + "triangles":29738, + "size":945540 + }, + { + "name":"Simplified", + "positions":32415, + "normals":0, + "triangles":20000, + "size":628980 + } + ], + "scans":3, + "textures":3 + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `Merge` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Merge_Merge): + # A unique identifier generated by the client. + self.Index = Index + # "Merge" + self.Type = Type + # The merge settings. + self.Input = Input + + class Response: + # Server response for the `Merge` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Merge_Merge, Output: MF_V3_Descriptors_Merge_Merge, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "Merge" + self.Type = Type + # The requested merge settings. + self.Input = Input + # The merge descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/MergeData.py b/three/MF/V3/Tasks/MergeData.py new file mode 100644 index 0000000..b9c0d68 --- /dev/null +++ b/three/MF/V3/Tasks/MergeData.py @@ -0,0 +1,239 @@ +from MF.V3.Descriptors.ScanData import ScanData as MF_V3_Descriptors_ScanData_ScanData +from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class MergeData: + """* + Download the raw scan data for the current merge process. + + > Request example: + + ``` + { + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":-1, + "buffers":["All"] + } + } + } + ``` + + > Vertex position buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":1558188, + "Descriptor":{ + "components":[{ + "type":"Position" + "size":3, + "offset":0, + "normalized":false, + }], + "stride":3 + }, + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex position binary data transfer from server [1558188 bytes]. + + > Vertex normal buffer message from server. + + ```json + { + "Buffer":{ + "Index":1, + "Size":1558188, + "Descriptor":{ + "components":[{ + "type":"Normal" + "size":3, + "offset":0, + "normalized":false, + }], + "stride":3 + }, + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex normal binary data transfer from server [1558188 bytes]. + + > Vertex texture coordinate buffer message from server. + + ```json + { + "Buffer":{ + "Index":2, + "Size":1038792, + "Descriptor":{ + "components":[{ + "type":"UV" + "size":2, + "offset":0, + "normalized":false, + }], + "stride":2 + }, + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex texture coordinate binary data transfer from server [1038792 bytes]. + + > Texture image buffer message from server. + + ```json + { + "Buffer":{ + "Index":3, + "Size":3504494, + "Descriptor":{ + "components":[{ + "type":"Texture" + "size":0, + "offset":0, + "normalized":false, + }], + "stride":0 + }, + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Texture binary data transfer from server [3504494 bytes]. + + > Triangle index buffer message from server. + + ```json + { + "Buffer":{ + "Index":4, + "Size":1996356, + "Descriptor":{ + "components":[{ + "type":"Triangle" + "size":1, + "offset":0, + "normalized":false, + }], + "stride":1 + }, + "Task":{ + "Index":1, + "Type":"MergeData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Triangle index binary data transfer from server [1996356 bytes]. + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"MergeData" + "Input":{"index":-1,"buffers":["All"]}, + "Output":{ + "buffers":[ + {"components":[{"normalized":false,"offset":0,"size":3,"type":"Position"}],"stride":3}, + {"components":[{"normalized":false,"offset":0,"size":3,"type":"Normal"}],"stride":3}, + {"components":[{"normalized":false,"offset":0,"size":2,"type":"UV"}],"stride":2}, + {"components":[{"normalized":false,"offset":0,"size":0,"type":"Texture"}],"stride":0}, + {"components":[{"normalized":false,"offset":0,"size":1,"type":"Triangle"}],"stride":1} + ], + "index":1, + "name":"Scan-1" + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `MergeData` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData): + # A unique identifier generated by the client. + self.Index = Index + # "MergeData" + self.Type = Type + # Requested scan data. + self.Input = Input + + class Response: + # Server response for the `MergeData` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData, Output: MF_V3_Descriptors_ScanData_ScanData, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "MergeData" + self.Type = Type + # The scan data requested by the client. + self.Input = Input + # The scan data sent from the server. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `MergeData` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: MF_V3_Descriptors_ScanData_ScanData.Buffer): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested MergeData task. + self.Task = Task + # The scan data buffer descriptor. + self.Descriptor = Descriptor + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/MoveGroup.py b/three/MF/V3/Tasks/MoveGroup.py new file mode 100644 index 0000000..ba5d1aa --- /dev/null +++ b/three/MF/V3/Tasks/MoveGroup.py @@ -0,0 +1,79 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState +from typing import List + + +class MoveGroup: + """* + Move a scan group. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"MoveGroup", + "Input":[1,2,0] + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"MoveGroup", + "Input":[1,2,0], + "Output":{ + "groups":[{ + "index":2, + "name":"Group 2", + "groups":[{ + "index":1, + "name":"Group 1" + }] + }], + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `MoveGroup` task. + def __init__(self, Index: int, Type: str, Input: List[int] = None): + # A unique identifier generated by the client. + self.Index = Index + # "MoveGroup" + self.Type = Type + """ + The requested source and destination move indices. + An Array of group indexes where + 1. The first is the index of the _source group_: the group to be moved. + 2. The second is the index of the _parent group_: the group into which the source group is moved. + 3. (Optional) The third is the zero-based order in which the source group is placed the other children of the parent group. Use `0` to insert the source group at the beginning of the parent group's children. If omitted, the source group is inserted at the end of the parent group's children. + """ + self.Input = Input + + class Response: + # Server response for the `MoveGroup` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, Input: List[int] = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "MoveGroup" + self.Type = Type + # The root scan group in the current open project. + self.Output = Output + # The requested source and destination move indices. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/NewGroup.py b/three/MF/V3/Tasks/NewGroup.py new file mode 100644 index 0000000..93db660 --- /dev/null +++ b/three/MF/V3/Tasks/NewGroup.py @@ -0,0 +1,77 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.NewGroup import NewGroup as MF_V3_Settings_NewGroup_NewGroup +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class NewGroup: + """* + Create a new scan group. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewGroup", + "Input":{ + "parentIndex":0, + "baseName":"Group" + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewGroup", + "Input":{ + "parentIndex":0, + "baseName":"Group" + }, + "Output":{ + "groups":[ + { + "index":1, + "name":"Group 1" + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `NewGroup` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_NewGroup_NewGroup = None): + # A unique identifier generated by the client. + self.Index = Index + # "NewGroup" + self.Type = Type + # The requested new group settings. + self.Input = Input + + class Response: + # Server response for the `NewGroup` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, Input: MF_V3_Settings_NewGroup_NewGroup = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "NewGroup" + self.Type = Type + # The root scan group in the current open project. + self.Output = Output + # The requested new group settings. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/NewProject.py b/three/MF/V3/Tasks/NewProject.py new file mode 100644 index 0000000..28ebce7 --- /dev/null +++ b/three/MF/V3/Tasks/NewProject.py @@ -0,0 +1,69 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class NewProject: + """* + Create a new project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewProject", + "Input":"New Project Name" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewProject", + "Input":{ + "name":"New Project Name" + }, + "Output":{ + "index":5, + "name":"New Project Name" + } + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `NewProject` task. + def __init__(self, Index: int, Type: str, Input: str = None): + # A unique identifier generated by the client. + self.Index = Index + # "NewProject" + self.Type = Type + # Optional new project name. + self.Input = Input + + class Response: + # Server response for the `NewProject` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Project_Project = None, Output: MF_V3_Descriptors_Project_Project = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "NewProject" + self.Type = Type + # Requested new project name. + self.Input = Input + # The new project descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/NewScan.py b/three/MF/V3/Tasks/NewScan.py new file mode 100644 index 0000000..2107534 --- /dev/null +++ b/three/MF/V3/Tasks/NewScan.py @@ -0,0 +1,82 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class NewScan: + """* + Capture a new scan. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewScan" + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + }, + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"NewScan" + "Input":{ + "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, + "capture":{"quality":"Medium","texture":true}, + "projector":{"brightness":0.8} + }, + "Output":{ + "groups":[{ + "color":[0.8,0.5,0.6,1.0], + "index":1, + "name":"Scan-1", + "scan":1, + "rotation":[0.2,0.8,-0.1], + "translation":[-275,-32,-134], + "visible":true + }], + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `NewScan` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None): + # A unique identifier generated by the client. + self.Index = Index + # "NewScan" + self.Type = Type + # Scan settings. + self.Input = Input + + class Response: + # Server response for the `NewScan` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None, Output: MF_V3_Descriptors_Project_Project.Group = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "NewScan" + self.Type = Type + # Requested scan settings. + self.Input = Input + # Project group descriptor with the updated list of scans. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/OpenProject.py b/three/MF/V3/Tasks/OpenProject.py new file mode 100644 index 0000000..06c6fa2 --- /dev/null +++ b/three/MF/V3/Tasks/OpenProject.py @@ -0,0 +1,66 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class OpenProject: + """* + Create a new project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"OpenProject", + "Input":5 + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"OpenProject", + "Input":5, + "Output":{ + "index":5, + "name":"Project 5" + } + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `OpenProject` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "OpenProject" + self.Type = Type + # The index of the project to open. Project indices can be obtained from the `ListProjects` task. + self.Input = Input + + class Response: + # Server response for the `OpenProject` task. + def __init__(self, Index: int, Type: str, Input: int, Output: MF_V3_Descriptors_Project_Project = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "OpenProject" + self.Type = Type + # The index of the project requested to open. + self.Input = Input + # The open project descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/PopSettings.py b/three/MF/V3/Tasks/PopSettings.py new file mode 100644 index 0000000..80916e5 --- /dev/null +++ b/three/MF/V3/Tasks/PopSettings.py @@ -0,0 +1,92 @@ +from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class PopSettings: + """* + Pop and restore scanner settings from the stack and optionally apply the popped settings. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"PopSettings", + "Input":true + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"PopSettings", + "Input":true, + "Output":{ + "camera":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "autoExposure":{"default":false,"value":false}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "projector":{ + "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, + "on":{"default":false,"value":true} + }, + "turntable":{ + "scans":{"default":8,"max":24,"min":1,"value":3}, + "sweep":{"default":360,"max":360,"min":5,"value":90}, + "use":{"default":true,"value":true} + }, + "capture":{ + "quality":{"default":"Medium","value":"Medium"}, + "texture":{"default":true,"value":true} + }, + "i18n":{ + "language":{"default":"en","value":"en"} + }, + "style":{ + "theme":{"default":"Dark","value":"Dark"} + }, + "viewer":{ + "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} + } + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `PopSettings` task. + def __init__(self, Index: int, Type: str, Input: bool = None): + # A unique identifier generated by the client. + self.Index = Index + # "PopSettings" + self.Type = Type + # Apply the popped settings. If unspecified popped settings are not applied. + self.Input = Input + + class Response: + # Server response for the `PopSettings` task. + def __init__(self, Index: int, Type: str, Input: bool = None, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "PopSettings" + self.Type = Type + # Request to apply the popped settings. + self.Input = Input + # The scanner settings descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/PushSettings.py b/three/MF/V3/Tasks/PushSettings.py new file mode 100644 index 0000000..feaf6b0 --- /dev/null +++ b/three/MF/V3/Tasks/PushSettings.py @@ -0,0 +1,86 @@ +from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class PushSettings: + """* + Push the current scanner settings to a stack so they can be restored with PopSettings. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"PushSettings" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"PushSettings", + "Output":{ + "camera":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "autoExposure":{"default":false,"value":false}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "projector":{ + "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, + "on":{"default":false,"value":true} + }, + "turntable":{ + "scans":{"default":8,"max":24,"min":1,"value":3}, + "sweep":{"default":360,"max":360,"min":5,"value":90}, + "use":{"default":true,"value":true} + }, + "capture":{ + "quality":{"default":"Medium","value":"Medium"}, + "texture":{"default":true,"value":true} + }, + "i18n":{ + "language":{"default":"en","value":"en"} + }, + "style":{ + "theme":{"default":"Dark","value":"Dark"} + }, + "viewer":{ + "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} + } + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `PushSettings` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "PushSettings" + self.Type = Type + + class Response: + # Server response for the `PushSettings` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "PushSettings" + self.Type = Type + # The scanner settings descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/Reboot.py b/three/MF/V3/Tasks/Reboot.py new file mode 100644 index 0000000..c954807 --- /dev/null +++ b/three/MF/V3/Tasks/Reboot.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class Reboot: + """* + Reboot the scanner. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Reboot" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Reboot" + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `Reboot` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "Reboot" + self.Type = Type + + class Response: + # Server response for the `Reboot` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "Reboot" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/RemoveGroups.py b/three/MF/V3/Tasks/RemoveGroups.py new file mode 100644 index 0000000..cc0cbd3 --- /dev/null +++ b/three/MF/V3/Tasks/RemoveGroups.py @@ -0,0 +1,64 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState +from typing import List + + +class RemoveGroups: + """* + Remove selected scan groups. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RemoveGroups", + "Input":[1,2] + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RemoveGroups", + "Input":[1,2], + "Output":{"groups":[]}, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `RemoveGroups` task. + def __init__(self, Index: int, Type: str, Input: List[int] = None): + # A unique identifier generated by the client. + self.Index = Index + # "RemoveGroups" + self.Type = Type + # The list of indices of the scan groups to remove. + self.Input = Input + + class Response: + # Server response for the `RemoveGroups` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, Input: List[int] = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "RemoveGroups" + self.Type = Type + # The root scan group in the current open project. + self.Output = Output + # The requested of indices of the scan groups to remove. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/RemoveProjects.py b/three/MF/V3/Tasks/RemoveProjects.py new file mode 100644 index 0000000..aef7e61 --- /dev/null +++ b/three/MF/V3/Tasks/RemoveProjects.py @@ -0,0 +1,68 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState +from typing import List + + +class RemoveProjects: + """* + Remove selected projects. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RemoveProjects", + "Input":[1,3,6] + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RemoveProjects", + "Input":[1,3,6], + "Output":[ + {"index":2,"modified":[2024,5,12,11,23,17],"name":"Project 2","size":35409834}, + {"index":4,"modified":[2024,5,12,11,2,37],"name":"Project 4","size":175025367}, + {"index":5,"modified":[2024,5,6,17,15,53],"name":"Project 5","size":24314083} + ], + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `RemoveProjects` task. + def __init__(self, Index: int, Type: str, Input: List[int] = None): + # A unique identifier generated by the client. + self.Index = Index + # "RemoveProjects" + self.Type = Type + # The list of indices of the projects to remove. + self.Input = Input + + class Response: + # Server response for the `RemoveProjects` task. + def __init__(self, Index: int, Type: str, Input: List[int] = None, Output: MF_V3_Descriptors_Project_Project.Brief = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "RemoveProjects" + self.Type = Type + # The list of indices of the requested projects to remove. + self.Input = Input + # Brief descriptors of the remaining projects. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/RestoreFactoryCalibration.py b/three/MF/V3/Tasks/RestoreFactoryCalibration.py new file mode 100644 index 0000000..4caea88 --- /dev/null +++ b/three/MF/V3/Tasks/RestoreFactoryCalibration.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class RestoreFactoryCalibration: + """* + Restore factory calibration. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RestoreFactoryCalibration" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RestoreFactoryCalibration", + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `RestoreFactoryCalibration` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "RestoreFactoryCalibration" + self.Type = Type + + class Response: + # Server response for the `RestoreFactoryCalibration` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "RestoreFactoryCalibration" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/RotateTurntable.py b/three/MF/V3/Tasks/RotateTurntable.py new file mode 100644 index 0000000..219c752 --- /dev/null +++ b/three/MF/V3/Tasks/RotateTurntable.py @@ -0,0 +1,59 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class RotateTurntable: + """* + Rotate the turntable. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RotateTurntable", + "Input":15 + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"RotateTurntable", + "Input":15, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `RotateTurntable` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "RotateTurntable" + self.Type = Type + # The rotation angle in degrees. + self.Input = Input + + class Response: + # Server response for the `RotateTurntable` task. + def __init__(self, Index: int, Type: str, Input: int, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "RotateTurntable" + self.Type = Type + # The requested rotation angle in degrees. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/ScanData.py b/three/MF/V3/Tasks/ScanData.py new file mode 100644 index 0000000..c5ecab3 --- /dev/null +++ b/three/MF/V3/Tasks/ScanData.py @@ -0,0 +1,239 @@ +from MF.V3.Descriptors.ScanData import ScanData as MF_V3_Descriptors_ScanData_ScanData +from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class ScanData: + """* + Download the raw scan data for a scan in the current open project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + ``` + + > Vertex position buffer message from server. + + ```json + { + "Buffer":{ + "Index":0, + "Size":1558188, + "Descriptor":{ + "components":[{ + "type":"Position" + "size":3, + "offset":0, + "normalized":false, + }], + "stride":3 + }, + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex position binary data transfer from server [1558188 bytes]. + + > Vertex normal buffer message from server. + + ```json + { + "Buffer":{ + "Index":1, + "Size":1558188, + "Descriptor":{ + "components":[{ + "type":"Normal" + "size":3, + "offset":0, + "normalized":false, + }], + "stride":3 + }, + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex normal binary data transfer from server [1558188 bytes]. + + > Vertex texture coordinate buffer message from server. + + ```json + { + "Buffer":{ + "Index":2, + "Size":1038792, + "Descriptor":{ + "components":[{ + "type":"UV" + "size":2, + "offset":0, + "normalized":false, + }], + "stride":2 + }, + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Vertex texture coordinate binary data transfer from server [1038792 bytes]. + + > Texture image buffer message from server. + + ```json + { + "Buffer":{ + "Index":3, + "Size":3504494, + "Descriptor":{ + "components":[{ + "type":"Texture" + "size":0, + "offset":0, + "normalized":false, + }], + "stride":0 + }, + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Texture binary data transfer from server [3504494 bytes]. + + > Triangle index buffer message from server. + + ```json + { + "Buffer":{ + "Index":4, + "Size":1996356, + "Descriptor":{ + "components":[{ + "type":"Triangle" + "size":1, + "offset":0, + "normalized":false, + }], + "stride":1 + }, + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{ + "index":1, + "buffers":["All"] + } + } + } + } + ``` + + > Triangle index binary data transfer from server [1996356 bytes]. + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"ScanData", + "Input":{"buffers":["All"],"index":1}, + "Output":{ + "buffers":[ + {"components":[{"normalized":false,"offset":0,"size":3,"type":"Position"}],"stride":3}, + {"components":[{"normalized":false,"offset":0,"size":3,"type":"Normal"}],"stride":3}, + {"components":[{"normalized":false,"offset":0,"size":2,"type":"UV"}],"stride":2}, + {"components":[{"normalized":false,"offset":0,"size":0,"type":"Texture"}],"stride":0}, + {"components":[{"normalized":false,"offset":0,"size":1,"type":"Triangle"}],"stride":1} + ], + "index":1, + "name":"Scan-1" + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `ScanData` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData): + # A unique identifier generated by the client. + self.Index = Index + # "ScanData" + self.Type = Type + # Requested scan data. + self.Input = Input + + class Response: + # Server response for the `ScanData` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData, Output: MF_V3_Descriptors_ScanData_ScanData, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "ScanData" + self.Type = Type + # The scan data requested by the client. + self.Input = Input + # The scan data sent from the server. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Server buffer message for the `ScanData` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: MF_V3_Descriptors_ScanData_ScanData.Buffer): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested ScanData task. + self.Task = Task + # The scan data buffer descriptor. + self.Descriptor = Descriptor + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/SetCameras.py b/three/MF/V3/Tasks/SetCameras.py new file mode 100644 index 0000000..188e93c --- /dev/null +++ b/three/MF/V3/Tasks/SetCameras.py @@ -0,0 +1,76 @@ +from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SetCameras: + """* + Apply camera settings to one or both cameras. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetCameras", + "Input":{ + "analogGain":256, + "digitalGain":128, + "exposure":18000 + }, + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetCameras" + "Input":{ + "analogGain":256, + "digitalGain":512, + "exposure":18000 + }, + "Output":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":512}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SetCameras` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Camera_Camera = None): + # A unique identifier generated by the client. + self.Index = Index + # "SetCameras" + self.Type = Type + # Camera settings. + self.Input = Input + + class Response: + # Server response for the `SetCameras` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Camera_Camera = None, Output: MF_V3_Descriptors_Settings_Camera_Camera = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SetCameras" + self.Type = Type + # Requested camera settings. + self.Input = Input + # Actual camera settings after applying the requested settings. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/SetGroup.py b/three/MF/V3/Tasks/SetGroup.py new file mode 100644 index 0000000..ab4933c --- /dev/null +++ b/three/MF/V3/Tasks/SetGroup.py @@ -0,0 +1,104 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.Group import Group as MF_V3_Settings_Group_Group +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SetGroup: + """* + Set scan group properties. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetGroup", + "Input":{ + "index":2, + "name":"Amazing Scan" + "color":[1,0,0,1], + "rotation":[0,3.14,0], + "translation":[0,10,25] + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetGroup", + "Input":{ + "index":2, + "name":"Amazing Scan" + "color":[1,0,0,1], + "rotation":[0,3.14,0], + "translation":[0,10,25] + } + "Output":{ + "groups":[ + { + "index":1, + "scan":1, + "name":"Scan-1", + "color":[0.75,0.5,0.2,1.0], + "rotation":[0.03,0.1,-0.01], + "translation":[-101,67,-561], + "visible":true + }, + { + "index":2, + "scan":2, + "name":"Amazing Scan", + "color":[1,0,0,1], + "rotation":[0,3.14,0], + "translation":[0,10,25], + "visible":true + }, + { + "index":3, + "scan":3, + "name":"Scan-3", + "color":[0.6,0.8,0.9,1.0], + "visible":true + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SetGroup` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group): + # A unique identifier generated by the client. + self.Index = Index + # "SetGroup" + self.Type = Type + # The requested group settings. + self.Input = Input + + class Response: + # Server response for the `SetGroup` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SetGroup" + self.Type = Type + # The requested group settings. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/SetProject.py b/three/MF/V3/Tasks/SetProject.py new file mode 100644 index 0000000..c2d785f --- /dev/null +++ b/three/MF/V3/Tasks/SetProject.py @@ -0,0 +1,80 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SetProject: + """* + Apply settings to the current open project. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetProject", + "Input":{ + "name":"My Project" + }, + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetProject", + "Input":{ + "name":"My Project" + }, + "Output":{ + "index":5, + "name":"My Project", + "groups":[{ + "color":[0.8,0.5,0.6,1.0], + "index":1, + "name":"Scan-1", + "scan":1, + "rotation":[0.2,0.8,-0.1], + "translation":[-275,-32,-134], + "visible":true + }], + } + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SetProject` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Project_Project = None): + # A unique identifier generated by the client. + self.Index = Index + # "SetProject" + self.Type = Type + # Project settings. + self.Input = Input + + class Response: + # Server response for the `SetProject` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Project_Project = None, Output: MF_V3_Descriptors_Project_Project = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SetProject" + self.Type = Type + # Requested project settings. + self.Input = Input + # Actual project settings after applying the requested settings. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/SetProjector.py b/three/MF/V3/Tasks/SetProjector.py new file mode 100644 index 0000000..2fe887c --- /dev/null +++ b/three/MF/V3/Tasks/SetProjector.py @@ -0,0 +1,75 @@ +from MF.V3.Descriptors.Settings.Projector import Projector as MF_V3_Descriptors_Settings_Projector_Projector +from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SetProjector: + """* + Apply projector settings. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetProjector" + "Input":{ + "on":true, + "brightness":0.75, + "color":[1.0, 1.0, 1.0] + }, + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SetProjector" + "Input":{ + "on":true, + "brightness":0.75, + "color":[1.0, 1.0, 1.0] + }, + "Output":{ + "on":{"default":false,"value":true}, + "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.75} + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SetProjector` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Projector_Projector = None): + # A unique identifier generated by the client. + self.Index = Index + # "SetProjector" + self.Type = Type + # Projector settings. + self.Input = Input + + class Response: + # Server response for the `SetProjector` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Projector_Projector = None, Output: MF_V3_Descriptors_Settings_Projector_Projector = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SetProjector" + self.Type = Type + # Requested projector settings. + self.Input = Input + # Actual projector settings after applying the requested settings. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/Shutdown.py b/three/MF/V3/Tasks/Shutdown.py new file mode 100644 index 0000000..c6928ef --- /dev/null +++ b/three/MF/V3/Tasks/Shutdown.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class Shutdown: + """* + Shutdown the scanner. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Shutdown" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"Shutdown" + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `Shutdown` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "Shutdown" + self.Type = Type + + class Response: + # Server response for the `Shutdown` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "Shutdown" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/SplitGroup.py b/three/MF/V3/Tasks/SplitGroup.py new file mode 100644 index 0000000..7efbce8 --- /dev/null +++ b/three/MF/V3/Tasks/SplitGroup.py @@ -0,0 +1,74 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SplitGroup: + """* + Split a scan group (ie. move its subgroups to its parent group). + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SplitGroup", + "Input":0 + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"SplitGroup", + "Input":0, + "Output":{ + "groups":[ + { + "index":1, + "name":"Group 1", + }, + { + "index":2, + "name":"Group 2" + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SplitGroup` task. + def __init__(self, Index: int, Type: str, Input: int): + # A unique identifier generated by the client. + self.Index = Index + # "SplitGroup" + self.Type = Type + # The index of the group to split. + self.Input = Input + + class Response: + # Server response for the `SplitGroup` task. + def __init__(self, Index: int, Type: str, Input: int, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SplitGroup" + self.Type = Type + # The requested index of the group to split. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/StartVideo.py b/three/MF/V3/Tasks/StartVideo.py new file mode 100644 index 0000000..da7f6b2 --- /dev/null +++ b/three/MF/V3/Tasks/StartVideo.py @@ -0,0 +1,64 @@ +from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class StartVideo: + """* + Start the video stream. + + The video frames are sent as task buffers associated with the reserved video task index -1. The left and right camera frames are sent in buffer 0 and 1, respectively. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"StartVideo" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"StartVideo", + "Output":{ + "codec":"JPEG", + "format":"YUV420", + "width":510, + "height":380 + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `StartVideo` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "StartVideo" + self.Type = Type + + class Response: + # Server response for the `StartVideo` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Settings_Video_Video = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "StartVideo" + self.Type = Type + # The video settings. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/StopVideo.py b/three/MF/V3/Tasks/StopVideo.py new file mode 100644 index 0000000..68662b0 --- /dev/null +++ b/three/MF/V3/Tasks/StopVideo.py @@ -0,0 +1,53 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class StopVideo: + """* + Stop the video stream. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"StopVideo" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"StopVideo", + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `StopVideo` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "StopVideo" + self.Type = Type + + class Response: + # Server response for the `StopVideo` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "StopVideo" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/SystemInfo.py b/three/MF/V3/Tasks/SystemInfo.py new file mode 100644 index 0000000..59d8d4e --- /dev/null +++ b/three/MF/V3/Tasks/SystemInfo.py @@ -0,0 +1,92 @@ +from MF.V3.Descriptors.System import System as MF_V3_Descriptors_System_System +from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class SystemInfo: + """* + Get system information including the serial number, disk space and installed and available software versions. + + Request example: + ``` + { + "Task":{ + "Index":1, + "Type":"SystemInfo", + "Input":{ + "installed":["server","frontend"], + "available":["server","frontend"] + } + } + } + ``` + Response example: + ``` + { + "Task":{ + "Index":1, + "Type":"SystemInfo" + "Input":{ + "installed":["server","frontend"], + "available":["server","frontend"] + } + "Output":{ + "serialNumber":"1000000012345678", + "diskSpace":{"available":8523210752,"capacity":15082610688}, + "software:{ + "installed":[ + { + "name":"server", + "version":{ + "major":2, + "minor":21, + "patch":119, + "string":"2.21.119" + } + }, + { + "name":"frontend", + "version":{ + "major":2, + "minor":14, + "patch":39, + "string":"2.14.39" + } + } + }, + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `SystemInfo` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Software_Software = None): + # A unique identifier generated by the client. + self.Index = Index + # "SystemInfo" + self.Type = Type + # Software settings. + self.Input = Input + + class Response: + # Server response for the `SystemInfo` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_System_System, Input: MF_V3_Settings_Software_Software = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "SystemInfo" + self.Type = Type + # The system descriptor. + self.Output = Output + # The requested software settings. + self.Input = Input + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/TransformGroup.py b/three/MF/V3/Tasks/TransformGroup.py new file mode 100644 index 0000000..f706e6b --- /dev/null +++ b/three/MF/V3/Tasks/TransformGroup.py @@ -0,0 +1,81 @@ +from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project +from MF.V3.Settings.Group import Group as MF_V3_Settings_Group_Group +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class TransformGroup: + """* + Apply a rigid transformation to a group. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"TransformGroup", + "Input":{ + "index":1, + "rotation":[0.5, 1.0, 1.5], + "translation":[10, 20, 30] + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"TransformGroup", + "Input":{ + "index":1, + "rotation":[0.5, 1.0, 1.5], + "translation":[10, 20, 30] + }, + "Output":{ + "groups":[ + { + "index":1, + "name":"Group 1", + "rotation":[0.5, 1.0, 1.5], + "translation":[10, 20, 30] + } + ] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `TransformGroup` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group): + # A unique identifier generated by the client. + self.Index = Index + # "TransformGroup" + self.Type = Type + # The group settings containing the requested rotation and translation. + self.Input = Input + + class Response: + # Server response for the `TransformGroup` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "TransformGroup" + self.Type = Type + # The group settings containing the requested rotation and translation. + self.Input = Input + # The root scan group in the current open project. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/TurntableCalibration.py b/three/MF/V3/Tasks/TurntableCalibration.py new file mode 100644 index 0000000..67308a8 --- /dev/null +++ b/three/MF/V3/Tasks/TurntableCalibration.py @@ -0,0 +1,61 @@ +from MF.V3.Descriptors.Calibration import Turntable as MF_V3_Descriptors_Calibration_Turntable +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class TurntableCalibration: + """* + Get the turntable calibration descriptor. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"TurntableCalibration" + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"TurntableCalibration", + "Output":{ + "date":[2024,4,27,16,57,35], + "quality":"Excellent", + "focus":[300,320] + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `TurntableCalibration` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "TurntableCalibration" + self.Type = Type + + class Response: + # Server response for the `TurntableCalibration` task. + def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_Turntable = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "TurntableCalibration" + self.Type = Type + # The turntable calibration descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/UpdateSettings.py b/three/MF/V3/Tasks/UpdateSettings.py new file mode 100644 index 0000000..26818f7 --- /dev/null +++ b/three/MF/V3/Tasks/UpdateSettings.py @@ -0,0 +1,105 @@ +from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner +from MF.V3.Settings.Scanner import Scanner as MF_V3_Settings_Scanner_Scanner +from MF.V3.Task import TaskState as MF_V3_Task_TaskState + + +class UpdateSettings: + """* + Update scanner settings. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"UpdateSettings", + "Input":{ + "camera":{ + "analogGain":256, + "digitalGain":320, + "exposure":18000 + } + } + } + } + ``` + + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"UpdateSettings", + "Input":{ + "camera":{ + "analogGain":256, + "digitalGain":320, + "exposure":18000 + } + }, + "Output":{ + "camera":{ + "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, + "autoExposure":{"default":false,"value":false}, + "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, + "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, + }, + "projector":{ + "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, + "on":{"default":false,"value":true} + }, + "turntable":{ + "scans":{"default":8,"max":24,"min":1,"value":3}, + "sweep":{"default":360,"max":360,"min":5,"value":90}, + "use":{"default":true,"value":true} + }, + "capture":{ + "quality":{"default":"Medium","value":"Medium"}, + "texture":{"default":true,"value":true} + }, + "i18n":{ + "language":{"default":"en","value":"en"} + }, + "style":{ + "theme":{"default":"Dark","value":"Dark"} + }, + "viewer":{ + "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} + } + }, + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `UpdateSettings` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scanner_Scanner): + # A unique identifier generated by the client. + self.Index = Index + # "UpdateSettings" + self.Type = Type + # Scanner settings. + self.Input = Input + + class Response: + # Server response for the `UpdateSettings` task. + def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scanner_Scanner, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "UpdateSettings" + self.Type = Type + # The requested scanner settings. + self.Input = Input + # The scanner settings descriptor. + self.Output = Output + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/UploadProject.py b/three/MF/V3/Tasks/UploadProject.py new file mode 100644 index 0000000..8314523 --- /dev/null +++ b/three/MF/V3/Tasks/UploadProject.py @@ -0,0 +1,79 @@ +from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task + + +class UploadProject: + """* + Upload a project to the scanner. The project must be archived in a ZIP file. + + > Request example: + + ```json + { + "Task":{ + "Index":1, + "Type":"UploadProject" + } + } + ``` + + > Buffer message from client. + + ```json + { + "Buffer":{ + "Index":0, + "Size":15682096, + "Task":{ + "Index":1, + "Type":"UploadProject" + } + } + } + ``` + + > Binary data transfer from client: The project zip file [15682096 bytes]. + > Response example: + + ```json + { + "Task":{ + "Index":1, + "Type":"UploadProject" + "State":"Completed" + } + } + ``` + """ + class Request: + # Client request for the `UploadProject` task. + def __init__(self, Index: int, Type: str): + # A unique identifier generated by the client. + self.Index = Index + # "UploadProject" + self.Type = Type + + class Response: + # Server response for the `UploadProject` task. + def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): + # The unique identifier generated by the client. + self.Index = Index + # "UploadProject" + self.Type = Type + # The current state of the task. + self.State = State + # A string describing the error if the task has failed. + self.Error = Error + + class Buffer: + # Client buffer message for the `UploadProject` task. + def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): + # The zero-based index identifying the data buffer. + self.Index = Index + # The size of the incoming data buffer in bytes. + self.Size = Size + # The requested UploadProject task. + self.Task = Task + + def __init__(self): + pass + diff --git a/three/MF/V3/Tasks/__init__.py b/three/MF/V3/Tasks/__init__.py new file mode 100644 index 0000000..d91979d --- /dev/null +++ b/three/MF/V3/Tasks/__init__.py @@ -0,0 +1,56 @@ +from MF.V3.Tasks.AddMergeToProject import * +from MF.V3.Tasks.Align import * +from MF.V3.Tasks.AutoFocus import * +from MF.V3.Tasks.BoundingBox import * +from MF.V3.Tasks.CalibrateCameras import * +from MF.V3.Tasks.CalibrateTurntable import * +from MF.V3.Tasks.CalibrationCaptureTargets import * +from MF.V3.Tasks.CameraCalibration import * +from MF.V3.Tasks.CloseProject import * +from MF.V3.Tasks.ConnectWifi import * +from MF.V3.Tasks.DepthMap import * +from MF.V3.Tasks.DetectCalibrationCard import * +from MF.V3.Tasks.DownloadProject import * +from MF.V3.Tasks.Export import * +from MF.V3.Tasks.ExportLogs import * +from MF.V3.Tasks.ExportMerge import * +from MF.V3.Tasks.FlattenGroup import * +from MF.V3.Tasks.ForgetWifi import * +from MF.V3.Tasks.HasCameras import * +from MF.V3.Tasks.HasProjector import * +from MF.V3.Tasks.HasTurntable import * +from MF.V3.Tasks.ListExportFormats import * +from MF.V3.Tasks.ListGroups import * +from MF.V3.Tasks.ListNetworkInterfaces import * +from MF.V3.Tasks.ListProjects import * +from MF.V3.Tasks.ListScans import * +from MF.V3.Tasks.ListSettings import * +from MF.V3.Tasks.ListWifi import * +from MF.V3.Tasks.Merge import * +from MF.V3.Tasks.MergeData import * +from MF.V3.Tasks.MoveGroup import * +from MF.V3.Tasks.NewGroup import * +from MF.V3.Tasks.NewProject import * +from MF.V3.Tasks.NewScan import * +from MF.V3.Tasks.OpenProject import * +from MF.V3.Tasks.PopSettings import * +from MF.V3.Tasks.PushSettings import * +from MF.V3.Tasks.Reboot import * +from MF.V3.Tasks.RemoveGroups import * +from MF.V3.Tasks.RemoveProjects import * +from MF.V3.Tasks.RestoreFactoryCalibration import * +from MF.V3.Tasks.RotateTurntable import * +from MF.V3.Tasks.ScanData import * +from MF.V3.Tasks.SetCameras import * +from MF.V3.Tasks.SetGroup import * +from MF.V3.Tasks.SetProject import * +from MF.V3.Tasks.SetProjector import * +from MF.V3.Tasks.Shutdown import * +from MF.V3.Tasks.SplitGroup import * +from MF.V3.Tasks.StartVideo import * +from MF.V3.Tasks.StopVideo import * +from MF.V3.Tasks.SystemInfo import * +from MF.V3.Tasks.TransformGroup import * +from MF.V3.Tasks.TurntableCalibration import * +from MF.V3.Tasks.UpdateSettings import * +from MF.V3.Tasks.UploadProject import * diff --git a/three/MF/V3/Three.py b/three/MF/V3/Three.py new file mode 100644 index 0000000..150a228 --- /dev/null +++ b/three/MF/V3/Three.py @@ -0,0 +1,1160 @@ +from MF.V3 import Task +from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced +from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align +from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus +from MF.V3.Settings.BoundingBox import BoundingBox as MF_V3_Settings_BoundingBox_BoundingBox +from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera +from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture +from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export +from MF.V3.Settings.Group import Group as MF_V3_Settings_Group_Group +from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n +from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge +from MF.V3.Settings.NewGroup import NewGroup as MF_V3_Settings_NewGroup_NewGroup +from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project +from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector +from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan +from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData +from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection +from MF.V3.Settings.Scanner import Scanner as MF_V3_Settings_Scanner_Scanner +from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software +from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style +from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable +from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials +from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer +from MF.V3.Settings.Wifi import Wifi as MF_V3_Settings_Wifi_Wifi +from MF.V3.Tasks.AddMergeToProject import AddMergeToProject as MF_V3_Tasks_AddMergeToProject +from MF.V3.Tasks.Align import Align as MF_V3_Tasks_Align +from MF.V3.Tasks.AutoFocus import AutoFocus as MF_V3_Tasks_AutoFocus +from MF.V3.Tasks.BoundingBox import BoundingBox as MF_V3_Tasks_BoundingBox +from MF.V3.Tasks.CalibrateCameras import CalibrateCameras as MF_V3_Tasks_CalibrateCameras +from MF.V3.Tasks.CalibrateTurntable import CalibrateTurntable as MF_V3_Tasks_CalibrateTurntable +from MF.V3.Tasks.CalibrationCaptureTargets import CalibrationCaptureTargets as MF_V3_Tasks_CalibrationCaptureTargets +from MF.V3.Tasks.CameraCalibration import CameraCalibration as MF_V3_Tasks_CameraCalibration +from MF.V3.Tasks.CloseProject import CloseProject as MF_V3_Tasks_CloseProject +from MF.V3.Tasks.ConnectWifi import ConnectWifi as MF_V3_Tasks_ConnectWifi +from MF.V3.Tasks.DepthMap import DepthMap as MF_V3_Tasks_DepthMap +from MF.V3.Tasks.DetectCalibrationCard import DetectCalibrationCard as MF_V3_Tasks_DetectCalibrationCard +from MF.V3.Tasks.DownloadProject import DownloadProject as MF_V3_Tasks_DownloadProject +from MF.V3.Tasks.Export import Export as MF_V3_Tasks_Export +from MF.V3.Tasks.ExportLogs import ExportLogs as MF_V3_Tasks_ExportLogs +from MF.V3.Tasks.ExportMerge import ExportMerge as MF_V3_Tasks_ExportMerge +from MF.V3.Tasks.FlattenGroup import FlattenGroup as MF_V3_Tasks_FlattenGroup +from MF.V3.Tasks.ForgetWifi import ForgetWifi as MF_V3_Tasks_ForgetWifi +from MF.V3.Tasks.HasCameras import HasCameras as MF_V3_Tasks_HasCameras +from MF.V3.Tasks.HasProjector import HasProjector as MF_V3_Tasks_HasProjector +from MF.V3.Tasks.HasTurntable import HasTurntable as MF_V3_Tasks_HasTurntable +from MF.V3.Tasks.ListExportFormats import ListExportFormats as MF_V3_Tasks_ListExportFormats +from MF.V3.Tasks.ListGroups import ListGroups as MF_V3_Tasks_ListGroups +from MF.V3.Tasks.ListNetworkInterfaces import ListNetworkInterfaces as MF_V3_Tasks_ListNetworkInterfaces +from MF.V3.Tasks.ListProjects import ListProjects as MF_V3_Tasks_ListProjects +from MF.V3.Tasks.ListScans import ListScans as MF_V3_Tasks_ListScans +from MF.V3.Tasks.ListSettings import ListSettings as MF_V3_Tasks_ListSettings +from MF.V3.Tasks.ListWifi import ListWifi as MF_V3_Tasks_ListWifi +from MF.V3.Tasks.Merge import Merge as MF_V3_Tasks_Merge +from MF.V3.Tasks.MergeData import MergeData as MF_V3_Tasks_MergeData +from MF.V3.Tasks.MoveGroup import MoveGroup as MF_V3_Tasks_MoveGroup +from MF.V3.Tasks.NewGroup import NewGroup as MF_V3_Tasks_NewGroup +from MF.V3.Tasks.NewProject import NewProject as MF_V3_Tasks_NewProject +from MF.V3.Tasks.NewScan import NewScan as MF_V3_Tasks_NewScan +from MF.V3.Tasks.OpenProject import OpenProject as MF_V3_Tasks_OpenProject +from MF.V3.Tasks.PopSettings import PopSettings as MF_V3_Tasks_PopSettings +from MF.V3.Tasks.PushSettings import PushSettings as MF_V3_Tasks_PushSettings +from MF.V3.Tasks.Reboot import Reboot as MF_V3_Tasks_Reboot +from MF.V3.Tasks.RemoveGroups import RemoveGroups as MF_V3_Tasks_RemoveGroups +from MF.V3.Tasks.RemoveProjects import RemoveProjects as MF_V3_Tasks_RemoveProjects +from MF.V3.Tasks.RestoreFactoryCalibration import RestoreFactoryCalibration as MF_V3_Tasks_RestoreFactoryCalibration +from MF.V3.Tasks.RotateTurntable import RotateTurntable as MF_V3_Tasks_RotateTurntable +from MF.V3.Tasks.ScanData import ScanData as MF_V3_Tasks_ScanData +from MF.V3.Tasks.SetCameras import SetCameras as MF_V3_Tasks_SetCameras +from MF.V3.Tasks.SetGroup import SetGroup as MF_V3_Tasks_SetGroup +from MF.V3.Tasks.SetProject import SetProject as MF_V3_Tasks_SetProject +from MF.V3.Tasks.SetProjector import SetProjector as MF_V3_Tasks_SetProjector +from MF.V3.Tasks.Shutdown import Shutdown as MF_V3_Tasks_Shutdown +from MF.V3.Tasks.SplitGroup import SplitGroup as MF_V3_Tasks_SplitGroup +from MF.V3.Tasks.StartVideo import StartVideo as MF_V3_Tasks_StartVideo +from MF.V3.Tasks.StopVideo import StopVideo as MF_V3_Tasks_StopVideo +from MF.V3.Tasks.SystemInfo import SystemInfo as MF_V3_Tasks_SystemInfo +from MF.V3.Tasks.TransformGroup import TransformGroup as MF_V3_Tasks_TransformGroup +from MF.V3.Tasks.TurntableCalibration import TurntableCalibration as MF_V3_Tasks_TurntableCalibration +from MF.V3.Tasks.UpdateSettings import UpdateSettings as MF_V3_Tasks_UpdateSettings +from MF.V3.Tasks.UploadProject import UploadProject as MF_V3_Tasks_UploadProject +from typing import List + + +def list_network_interfaces(self) -> Task: + # List available wifi networks. + list_network_interfaces_request = MF_V3_Tasks_ListNetworkInterfaces.Request( + Index=0, + Type="ListNetworkInterfaces" + ) + list_network_interfaces_response = MF_V3_Tasks_ListNetworkInterfaces.Response( + Index=0, + Type="ListNetworkInterfaces" + ) + task = Task(Index=0, Type="ListNetworkInterfaces", Input=list_network_interfaces_request, Output=list_network_interfaces_response) + self.SendTask(task) + return task + + +def list_wifi(self) -> Task: + # List available wifi networks. + list_wifi_request = MF_V3_Tasks_ListWifi.Request( + Index=0, + Type="ListWifi" + ) + list_wifi_response = MF_V3_Tasks_ListWifi.Response( + Index=0, + Type="ListWifi" + ) + task = Task(Index=0, Type="ListWifi", Input=list_wifi_request, Output=list_wifi_response) + self.SendTask(task) + return task + + +def connect_wifi(self, ssid: str, password: str) -> Task: + # Connect to a wifi network. + connect_wifi_request = MF_V3_Tasks_ConnectWifi.Request( + Index=0, + Type="ConnectWifi", + Input=MF_V3_Settings_Wifi_Wifi( + ssid=ssid, + password=password, + ) + ) + connect_wifi_response = MF_V3_Tasks_ConnectWifi.Response( + Index=0, + Type="ConnectWifi", + Input=MF_V3_Settings_Wifi_Wifi( + ssid=ssid, + password=password, + ) + ) + task = Task(Index=0, Type="ConnectWifi", Input=connect_wifi_request, Output=connect_wifi_response) + self.SendTask(task) + return task + + +def forget_wifi(self) -> Task: + # Forget all wifi connections. + forget_wifi_request = MF_V3_Tasks_ForgetWifi.Request( + Index=0, + Type="ForgetWifi" + ) + forget_wifi_response = MF_V3_Tasks_ForgetWifi.Response( + Index=0, + Type="ForgetWifi" + ) + task = Task(Index=0, Type="ForgetWifi", Input=forget_wifi_request, Output=forget_wifi_response) + self.SendTask(task) + return task + + +def list_settings(self) -> Task: + # Get scanner settings. + list_settings_request = MF_V3_Tasks_ListSettings.Request( + Index=0, + Type="ListSettings" + ) + list_settings_response = MF_V3_Tasks_ListSettings.Response( + Index=0, + Type="ListSettings" + ) + task = Task(Index=0, Type="ListSettings", Input=list_settings_request, Output=list_settings_response) + self.SendTask(task) + return task + + +def push_settings(self) -> Task: + # Push the current scanner settings to the settings stack. + push_settings_request = MF_V3_Tasks_PushSettings.Request( + Index=0, + Type="PushSettings" + ) + push_settings_response = MF_V3_Tasks_PushSettings.Response( + Index=0, + Type="PushSettings" + ) + task = Task(Index=0, Type="PushSettings", Input=push_settings_request, Output=push_settings_response) + self.SendTask(task) + return task + + +def pop_settings(self, Input: bool = None) -> Task: + # Pop and restore scanner settings from the settings stack. + pop_settings_request = MF_V3_Tasks_PopSettings.Request( + Index=0, + Type="PopSettings", + Input=Input + ) + pop_settings_response = MF_V3_Tasks_PopSettings.Response( + Index=0, + Type="PopSettings" + ) + task = Task(Index=0, Type="PopSettings", Input=pop_settings_request, Output=pop_settings_response) + self.SendTask(task) + return task + + +def update_settings(self, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None) -> Task: + # Update scanner settings. + update_settings_request = MF_V3_Tasks_UpdateSettings.Request( + Index=0, + Type="UpdateSettings", + Input=MF_V3_Settings_Scanner_Scanner( + advanced=advanced, + camera=camera, + capture=capture, + i18n=i18n, + projector=projector, + style=style, + turntable=turntable, + tutorials=tutorials, + viewer=viewer, + software=software, + ) + ) + update_settings_response = MF_V3_Tasks_UpdateSettings.Response( + Index=0, + Type="UpdateSettings", + Input=MF_V3_Settings_Scanner_Scanner( + advanced=advanced, + camera=camera, + capture=capture, + i18n=i18n, + projector=projector, + style=style, + turntable=turntable, + tutorials=tutorials, + viewer=viewer, + software=software, + ) + ) + task = Task(Index=0, Type="UpdateSettings", Input=update_settings_request, Output=update_settings_response) + self.SendTask(task) + return task + + +def list_projects(self) -> Task: + # List all projects. + list_projects_request = MF_V3_Tasks_ListProjects.Request( + Index=0, + Type="ListProjects" + ) + list_projects_response = MF_V3_Tasks_ListProjects.Response( + Index=0, + Type="ListProjects" + ) + task = Task(Index=0, Type="ListProjects", Input=list_projects_request, Output=list_projects_response) + self.SendTask(task) + return task + + +def download_project(self, Input: int) -> Task: + # Download a project from the scanner. + download_project_request = MF_V3_Tasks_DownloadProject.Request( + Index=0, + Type="DownloadProject", + Input=Input + ) + download_project_response = MF_V3_Tasks_DownloadProject.Response( + Index=0, + Type="DownloadProject", + Input=Input + ) + task = Task(Index=0, Type="DownloadProject", Input=download_project_request, Output=download_project_response) + self.SendTask(task) + return task + + +def upload_project(self, buffer: bytes) -> Task: + # Upload a project to the scanner. + upload_project_request = MF_V3_Tasks_UploadProject.Request( + Index=0, + Type="UploadProject" + ) + upload_project_response = MF_V3_Tasks_UploadProject.Response( + Index=0, + Type="UploadProject" + ) + task = Task(Index=0, Type="UploadProject", Input=upload_project_request, Output=upload_project_response) + self.SendTask(task, buffer) + return task + + +def new_project(self, Input: str = None) -> Task: + # Create a new project. + new_project_request = MF_V3_Tasks_NewProject.Request( + Index=0, + Type="NewProject", + Input=Input + ) + new_project_response = MF_V3_Tasks_NewProject.Response( + Index=0, + Type="NewProject" + ) + task = Task(Index=0, Type="NewProject", Input=new_project_request, Output=new_project_response) + self.SendTask(task) + return task + + +def open_project(self, Input: int) -> Task: + # Open an existing project. + open_project_request = MF_V3_Tasks_OpenProject.Request( + Index=0, + Type="OpenProject", + Input=Input + ) + open_project_response = MF_V3_Tasks_OpenProject.Response( + Index=0, + Type="OpenProject", + Input=Input + ) + task = Task(Index=0, Type="OpenProject", Input=open_project_request, Output=open_project_response) + self.SendTask(task) + return task + + +def close_project(self) -> Task: + # Close the current open project. + close_project_request = MF_V3_Tasks_CloseProject.Request( + Index=0, + Type="CloseProject" + ) + close_project_response = MF_V3_Tasks_CloseProject.Response( + Index=0, + Type="CloseProject" + ) + task = Task(Index=0, Type="CloseProject", Input=close_project_request, Output=close_project_response) + self.SendTask(task) + return task + + +def remove_projects(self, Input: List[int] = None) -> Task: + # Remove selected projects. + remove_projects_request = MF_V3_Tasks_RemoveProjects.Request( + Index=0, + Type="RemoveProjects", + Input=Input + ) + remove_projects_response = MF_V3_Tasks_RemoveProjects.Response( + Index=0, + Type="RemoveProjects" + ) + task = Task(Index=0, Type="RemoveProjects", Input=remove_projects_request, Output=remove_projects_response) + self.SendTask(task) + return task + + +def list_groups(self) -> Task: + # List the scan groups in the current open project. + list_groups_request = MF_V3_Tasks_ListGroups.Request( + Index=0, + Type="ListGroups" + ) + list_groups_response = MF_V3_Tasks_ListGroups.Response( + Index=0, + Type="ListGroups", + Output=None + ) + task = Task(Index=0, Type="ListGroups", Input=list_groups_request, Output=list_groups_response) + self.SendTask(task) + return task + + +def list_scans(self) -> Task: + # List the scans in the current open project. + list_scans_request = MF_V3_Tasks_ListScans.Request( + Index=0, + Type="ListScans" + ) + list_scans_response = MF_V3_Tasks_ListScans.Response( + Index=0, + Type="ListScans" + ) + task = Task(Index=0, Type="ListScans", Input=list_scans_request, Output=list_scans_response) + self.SendTask(task) + return task + + +def scan_data(self, index: int, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None, buffers: List[MF_V3_Settings_ScanData_ScanData.Buffer] = None, metadata: List[MF_V3_Settings_ScanData_ScanData.Metadata] = None) -> Task: + # Download the raw scan data for a scan in the current open project. + scan_data_request = MF_V3_Tasks_ScanData.Request( + Index=0, + Type="ScanData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + mergeStep=mergeStep, + buffers=buffers, + metadata=metadata, + ) + ) + scan_data_response = MF_V3_Tasks_ScanData.Response( + Index=0, + Type="ScanData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + mergeStep=mergeStep, + buffers=buffers, + metadata=metadata, + ), + Output=None + ) + task = Task(Index=0, Type="ScanData", Input=scan_data_request, Output=scan_data_response) + self.SendTask(task) + return task + + +def set_project(self, index: int = None, name: str = None) -> Task: + # Apply settings to the current open project. + set_project_request = MF_V3_Tasks_SetProject.Request( + Index=0, + Type="SetProject", + Input=MF_V3_Settings_Project_Project( + index=index, + name=name, + ) + ) + set_project_response = MF_V3_Tasks_SetProject.Response( + Index=0, + Type="SetProject" + ) + task = Task(Index=0, Type="SetProject", Input=set_project_request, Output=set_project_response) + self.SendTask(task) + return task + + +def set_group(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> Task: + # Set scan group properties. + set_group_request = MF_V3_Tasks_SetGroup.Request( + Index=0, + Type="SetGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + name=name, + color=color, + visible=visible, + collapsed=collapsed, + rotation=rotation, + translation=translation, + ) + ) + set_group_response = MF_V3_Tasks_SetGroup.Response( + Index=0, + Type="SetGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + name=name, + color=color, + visible=visible, + collapsed=collapsed, + rotation=rotation, + translation=translation, + ), + Output=None + ) + task = Task(Index=0, Type="SetGroup", Input=set_group_request, Output=set_group_response) + self.SendTask(task) + return task + + +def new_group(self, parentIndex: int = None, baseName: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> Task: + # Create a new scan group. + new_group_request = MF_V3_Tasks_NewGroup.Request( + Index=0, + Type="NewGroup", + Input=MF_V3_Settings_NewGroup_NewGroup( + parentIndex=parentIndex, + baseName=baseName, + color=color, + visible=visible, + collapsed=collapsed, + rotation=rotation, + translation=translation, + ) + ) + new_group_response = MF_V3_Tasks_NewGroup.Response( + Index=0, + Type="NewGroup", + Output=None + ) + task = Task(Index=0, Type="NewGroup", Input=new_group_request, Output=new_group_response) + self.SendTask(task) + return task + + +def move_group(self, Input: List[int] = None) -> Task: + # Move a scan group. + move_group_request = MF_V3_Tasks_MoveGroup.Request( + Index=0, + Type="MoveGroup", + Input=Input + ) + move_group_response = MF_V3_Tasks_MoveGroup.Response( + Index=0, + Type="MoveGroup", + Output=None + ) + task = Task(Index=0, Type="MoveGroup", Input=move_group_request, Output=move_group_response) + self.SendTask(task) + return task + + +def flatten_group(self, Input: int) -> Task: + # Flatten a scan group such that it only consists of single scans. + flatten_group_request = MF_V3_Tasks_FlattenGroup.Request( + Index=0, + Type="FlattenGroup", + Input=Input + ) + flatten_group_response = MF_V3_Tasks_FlattenGroup.Response( + Index=0, + Type="FlattenGroup", + Input=Input, + Output=None + ) + task = Task(Index=0, Type="FlattenGroup", Input=flatten_group_request, Output=flatten_group_response) + self.SendTask(task) + return task + + +def split_group(self, Input: int) -> Task: + # Split a scan group (ie. move its subgroups to its parent group). + split_group_request = MF_V3_Tasks_SplitGroup.Request( + Index=0, + Type="SplitGroup", + Input=Input + ) + split_group_response = MF_V3_Tasks_SplitGroup.Response( + Index=0, + Type="SplitGroup", + Input=Input, + Output=None + ) + task = Task(Index=0, Type="SplitGroup", Input=split_group_request, Output=split_group_response) + self.SendTask(task) + return task + + +def transform_group(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> Task: + # Apply a rigid transformation to a group. + transform_group_request = MF_V3_Tasks_TransformGroup.Request( + Index=0, + Type="TransformGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + name=name, + color=color, + visible=visible, + collapsed=collapsed, + rotation=rotation, + translation=translation, + ) + ) + transform_group_response = MF_V3_Tasks_TransformGroup.Response( + Index=0, + Type="TransformGroup", + Input=MF_V3_Settings_Group_Group( + index=index, + name=name, + color=color, + visible=visible, + collapsed=collapsed, + rotation=rotation, + translation=translation, + ), + Output=None + ) + task = Task(Index=0, Type="TransformGroup", Input=transform_group_request, Output=transform_group_response) + self.SendTask(task) + return task + + +def remove_groups(self, Input: List[int] = None) -> Task: + # Remove selected scan groups. + remove_groups_request = MF_V3_Tasks_RemoveGroups.Request( + Index=0, + Type="RemoveGroups", + Input=Input + ) + remove_groups_response = MF_V3_Tasks_RemoveGroups.Response( + Index=0, + Type="RemoveGroups", + Output=None + ) + task = Task(Index=0, Type="RemoveGroups", Input=remove_groups_request, Output=remove_groups_response) + self.SendTask(task) + return task + + +def bounding_box(self, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool) -> Task: + # Get the bounding box of a set of scan groups. + bounding_box_request = MF_V3_Tasks_BoundingBox.Request( + Index=0, + Type="BoundingBox", + Input=MF_V3_Settings_BoundingBox_BoundingBox( + selection=selection, + axisAligned=axisAligned, + ) + ) + bounding_box_response = MF_V3_Tasks_BoundingBox.Response( + Index=0, + Type="BoundingBox", + Input=MF_V3_Settings_BoundingBox_BoundingBox( + selection=selection, + axisAligned=axisAligned, + ), + Output=None + ) + task = Task(Index=0, Type="BoundingBox", Input=bounding_box_request, Output=bounding_box_response) + self.SendTask(task) + return task + + +def align(self, source: int, target: int, rough: MF_V3_Settings_Align_Align.Rough = None, fine: MF_V3_Settings_Align_Align.Fine = None) -> Task: + # Align two scan groups. + align_request = MF_V3_Tasks_Align.Request( + Index=0, + Type="Align", + Input=MF_V3_Settings_Align_Align( + source=source, + target=target, + rough=rough, + fine=fine, + ) + ) + align_response = MF_V3_Tasks_Align.Response( + Index=0, + Type="Align", + Input=MF_V3_Settings_Align_Align( + source=source, + target=target, + rough=rough, + fine=fine, + ), + Output=None + ) + task = Task(Index=0, Type="Align", Input=align_request, Output=align_response) + self.SendTask(task) + return task + + +def merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: MF_V3_Settings_Merge_Merge.Remesh = None, simplify: MF_V3_Settings_Merge_Merge.Simplify = None, texturize: bool = None) -> Task: + # Merge two or more scan groups. + merge_request = MF_V3_Tasks_Merge.Request( + Index=0, + Type="Merge", + Input=MF_V3_Settings_Merge_Merge( + selection=selection, + remesh=remesh, + simplify=simplify, + texturize=texturize, + ) + ) + merge_response = MF_V3_Tasks_Merge.Response( + Index=0, + Type="Merge", + Input=MF_V3_Settings_Merge_Merge( + selection=selection, + remesh=remesh, + simplify=simplify, + texturize=texturize, + ), + Output=None + ) + task = Task(Index=0, Type="Merge", Input=merge_request, Output=merge_response) + self.SendTask(task) + return task + + +def merge_data(self, index: int, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None, buffers: List[MF_V3_Settings_ScanData_ScanData.Buffer] = None, metadata: List[MF_V3_Settings_ScanData_ScanData.Metadata] = None) -> Task: + # Download the raw scan data for the current merge process. + merge_data_request = MF_V3_Tasks_MergeData.Request( + Index=0, + Type="MergeData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + mergeStep=mergeStep, + buffers=buffers, + metadata=metadata, + ) + ) + merge_data_response = MF_V3_Tasks_MergeData.Response( + Index=0, + Type="MergeData", + Input=MF_V3_Settings_ScanData_ScanData( + index=index, + mergeStep=mergeStep, + buffers=buffers, + metadata=metadata, + ), + Output=None + ) + task = Task(Index=0, Type="MergeData", Input=merge_data_request, Output=merge_data_response) + self.SendTask(task) + return task + + +def add_merge_to_project(self) -> Task: + # Add a merged scan to the current project. + add_merge_to_project_request = MF_V3_Tasks_AddMergeToProject.Request( + Index=0, + Type="AddMergeToProject" + ) + add_merge_to_project_response = MF_V3_Tasks_AddMergeToProject.Response( + Index=0, + Type="AddMergeToProject", + Output=None + ) + task = Task(Index=0, Type="AddMergeToProject", Input=add_merge_to_project_request, Output=add_merge_to_project_response) + self.SendTask(task) + return task + + +def list_export_formats(self) -> Task: + # List all export formats. + list_export_formats_request = MF_V3_Tasks_ListExportFormats.Request( + Index=0, + Type="ListExportFormats" + ) + list_export_formats_response = MF_V3_Tasks_ListExportFormats.Response( + Index=0, + Type="ListExportFormats" + ) + task = Task(Index=0, Type="ListExportFormats", Input=list_export_formats_request, Output=list_export_formats_response) + self.SendTask(task) + return task + + +def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None, scale: float = None) -> Task: + # Export a group of scans. + export_request = MF_V3_Tasks_Export.Request( + Index=0, + Type="Export", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + scale=scale, + ) + ) + export_response = MF_V3_Tasks_Export.Response( + Index=0, + Type="Export", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + scale=scale, + ) + ) + task = Task(Index=0, Type="Export", Input=export_request, Output=export_response) + self.SendTask(task) + return task + + +def export_merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None, scale: float = None) -> Task: + # Export a merged scan. + export_merge_request = MF_V3_Tasks_ExportMerge.Request( + Index=0, + Type="ExportMerge", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + scale=scale, + ) + ) + export_merge_response = MF_V3_Tasks_ExportMerge.Response( + Index=0, + Type="ExportMerge", + Input=MF_V3_Settings_Export_Export( + selection=selection, + texture=texture, + merge=merge, + format=format, + scale=scale, + ) + ) + task = Task(Index=0, Type="ExportMerge", Input=export_merge_request, Output=export_merge_response) + self.SendTask(task) + return task + + +def export_logs(self, Input: bool = None) -> Task: + # Export scanner logs. + export_logs_request = MF_V3_Tasks_ExportLogs.Request( + Index=0, + Type="ExportLogs", + Input=Input + ) + export_logs_response = MF_V3_Tasks_ExportLogs.Response( + Index=0, + Type="ExportLogs" + ) + task = Task(Index=0, Type="ExportLogs", Input=export_logs_request, Output=export_logs_response) + self.SendTask(task) + return task + + +def has_cameras(self) -> Task: + # Check if the scanner has working cameras. + has_cameras_request = MF_V3_Tasks_HasCameras.Request( + Index=0, + Type="HasCameras" + ) + has_cameras_response = MF_V3_Tasks_HasCameras.Response( + Index=0, + Type="HasCameras" + ) + task = Task(Index=0, Type="HasCameras", Input=has_cameras_request, Output=has_cameras_response) + self.SendTask(task) + return task + + +def has_projector(self) -> Task: + # Check if the scanner has a working projector. + has_projector_request = MF_V3_Tasks_HasProjector.Request( + Index=0, + Type="HasProjector" + ) + has_projector_response = MF_V3_Tasks_HasProjector.Response( + Index=0, + Type="HasProjector" + ) + task = Task(Index=0, Type="HasProjector", Input=has_projector_request, Output=has_projector_response) + self.SendTask(task) + return task + + +def has_turntable(self) -> Task: + # Check if the scanner is connected to a working turntable. + has_turntable_request = MF_V3_Tasks_HasTurntable.Request( + Index=0, + Type="HasTurntable" + ) + has_turntable_response = MF_V3_Tasks_HasTurntable.Response( + Index=0, + Type="HasTurntable" + ) + task = Task(Index=0, Type="HasTurntable", Input=has_turntable_request, Output=has_turntable_response) + self.SendTask(task) + return task + + +def system_info(self, updateMajor: bool = None, updateNightly: bool = None) -> Task: + # Get system information. + system_info_request = MF_V3_Tasks_SystemInfo.Request( + Index=0, + Type="SystemInfo", + Input=MF_V3_Settings_Software_Software( + updateMajor=updateMajor, + updateNightly=updateNightly, + ) + ) + system_info_response = MF_V3_Tasks_SystemInfo.Response( + Index=0, + Type="SystemInfo", + Output=None + ) + task = Task(Index=0, Type="SystemInfo", Input=system_info_request, Output=system_info_response) + self.SendTask(task) + return task + + +def camera_calibration(self) -> Task: + # Get the camera calibration descriptor. + camera_calibration_request = MF_V3_Tasks_CameraCalibration.Request( + Index=0, + Type="CameraCalibration" + ) + camera_calibration_response = MF_V3_Tasks_CameraCalibration.Response( + Index=0, + Type="CameraCalibration" + ) + task = Task(Index=0, Type="CameraCalibration", Input=camera_calibration_request, Output=camera_calibration_response) + self.SendTask(task) + return task + + +def turntable_calibration(self) -> Task: + # Get the turntable calibration descriptor. + turntable_calibration_request = MF_V3_Tasks_TurntableCalibration.Request( + Index=0, + Type="TurntableCalibration" + ) + turntable_calibration_response = MF_V3_Tasks_TurntableCalibration.Response( + Index=0, + Type="TurntableCalibration" + ) + task = Task(Index=0, Type="TurntableCalibration", Input=turntable_calibration_request, Output=turntable_calibration_response) + self.SendTask(task) + return task + + +def calibration_capture_targets(self) -> Task: + # Get the calibration capture target for each camera calibration capture. + calibration_capture_targets_request = MF_V3_Tasks_CalibrationCaptureTargets.Request( + Index=0, + Type="CalibrationCaptureTargets" + ) + calibration_capture_targets_response = MF_V3_Tasks_CalibrationCaptureTargets.Response( + Index=0, + Type="CalibrationCaptureTargets" + ) + task = Task(Index=0, Type="CalibrationCaptureTargets", Input=calibration_capture_targets_request, Output=calibration_capture_targets_response) + self.SendTask(task) + return task + + +def calibrate_cameras(self) -> Task: + # Calibrate the cameras. + calibrate_cameras_request = MF_V3_Tasks_CalibrateCameras.Request( + Index=0, + Type="CalibrateCameras" + ) + calibrate_cameras_response = MF_V3_Tasks_CalibrateCameras.Response( + Index=0, + Type="CalibrateCameras" + ) + task = Task(Index=0, Type="CalibrateCameras", Input=calibrate_cameras_request, Output=calibrate_cameras_response) + self.SendTask(task) + return task + + +def calibrate_turntable(self) -> Task: + # Calibrate the turntable. + calibrate_turntable_request = MF_V3_Tasks_CalibrateTurntable.Request( + Index=0, + Type="CalibrateTurntable" + ) + calibrate_turntable_response = MF_V3_Tasks_CalibrateTurntable.Response( + Index=0, + Type="CalibrateTurntable" + ) + task = Task(Index=0, Type="CalibrateTurntable", Input=calibrate_turntable_request, Output=calibrate_turntable_response) + self.SendTask(task) + return task + + +def detect_calibration_card(self, Input: int) -> Task: + # Detect the calibration card on one or both cameras. + detect_calibration_card_request = MF_V3_Tasks_DetectCalibrationCard.Request( + Index=0, + Type="DetectCalibrationCard", + Input=Input + ) + detect_calibration_card_response = MF_V3_Tasks_DetectCalibrationCard.Response( + Index=0, + Type="DetectCalibrationCard", + Input=Input + ) + task = Task(Index=0, Type="DetectCalibrationCard", Input=detect_calibration_card_request, Output=detect_calibration_card_response) + self.SendTask(task) + return task + + +def restore_factory_calibration(self) -> Task: + # Restore factory calibration. + restore_factory_calibration_request = MF_V3_Tasks_RestoreFactoryCalibration.Request( + Index=0, + Type="RestoreFactoryCalibration" + ) + restore_factory_calibration_response = MF_V3_Tasks_RestoreFactoryCalibration.Response( + Index=0, + Type="RestoreFactoryCalibration" + ) + task = Task(Index=0, Type="RestoreFactoryCalibration", Input=restore_factory_calibration_request, Output=restore_factory_calibration_response) + self.SendTask(task) + return task + + +def start_video(self) -> Task: + # Start the video stream. + start_video_request = MF_V3_Tasks_StartVideo.Request( + Index=0, + Type="StartVideo" + ) + start_video_response = MF_V3_Tasks_StartVideo.Response( + Index=0, + Type="StartVideo" + ) + task = Task(Index=0, Type="StartVideo", Input=start_video_request, Output=start_video_response) + self.SendTask(task) + return task + + +def stop_video(self) -> Task: + # Stop the video stream. + stop_video_request = MF_V3_Tasks_StopVideo.Request( + Index=0, + Type="StopVideo" + ) + stop_video_response = MF_V3_Tasks_StopVideo.Response( + Index=0, + Type="StopVideo" + ) + task = Task(Index=0, Type="StopVideo", Input=stop_video_request, Output=stop_video_response) + self.SendTask(task) + return task + + +def set_cameras(self, selection: List[int] = None, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> Task: + # Apply camera settings to one or both cameras. + set_cameras_request = MF_V3_Tasks_SetCameras.Request( + Index=0, + Type="SetCameras", + Input=MF_V3_Settings_Camera_Camera( + selection=selection, + autoExposure=autoExposure, + exposure=exposure, + analogGain=analogGain, + digitalGain=digitalGain, + focus=focus, + ) + ) + set_cameras_response = MF_V3_Tasks_SetCameras.Response( + Index=0, + Type="SetCameras" + ) + task = Task(Index=0, Type="SetCameras", Input=set_cameras_request, Output=set_cameras_response) + self.SendTask(task) + return task + + +def set_projector(self, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None, color: List[float] = None, buffer: bytes = None) -> Task: + # Apply projector settings. + set_projector_request = MF_V3_Tasks_SetProjector.Request( + Index=0, + Type="SetProjector", + Input=MF_V3_Settings_Projector_Projector( + on=on, + brightness=brightness, + pattern=pattern, + image=image, + color=color, + ) + ) + set_projector_response = MF_V3_Tasks_SetProjector.Response( + Index=0, + Type="SetProjector" + ) + task = Task(Index=0, Type="SetProjector", Input=set_projector_request, Output=set_projector_response) + self.SendTask(task, buffer) + return task + + +def auto_focus(self, applyAll: bool, cameras: List[MF_V3_Settings_AutoFocus_AutoFocus.Camera] = None) -> Task: + # Auto focus one or both cameras. + auto_focus_request = MF_V3_Tasks_AutoFocus.Request( + Index=0, + Type="AutoFocus", + Input=MF_V3_Settings_AutoFocus_AutoFocus( + applyAll=applyAll, + cameras=cameras, + ) + ) + auto_focus_response = MF_V3_Tasks_AutoFocus.Response( + Index=0, + Type="AutoFocus" + ) + task = Task(Index=0, Type="AutoFocus", Input=auto_focus_request, Output=auto_focus_response) + self.SendTask(task) + return task + + +def rotate_turntable(self, Input: int) -> Task: + # Rotate the turntable. + rotate_turntable_request = MF_V3_Tasks_RotateTurntable.Request( + Index=0, + Type="RotateTurntable", + Input=Input + ) + rotate_turntable_response = MF_V3_Tasks_RotateTurntable.Response( + Index=0, + Type="RotateTurntable", + Input=Input + ) + task = Task(Index=0, Type="RotateTurntable", Input=rotate_turntable_request, Output=rotate_turntable_response) + self.SendTask(task) + return task + + +def new_scan(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: + # Capture a new scan. + new_scan_request = MF_V3_Tasks_NewScan.Request( + Index=0, + Type="NewScan", + Input=MF_V3_Settings_Scan_Scan( + camera=camera, + projector=projector, + turntable=turntable, + capture=capture, + processing=processing, + ) + ) + new_scan_response = MF_V3_Tasks_NewScan.Response( + Index=0, + Type="NewScan" + ) + task = Task(Index=0, Type="NewScan", Input=new_scan_request, Output=new_scan_response) + self.SendTask(task) + return task + + +def depth_map(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: + # Capture a depth map. + depth_map_request = MF_V3_Tasks_DepthMap.Request( + Index=0, + Type="DepthMap", + Input=MF_V3_Settings_Scan_Scan( + camera=camera, + projector=projector, + turntable=turntable, + capture=capture, + processing=processing, + ) + ) + depth_map_response = MF_V3_Tasks_DepthMap.Response( + Index=0, + Type="DepthMap" + ) + task = Task(Index=0, Type="DepthMap", Input=depth_map_request, Output=depth_map_response) + self.SendTask(task) + return task + + +def reboot(self) -> Task: + # Reboot the scanner. + reboot_request = MF_V3_Tasks_Reboot.Request( + Index=0, + Type="Reboot" + ) + reboot_response = MF_V3_Tasks_Reboot.Response( + Index=0, + Type="Reboot" + ) + task = Task(Index=0, Type="Reboot", Input=reboot_request, Output=reboot_response) + self.SendTask(task) + return task + + +def shutdown(self) -> Task: + # Shutdown the scanner. + shutdown_request = MF_V3_Tasks_Shutdown.Request( + Index=0, + Type="Shutdown" + ) + shutdown_response = MF_V3_Tasks_Shutdown.Response( + Index=0, + Type="Shutdown" + ) + task = Task(Index=0, Type="Shutdown", Input=shutdown_request, Output=shutdown_response) + self.SendTask(task) + return task + + + + diff --git a/three/MF/V3/__init__.py b/three/MF/V3/__init__.py new file mode 100644 index 0000000..2bcc874 --- /dev/null +++ b/three/MF/V3/__init__.py @@ -0,0 +1,3 @@ +from MF.V3.Buffer import * +from MF.V3.Task import * +from MF.V3.Three import * diff --git a/maf_three/__init__.py b/three/__init__.py similarity index 100% rename from maf_three/__init__.py rename to three/__init__.py diff --git a/maf_three/examples/__main__.py b/three/examples/__main__.py similarity index 83% rename from maf_three/examples/__main__.py rename to three/examples/__main__.py index 3301487..fe1d98e 100644 --- a/maf_three/examples/__main__.py +++ b/three/examples/__main__.py @@ -2,7 +2,7 @@ import sys -from maf_three.examples import connection, projector, turntable, task, turntableCalibration, simpleScanner +from three.examples import connection, projector, turntable, task, turntableCalibration, simpleScanner # Available examples dictionary examples = { @@ -20,7 +20,7 @@ def PrintExampleList(): for ex in examples: print(' *',ex) print('Run via:') - print('python3 -m maf_three.examples {example_name}') + print('python3 -m three.examples {example_name}') # No argument provided ? if len(sys.argv) == 1: diff --git a/maf_three/examples/connection.py b/three/examples/connection.py similarity index 91% rename from maf_three/examples/connection.py rename to three/examples/connection.py index db47015..cf91d41 100644 --- a/maf_three/examples/connection.py +++ b/three/examples/connection.py @@ -1,6 +1,6 @@ # Connection -from maf_three.scanner import Scanner +from three.scanner import Scanner def main(): try: diff --git a/maf_three/examples/projector.py b/three/examples/projector.py similarity index 87% rename from maf_three/examples/projector.py rename to three/examples/projector.py index 8916b96..f49b7c1 100644 --- a/maf_three/examples/projector.py +++ b/three/examples/projector.py @@ -5,14 +5,14 @@ import time import numpy as np -# from maf_three.scanner import Scanner +# from three.scanner import Scanner sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) -from maf_three.scanner import Scanner -import maf_three.MF.V3.Three as Three -from maf_three.MF.V3.Settings.Projector import Projector -from maf_three.MF.V3.Settings.Video import Video -from maf_three.MF.V3.Settings.Rectangle import Rectangle +from three.scanner import Scanner +import three.MF.V3.Three as Three +from three.MF.V3.Settings.Projector import Projector +from three.MF.V3.Settings.Video import Video +from three.MF.V3.Settings.Rectangle import Rectangle def main(): @@ -50,7 +50,7 @@ def main(): ### Project an image print('Project Image') - width = 512 + width = 856 height = 480 img = np.zeros([height, width, 3], np.uint8) for y in range(height): diff --git a/maf_three/examples/simpleScanner.py b/three/examples/simpleScanner.py similarity index 95% rename from maf_three/examples/simpleScanner.py rename to three/examples/simpleScanner.py index 63ab33a..e4917d5 100644 --- a/maf_three/examples/simpleScanner.py +++ b/three/examples/simpleScanner.py @@ -5,12 +5,12 @@ from typing import List # Three library -from maf_three.scanner import Scanner -from maf_three.MF.V3.Settings import Capture, Camera, Projector, Turntable, ScanSelection, Export, Quality -from maf_three.MF.V3.Descriptors import Project -from maf_three.MF.V3.Descriptors.Settings import Scanner as ScannerDescriptor, Camera as CameraDescriptor, Projector as ProjectorDescriptor, Turntable as TurntableDescriptor, Capture as CaptureDescriptor +from three.scanner import Scanner +from three.MF.V3.Settings import Capture, Camera, Projector, Turntable, ScanSelection, Export, Quality +from three.MF.V3.Descriptors import Project +from three.MF.V3.Descriptors.Settings import Scanner as ScannerDescriptor, Camera as CameraDescriptor, Projector as ProjectorDescriptor, Turntable as TurntableDescriptor, Capture as CaptureDescriptor -from maf_three.MF.V3 import Task, TaskState +from three.MF.V3 import Task, TaskState # Two frames for the video stream frame0 = np.zeros((0,0,3), np.uint8) frame1 = np.zeros((0,0,3), np.uint8) diff --git a/maf_three/examples/task.py b/three/examples/task.py similarity index 90% rename from maf_three/examples/task.py rename to three/examples/task.py index 703a69b..512842d 100644 --- a/maf_three/examples/task.py +++ b/three/examples/task.py @@ -2,10 +2,10 @@ from typing import List # Three library -from maf_three.scanner import Scanner -from maf_three.MF.V3.Settings import Capture, Camera, Projector -from maf_three.MF.V3.Descriptors import Project -from maf_three.MF.V3 import Task, TaskState +from three.scanner import Scanner +from three.MF.V3.Settings import Capture, Camera, Projector +from three.MF.V3.Descriptors import Project +from three.MF.V3 import Task, TaskState done = False diff --git a/maf_three/examples/turntableCalibration.py b/three/examples/turntableCalibration.py similarity index 89% rename from maf_three/examples/turntableCalibration.py rename to three/examples/turntableCalibration.py index 399009a..132e0b5 100644 --- a/maf_three/examples/turntableCalibration.py +++ b/three/examples/turntableCalibration.py @@ -2,12 +2,12 @@ import time # Three library -from maf_three.scanner import Scanner -from maf_three.MF.V3.Settings import Capture, Camera, Projector, Turntable, ScanSelection, Export, Quality -from maf_three.MF.V3.Descriptors import Calibration -from maf_three.MF.V3.Descriptors.Settings import Scanner as ScannerDescriptor, Camera as CameraDescriptor, Projector as ProjectorDescriptor, Turntable as TurntableDescriptor, Capture as CaptureDescriptor +from three.scanner import Scanner +from three.MF.V3.Settings import Capture, Camera, Projector, Turntable, ScanSelection, Export, Quality +from three.MF.V3.Descriptors import Calibration +from three.MF.V3.Descriptors.Settings import Scanner as ScannerDescriptor, Camera as CameraDescriptor, Projector as ProjectorDescriptor, Turntable as TurntableDescriptor, Capture as CaptureDescriptor -from maf_three.MF.V3 import Task, TaskState +from three.MF.V3 import Task, TaskState done = False diff --git a/maf_three/scanner.py b/three/scanner.py similarity index 98% rename from maf_three/scanner.py rename to three/scanner.py index 8fa7134..6e1922b 100644 --- a/maf_three/scanner.py +++ b/three/scanner.py @@ -1,4 +1,4 @@ -## @package maf_three +## @package three # @file scanner.py # @brief Scanner class to wrap websocket connection # @date 2024-04-22 @@ -16,11 +16,11 @@ from MF.V3 import Task, TaskState, Buffer -from maf_three import __version__ -from maf_three.serialization import TO_JSON -from maf_three.MF.V3.Buffer import Buffer +from three import __version__ +from three.serialization import TO_JSON +from three.MF.V3.Buffer import Buffer -import maf_three.MF.V3.Three as Three +import three.MF.V3.Three as Three class Scanner: """ diff --git a/maf_three/scanner.pyi b/three/scanner.pyi similarity index 98% rename from maf_three/scanner.pyi rename to three/scanner.pyi index 68f442e..e1dcbbd 100644 --- a/maf_three/scanner.pyi +++ b/three/scanner.pyi @@ -84,13 +84,13 @@ import MF.V3.Tasks.UploadProject import importlib import inspect import json -import maf_three -import maf_three.MF -import maf_three.MF.V3 -import maf_three.MF.V3.Buffer -import maf_three.MF.V3.Three -import maf_three.serialization import threading +import three +import three.MF +import three.MF.V3 +import three.MF.V3.Buffer +import three.MF.V3.Three +import three.serialization import time import types import typing diff --git a/maf_three/serialization.py b/three/serialization.py similarity index 100% rename from maf_three/serialization.py rename to three/serialization.py diff --git a/maf_three/setup.py b/three/setup.py similarity index 85% rename from maf_three/setup.py rename to three/setup.py index f55da86..bfb56cb 100644 --- a/maf_three/setup.py +++ b/three/setup.py @@ -1,9 +1,9 @@ from setuptools import setup, find_packages import os -# Function to read the version from maf_three/__init__.py +# Function to read the version from three/__init__.py def get_version(): - version_file = os.path.join('maf_three', '__init__.py') + version_file = os.path.join('three', '__init__.py') with open(version_file, 'r') as f: exec(f.read(), globals()) return __version__ @@ -17,7 +17,7 @@ def get_version(): long_description = f.read() setup( - name='maf_three', + name='three', version=get_version(), description='Matter and Form - THREE - Library', long_description=long_description, @@ -35,7 +35,7 @@ def get_version(): ], entry_points={ 'console_scripts': [ - 'examples=maf_three.examples:main_cli', + 'examples=three.examples:main_cli', ], }, ) \ No newline at end of file diff --git a/maf_three/tests/test_proto_camera.py b/three/tests/test_proto_camera.py similarity index 100% rename from maf_three/tests/test_proto_camera.py rename to three/tests/test_proto_camera.py diff --git a/maf_three/tests/test_proto_turntable.py b/three/tests/test_proto_turntable.py similarity index 100% rename from maf_three/tests/test_proto_turntable.py rename to three/tests/test_proto_turntable.py From a4c2567149177893fc6f3a4ef72b1ed8e9133e87 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 21 Nov 2024 20:25:33 -0500 Subject: [PATCH 82/86] removed old maf_three --- maf_three/MF/V3/Buffer.py | 66 - maf_three/MF/V3/Descriptors/BoundingBox.py | 24 - maf_three/MF/V3/Descriptors/Calibration.py | 79 -- maf_three/MF/V3/Descriptors/Export.py | 38 - maf_three/MF/V3/Descriptors/Image.py | 13 - maf_three/MF/V3/Descriptors/Merge.py | 34 - maf_three/MF/V3/Descriptors/Network.py | 11 - maf_three/MF/V3/Descriptors/Project.py | 47 - maf_three/MF/V3/Descriptors/ProjectActions.py | 37 - maf_three/MF/V3/Descriptors/RemoveVertices.py | 26 - maf_three/MF/V3/Descriptors/ScanData.py | 53 - .../MF/V3/Descriptors/Settings/Advanced.py | 284 ---- .../MF/V3/Descriptors/Settings/Camera.py | 71 - .../MF/V3/Descriptors/Settings/Capture.py | 46 - maf_three/MF/V3/Descriptors/Settings/I18n.py | 16 - .../MF/V3/Descriptors/Settings/Projector.py | 23 - .../MF/V3/Descriptors/Settings/Scanner.py | 37 - .../MF/V3/Descriptors/Settings/Software.py | 13 - maf_three/MF/V3/Descriptors/Settings/Style.py | 16 - .../MF/V3/Descriptors/Settings/Turntable.py | 33 - .../MF/V3/Descriptors/Settings/Tutorials.py | 30 - .../MF/V3/Descriptors/Settings/Viewer.py | 15 - .../MF/V3/Descriptors/Settings/__init__.py | 11 - maf_three/MF/V3/Descriptors/Software.py | 19 - maf_three/MF/V3/Descriptors/System.py | 19 - maf_three/MF/V3/Descriptors/Transform.py | 16 - maf_three/MF/V3/Descriptors/VideoFrame.py | 27 - maf_three/MF/V3/Descriptors/Wifi.py | 26 - maf_three/MF/V3/Descriptors/__init__.py | 13 - maf_three/MF/V3/Settings/Advanced.py | 185 --- maf_three/MF/V3/Settings/Align.py | 82 -- maf_three/MF/V3/Settings/AutoFocus.py | 24 - maf_three/MF/V3/Settings/BoundingBox.py | 15 - maf_three/MF/V3/Settings/Camera.py | 20 - maf_three/MF/V3/Settings/Capture.py | 25 - maf_three/MF/V3/Settings/CopyGroup.py | 25 - maf_three/MF/V3/Settings/CopyProject.py | 9 - maf_three/MF/V3/Settings/Export.py | 29 - maf_three/MF/V3/Settings/Group.py | 26 - maf_three/MF/V3/Settings/I18n.py | 16 - maf_three/MF/V3/Settings/Merge.py | 85 -- maf_three/MF/V3/Settings/NewGroup.py | 32 - maf_three/MF/V3/Settings/Project.py | 10 - maf_three/MF/V3/Settings/Projector.py | 58 - maf_three/MF/V3/Settings/Quality.py | 10 - maf_three/MF/V3/Settings/Rectangle.py | 13 - maf_three/MF/V3/Settings/Remesh.py | 36 - maf_three/MF/V3/Settings/RemoveVertices.py | 10 - maf_three/MF/V3/Settings/Scan.py | 157 --- maf_three/MF/V3/Settings/ScanData.py | 40 - maf_three/MF/V3/Settings/ScanSelection.py | 22 - maf_three/MF/V3/Settings/Scanner.py | 37 - maf_three/MF/V3/Settings/Software.py | 9 - maf_three/MF/V3/Settings/Style.py | 15 - maf_three/MF/V3/Settings/Turntable.py | 11 - maf_three/MF/V3/Settings/Tutorials.py | 18 - maf_three/MF/V3/Settings/Video.py | 31 - maf_three/MF/V3/Settings/Viewer.py | 7 - maf_three/MF/V3/Settings/Wifi.py | 9 - maf_three/MF/V3/Settings/__init__.py | 30 - maf_three/MF/V3/Task.py | 89 -- maf_three/MF/V3/Tasks/AddMergeToProject.py | 66 - maf_three/MF/V3/Tasks/Align.py | 77 -- maf_three/MF/V3/Tasks/AutoFocus.py | 94 -- maf_three/MF/V3/Tasks/BoundingBox.py | 82 -- maf_three/MF/V3/Tasks/CalibrateCameras.py | 58 - maf_three/MF/V3/Tasks/CalibrateTurntable.py | 61 - .../MF/V3/Tasks/CalibrationCaptureTargets.py | 66 - maf_three/MF/V3/Tasks/CameraCalibration.py | 60 - maf_three/MF/V3/Tasks/CloseProject.py | 53 - maf_three/MF/V3/Tasks/ConnectWifi.py | 67 - maf_three/MF/V3/Tasks/DepthMap.py | 141 -- .../MF/V3/Tasks/DetectCalibrationCard.py | 65 - maf_three/MF/V3/Tasks/DownloadProject.py | 89 -- maf_three/MF/V3/Tasks/Export.py | 103 -- maf_three/MF/V3/Tasks/ExportLogs.py | 87 -- maf_three/MF/V3/Tasks/ExportMerge.py | 97 -- maf_three/MF/V3/Tasks/FlattenGroup.py | 72 - maf_three/MF/V3/Tasks/ForgetWifi.py | 53 - maf_three/MF/V3/Tasks/HasCameras.py | 56 - maf_three/MF/V3/Tasks/HasProjector.py | 56 - maf_three/MF/V3/Tasks/HasTurntable.py | 56 - maf_three/MF/V3/Tasks/ListExportFormats.py | 86 -- maf_three/MF/V3/Tasks/ListGroups.py | 85 -- .../MF/V3/Tasks/ListNetworkInterfaces.py | 61 - maf_three/MF/V3/Tasks/ListProjects.py | 61 - maf_three/MF/V3/Tasks/ListScans.py | 77 -- maf_three/MF/V3/Tasks/ListSettings.py | 86 -- maf_three/MF/V3/Tasks/ListWifi.py | 64 - maf_three/MF/V3/Tasks/Merge.py | 104 -- maf_three/MF/V3/Tasks/MergeData.py | 239 ---- maf_three/MF/V3/Tasks/MoveGroup.py | 79 -- maf_three/MF/V3/Tasks/NewGroup.py | 77 -- maf_three/MF/V3/Tasks/NewProject.py | 69 - maf_three/MF/V3/Tasks/NewScan.py | 82 -- maf_three/MF/V3/Tasks/OpenProject.py | 66 - maf_three/MF/V3/Tasks/PopSettings.py | 92 -- maf_three/MF/V3/Tasks/PushSettings.py | 86 -- maf_three/MF/V3/Tasks/Reboot.py | 53 - maf_three/MF/V3/Tasks/RemoveGroups.py | 64 - maf_three/MF/V3/Tasks/RemoveProjects.py | 68 - .../MF/V3/Tasks/RestoreFactoryCalibration.py | 53 - maf_three/MF/V3/Tasks/RotateTurntable.py | 59 - maf_three/MF/V3/Tasks/ScanData.py | 239 ---- maf_three/MF/V3/Tasks/SetCameras.py | 76 -- maf_three/MF/V3/Tasks/SetGroup.py | 104 -- maf_three/MF/V3/Tasks/SetProject.py | 80 -- maf_three/MF/V3/Tasks/SetProjector.py | 75 -- maf_three/MF/V3/Tasks/Shutdown.py | 53 - maf_three/MF/V3/Tasks/SplitGroup.py | 74 -- maf_three/MF/V3/Tasks/StartVideo.py | 64 - maf_three/MF/V3/Tasks/StopVideo.py | 53 - maf_three/MF/V3/Tasks/SystemInfo.py | 92 -- maf_three/MF/V3/Tasks/TransformGroup.py | 81 -- maf_three/MF/V3/Tasks/TurntableCalibration.py | 61 - maf_three/MF/V3/Tasks/UpdateSettings.py | 105 -- maf_three/MF/V3/Tasks/UploadProject.py | 79 -- maf_three/MF/V3/Tasks/__init__.py | 56 - maf_three/MF/V3/Three.py | 1160 ----------------- maf_three/MF/V3/__init__.py | 3 - 120 files changed, 8053 deletions(-) delete mode 100644 maf_three/MF/V3/Buffer.py delete mode 100644 maf_three/MF/V3/Descriptors/BoundingBox.py delete mode 100644 maf_three/MF/V3/Descriptors/Calibration.py delete mode 100644 maf_three/MF/V3/Descriptors/Export.py delete mode 100644 maf_three/MF/V3/Descriptors/Image.py delete mode 100644 maf_three/MF/V3/Descriptors/Merge.py delete mode 100644 maf_three/MF/V3/Descriptors/Network.py delete mode 100644 maf_three/MF/V3/Descriptors/Project.py delete mode 100644 maf_three/MF/V3/Descriptors/ProjectActions.py delete mode 100644 maf_three/MF/V3/Descriptors/RemoveVertices.py delete mode 100644 maf_three/MF/V3/Descriptors/ScanData.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/Advanced.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/Camera.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/Capture.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/I18n.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/Projector.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/Scanner.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/Software.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/Style.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/Turntable.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/Tutorials.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/Viewer.py delete mode 100644 maf_three/MF/V3/Descriptors/Settings/__init__.py delete mode 100644 maf_three/MF/V3/Descriptors/Software.py delete mode 100644 maf_three/MF/V3/Descriptors/System.py delete mode 100644 maf_three/MF/V3/Descriptors/Transform.py delete mode 100644 maf_three/MF/V3/Descriptors/VideoFrame.py delete mode 100644 maf_three/MF/V3/Descriptors/Wifi.py delete mode 100644 maf_three/MF/V3/Descriptors/__init__.py delete mode 100644 maf_three/MF/V3/Settings/Advanced.py delete mode 100644 maf_three/MF/V3/Settings/Align.py delete mode 100644 maf_three/MF/V3/Settings/AutoFocus.py delete mode 100644 maf_three/MF/V3/Settings/BoundingBox.py delete mode 100644 maf_three/MF/V3/Settings/Camera.py delete mode 100644 maf_three/MF/V3/Settings/Capture.py delete mode 100644 maf_three/MF/V3/Settings/CopyGroup.py delete mode 100644 maf_three/MF/V3/Settings/CopyProject.py delete mode 100644 maf_three/MF/V3/Settings/Export.py delete mode 100644 maf_three/MF/V3/Settings/Group.py delete mode 100644 maf_three/MF/V3/Settings/I18n.py delete mode 100644 maf_three/MF/V3/Settings/Merge.py delete mode 100644 maf_three/MF/V3/Settings/NewGroup.py delete mode 100644 maf_three/MF/V3/Settings/Project.py delete mode 100644 maf_three/MF/V3/Settings/Projector.py delete mode 100644 maf_three/MF/V3/Settings/Quality.py delete mode 100644 maf_three/MF/V3/Settings/Rectangle.py delete mode 100644 maf_three/MF/V3/Settings/Remesh.py delete mode 100644 maf_three/MF/V3/Settings/RemoveVertices.py delete mode 100644 maf_three/MF/V3/Settings/Scan.py delete mode 100644 maf_three/MF/V3/Settings/ScanData.py delete mode 100644 maf_three/MF/V3/Settings/ScanSelection.py delete mode 100644 maf_three/MF/V3/Settings/Scanner.py delete mode 100644 maf_three/MF/V3/Settings/Software.py delete mode 100644 maf_three/MF/V3/Settings/Style.py delete mode 100644 maf_three/MF/V3/Settings/Turntable.py delete mode 100644 maf_three/MF/V3/Settings/Tutorials.py delete mode 100644 maf_three/MF/V3/Settings/Video.py delete mode 100644 maf_three/MF/V3/Settings/Viewer.py delete mode 100644 maf_three/MF/V3/Settings/Wifi.py delete mode 100644 maf_three/MF/V3/Settings/__init__.py delete mode 100644 maf_three/MF/V3/Task.py delete mode 100644 maf_three/MF/V3/Tasks/AddMergeToProject.py delete mode 100644 maf_three/MF/V3/Tasks/Align.py delete mode 100644 maf_three/MF/V3/Tasks/AutoFocus.py delete mode 100644 maf_three/MF/V3/Tasks/BoundingBox.py delete mode 100644 maf_three/MF/V3/Tasks/CalibrateCameras.py delete mode 100644 maf_three/MF/V3/Tasks/CalibrateTurntable.py delete mode 100644 maf_three/MF/V3/Tasks/CalibrationCaptureTargets.py delete mode 100644 maf_three/MF/V3/Tasks/CameraCalibration.py delete mode 100644 maf_three/MF/V3/Tasks/CloseProject.py delete mode 100644 maf_three/MF/V3/Tasks/ConnectWifi.py delete mode 100644 maf_three/MF/V3/Tasks/DepthMap.py delete mode 100644 maf_three/MF/V3/Tasks/DetectCalibrationCard.py delete mode 100644 maf_three/MF/V3/Tasks/DownloadProject.py delete mode 100644 maf_three/MF/V3/Tasks/Export.py delete mode 100644 maf_three/MF/V3/Tasks/ExportLogs.py delete mode 100644 maf_three/MF/V3/Tasks/ExportMerge.py delete mode 100644 maf_three/MF/V3/Tasks/FlattenGroup.py delete mode 100644 maf_three/MF/V3/Tasks/ForgetWifi.py delete mode 100644 maf_three/MF/V3/Tasks/HasCameras.py delete mode 100644 maf_three/MF/V3/Tasks/HasProjector.py delete mode 100644 maf_three/MF/V3/Tasks/HasTurntable.py delete mode 100644 maf_three/MF/V3/Tasks/ListExportFormats.py delete mode 100644 maf_three/MF/V3/Tasks/ListGroups.py delete mode 100644 maf_three/MF/V3/Tasks/ListNetworkInterfaces.py delete mode 100644 maf_three/MF/V3/Tasks/ListProjects.py delete mode 100644 maf_three/MF/V3/Tasks/ListScans.py delete mode 100644 maf_three/MF/V3/Tasks/ListSettings.py delete mode 100644 maf_three/MF/V3/Tasks/ListWifi.py delete mode 100644 maf_three/MF/V3/Tasks/Merge.py delete mode 100644 maf_three/MF/V3/Tasks/MergeData.py delete mode 100644 maf_three/MF/V3/Tasks/MoveGroup.py delete mode 100644 maf_three/MF/V3/Tasks/NewGroup.py delete mode 100644 maf_three/MF/V3/Tasks/NewProject.py delete mode 100644 maf_three/MF/V3/Tasks/NewScan.py delete mode 100644 maf_three/MF/V3/Tasks/OpenProject.py delete mode 100644 maf_three/MF/V3/Tasks/PopSettings.py delete mode 100644 maf_three/MF/V3/Tasks/PushSettings.py delete mode 100644 maf_three/MF/V3/Tasks/Reboot.py delete mode 100644 maf_three/MF/V3/Tasks/RemoveGroups.py delete mode 100644 maf_three/MF/V3/Tasks/RemoveProjects.py delete mode 100644 maf_three/MF/V3/Tasks/RestoreFactoryCalibration.py delete mode 100644 maf_three/MF/V3/Tasks/RotateTurntable.py delete mode 100644 maf_three/MF/V3/Tasks/ScanData.py delete mode 100644 maf_three/MF/V3/Tasks/SetCameras.py delete mode 100644 maf_three/MF/V3/Tasks/SetGroup.py delete mode 100644 maf_three/MF/V3/Tasks/SetProject.py delete mode 100644 maf_three/MF/V3/Tasks/SetProjector.py delete mode 100644 maf_three/MF/V3/Tasks/Shutdown.py delete mode 100644 maf_three/MF/V3/Tasks/SplitGroup.py delete mode 100644 maf_three/MF/V3/Tasks/StartVideo.py delete mode 100644 maf_three/MF/V3/Tasks/StopVideo.py delete mode 100644 maf_three/MF/V3/Tasks/SystemInfo.py delete mode 100644 maf_three/MF/V3/Tasks/TransformGroup.py delete mode 100644 maf_three/MF/V3/Tasks/TurntableCalibration.py delete mode 100644 maf_three/MF/V3/Tasks/UpdateSettings.py delete mode 100644 maf_three/MF/V3/Tasks/UploadProject.py delete mode 100644 maf_three/MF/V3/Tasks/__init__.py delete mode 100644 maf_three/MF/V3/Three.py delete mode 100644 maf_three/MF/V3/__init__.py diff --git a/maf_three/MF/V3/Buffer.py b/maf_three/MF/V3/Buffer.py deleted file mode 100644 index 9927532..0000000 --- a/maf_three/MF/V3/Buffer.py +++ /dev/null @@ -1,66 +0,0 @@ -from MF.V3.Task import Task as MF_V3_Task_Task -from google.protobuf import any_pb2 as _any_pb2 - - -class Buffer: - """* - Generic buffer message for the Three Scanner. - - Some tasks require the server and/or client to transfer binary data. In such cases the _buffer message_ is sent to inform the server/client what the data is and what task it belongs to. The binary data it refers to is sent immediately following the buffer message. - - For example, `DownloadProject` requires the server to transfer a ZIP file containing the project data to the client. - - > First, the client sends the task request to the server: - - ```json - { - "Task":{ - "Index":1, - "Type":"DownloadProject", - "Input":5 - } - } - ``` - - > The server sends the buffer message telling the client to expect a binary data transfer and what to do with it. Note that the buffer message `Task` field echoes the task request, making it clear which request this data is a response to. - - ```json - { - "Buffer":{ - "Descriptor":"Project-5.zip", - "Index":0, - "Size":15682096, - "Task":{ - "Index":1, - "Type":"DownloadProject", - "Input":5 - } - } - } - ``` - - > The server then sends the 15682096 byte data buffer of the project ZIP file. - > Finally, the server sends a task completion message. - - ```json - { - "Task":{ - "Index":1, - "Type":"DownloadProject" - "Input":5, - "State":"Completed" - } - } - ``` - """ - def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: _any_pb2 = None): - # The zero-based index identifying the data buffer. - self.Index = Index - # The size of the incoming data buffer in bytes. - self.Size = Size - # The task associated with the data buffer. This informs the client which request this data buffer corresponds to. - self.Task = Task - # Optional data buffer descriptor. See each task definition for details. - self.Descriptor = Descriptor - - diff --git a/maf_three/MF/V3/Descriptors/BoundingBox.py b/maf_three/MF/V3/Descriptors/BoundingBox.py deleted file mode 100644 index c7652ec..0000000 --- a/maf_three/MF/V3/Descriptors/BoundingBox.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import List - - -class BoundingBox: - # BoundingBox descriptor. - def __init__(self, center: List[float] = None, size: List[float] = None, rotation: List[float] = None, transform: List[float] = None): - # The center of the bounding box. - self.center = center - # The size of the bounding box. - self.size = size - """ - The 3x3 rotation matrix of the bounding box. - The first, second and third column vectors are the x, y and z axes of the bounding box. - """ - self.rotation = rotation - """ - The 4x4 matrix that transforms the canonical cube with corners [±1, ±1, ±1] to the - bounding box in world coordinates. - The transform can be used as the model matrix for rendering the bounding box with an - OpenGL shader. - """ - self.transform = transform - - diff --git a/maf_three/MF/V3/Descriptors/Calibration.py b/maf_three/MF/V3/Descriptors/Calibration.py deleted file mode 100644 index 3df31dc..0000000 --- a/maf_three/MF/V3/Descriptors/Calibration.py +++ /dev/null @@ -1,79 +0,0 @@ -from enum import Enum -from typing import List - - -# Calibration quality. -class Quality(Enum): - Empty = "None" # The calibration does not exist. - Poor = "Poor" # Poor calibration quality. - Fair = "Fair" # Fair calibration quality. - Good = "Good" # Good calibration quality. - Excellent = "Excellent" # Excellent calibration quality. - - -class Camera: - # Camera calibration descriptor. - def __init__(self, quality: 'Quality', date: List[int] = None): - # Calibration quality. - self.quality = quality - # Calibration date and time [year, month, day, hour, minute, second]. - self.date = date - - -class Turntable: - # Turntable calibration descriptor. - def __init__(self, quality: 'Quality', date: List[int] = None, focus: List[int] = None): - # Calibration quality. - self.quality = quality - # Calibration date and time [year, month, day, hour, minute, second]. - self.date = date - # Focus values of each camera during calibration. - self.focus = focus - - -class CaptureTarget: - """ - Calibration capture target. - - The camera calibration capture targets are used to draw quad overlays on the video stream to guide a user as to where to position the calibration card for each capture during camera calibration. - """ - def __init__(self, camera: int, quads: List[float] = None): - # Index of the camera that is displayed to the user for this capture. - self.camera = camera - """ - The target quad for each camera. - This is a set of 16 numbers defining the quad coordinates on the left and right camera. - The first 4 pairs of numbers define the quad on the left camera. - The last 4 pairs of numbers define the quad on the right camera. - """ - self.quads = quads - - -class DetectedCard: - # Detected calibration card descriptor. - class Target: - # Calibration capture target properties. - def __init__(self, match: float, hold: float): - """ - A normalized value indicating how closely the calibration card matches the target - overlay. 0 indicates a poor match. 1 indicates a good match. - """ - self.match = match - """ - A normalized value indicating how long the user has held the calibration card steady over - the target overlay. When the value reaches 1, the user has held the calibration card - steady for the complete required duration. - """ - self.hold = hold - - def __init__(self, size: List[int] = None, quad: List[float] = None, corners: List[float] = None, target: 'Target' = None): - # The calibration card columns and rows. - self.size = size - # The calibration card bounding quadrilateral. - self.quad = quad - # The detected corners of the calibration card. - self.corners = corners - # The capture target properties, if a capture target is specified. - self.target = target - - diff --git a/maf_three/MF/V3/Descriptors/Export.py b/maf_three/MF/V3/Descriptors/Export.py deleted file mode 100644 index 258340c..0000000 --- a/maf_three/MF/V3/Descriptors/Export.py +++ /dev/null @@ -1,38 +0,0 @@ -from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export -from enum import Enum -from typing import List - - -class Export: - # Scan data descriptor. - # Geometry face types. - class Face(Enum): - NoFace = "NoFace" # No faces. - Point = "Point" # Point faces. - Line = "Line" # Line faces. - Triangle = "Triangle" # Triangle faces. - Quad = "Quad" # Quad faces. - - # Texture support types. - class Texture(Enum): - Empty = "None" # The format does not support textures. - Single = "Single" # The format supports a single texture only. - Multiple = "Multiple" # The format supports multiple textures. - - def __init__(self, format: MF_V3_Settings_Export_Export.Format, extension: str, description: str, normals: bool, colors: bool, textures: 'Texture', faces: List['Face'] = None): - # Export format. - self.format = format - # Export file extension. e.g. ".ply" - self.extension = extension - # Export format description. e.g. "Polygon format" - self.description = description - # Vertex normal support. - self.normals = normals - # Vertex color support. - self.colors = colors - # Texture (UV) support. - self.textures = textures - # Types of supported faces. - self.faces = faces - - diff --git a/maf_three/MF/V3/Descriptors/Image.py b/maf_three/MF/V3/Descriptors/Image.py deleted file mode 100644 index 1e830d4..0000000 --- a/maf_three/MF/V3/Descriptors/Image.py +++ /dev/null @@ -1,13 +0,0 @@ -class Image: - # Image descriptor. - def __init__(self, width: int, height: int, step: int, type: int): - # Image width. - self.width = width - # Image height. - self.height = height - # Image row step in bytes. - self.step = step - # OpenCV image [type](https:gist.github.com/yangcha/38f2fa630e223a8546f9b48ebbb3e61a). - self.type = type - - diff --git a/maf_three/MF/V3/Descriptors/Merge.py b/maf_three/MF/V3/Descriptors/Merge.py deleted file mode 100644 index 2ebdd84..0000000 --- a/maf_three/MF/V3/Descriptors/Merge.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import List - - -class Merge: - # Merge descriptor. - class Mesh: - # Mesh descriptor. - def __init__(self, name: str, triangles: int, quads: int, positions: int, normals: int, uvs: int, size: int): - # The mesh name. - self.name = name - # Number of mesh triangle faces. - self.triangles = triangles - # Number of quad faces. - self.quads = quads - # Number of vertex positions. - self.positions = positions - # Number of vertex normals. - self.normals = normals - # Number of UV coordinates. - self.uvs = uvs - # Total mesh size in bytes. - self.size = size - - def __init__(self, scans: int, textures: int, maxSimplifyCount: int, meshes: List['Mesh'] = None): - # The number of input scans. - self.scans = scans - # The number of input textures. - self.textures = textures - # The maximum number of faces for the simplify merge step. - self.maxSimplifyCount = maxSimplifyCount - # The set of merged mesh descriptors. - self.meshes = meshes - - diff --git a/maf_three/MF/V3/Descriptors/Network.py b/maf_three/MF/V3/Descriptors/Network.py deleted file mode 100644 index 9f5ce91..0000000 --- a/maf_three/MF/V3/Descriptors/Network.py +++ /dev/null @@ -1,11 +0,0 @@ -class Interface: - # Network interface descriptor. - def __init__(self, name: str, ip: str, ssid: str): - # The name of the interface. - self.name = name - # The address associated with the interface. - self.ip = ip - # The ssid or name of the network. - self.ssid = ssid - - diff --git a/maf_three/MF/V3/Descriptors/Project.py b/maf_three/MF/V3/Descriptors/Project.py deleted file mode 100644 index 90e35bc..0000000 --- a/maf_three/MF/V3/Descriptors/Project.py +++ /dev/null @@ -1,47 +0,0 @@ -from typing import List - - -class Project: - # V3 project descriptor. - class Brief: - # V3 project brief descriptor. - def __init__(self, index: int, name: str, size: int, modified: List[int] = None): - # Project index. - self.index = index - # Project name. - self.name = name - # Size in bytes. - self.size = size - # Project last modified date and time [year, month, day, hour, minute, second]. - self.modified = modified - - class Group: - # V3 project scan group tree descriptor. - def __init__(self, index: int, name: str, visible: bool, collapsed: bool, color: List[float] = None, rotation: List[float] = None, translation: List[float] = None, scan: int = None, groups: List['Project.Group'] = None): - # Group index. - self.index = index - # Group name. - self.name = name - # Visibility in the renderer. - self.visible = visible - # Collapsed state in the group tree. - self.collapsed = collapsed - # Color in the renderer. - self.color = color - # Axis-angle rotation vector. The direction of the vector is the rotation axis. The magnitude of the vector is rotation angle in radians. - self.rotation = rotation - # Translation vector. - self.translation = translation - # The scan index. If defined this group is a scan and cannot have subgroups. - self.scan = scan - # Subgroups. - self.groups = groups - - def __init__(self, index: int, name: str, groups: 'Group'): - # Project index. - self.index = index - # Project name. - self.name = name - self.groups = groups - - diff --git a/maf_three/MF/V3/Descriptors/ProjectActions.py b/maf_three/MF/V3/Descriptors/ProjectActions.py deleted file mode 100644 index 57485bc..0000000 --- a/maf_three/MF/V3/Descriptors/ProjectActions.py +++ /dev/null @@ -1,37 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from typing import List - - -class ProjectAction: - # Descriptor for a project undo/redo action. - class Scan: - # Scan vertices removal/insertion metadata. - def __init__(self, index: int, vertices: int, triangles: int): - # The scan index. - self.index = index - # The number of vertices after undo or redo. - self.vertices = vertices - # The number of triangles after undo or redo. - self.triangles = triangles - - def __init__(self, task: str, project: MF_V3_Descriptors_Project_Project = None, scans: List['Scan'] = None): - # The original websocket task that the action is undoing or redoing. - self.task = task - """ - The updated project data after undo or redo. - If undefined, then there was no change to the project. - """ - self.project = project - # The list of scans whose vertex/triangle elements were changed by the undo/redo action. - self.scans = scans - - -class ProjectActions: - # Project undo and redo action descriptors. - def __init__(self, undo: List[str] = None, redo: List[str] = None): - # Project undo action descriptors. - self.undo = undo - # Project redo action descriptors. - self.redo = redo - - diff --git a/maf_three/MF/V3/Descriptors/RemoveVertices.py b/maf_three/MF/V3/Descriptors/RemoveVertices.py deleted file mode 100644 index 2aa3ac3..0000000 --- a/maf_three/MF/V3/Descriptors/RemoveVertices.py +++ /dev/null @@ -1,26 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from typing import List - - -class RemoveVertices: - # Descriptor a remove vertices task. - class Scan: - # Scan vertex and triangle removal metadata. - def __init__(self, index: int, vertices: int, triangles: int): - # The scan index. - self.index = index - # The number of vertices after the removal. - self.vertices = vertices - # The number of triangles after the removal. - self.triangles = triangles - - def __init__(self, scans: List['Scan'] = None, groups: MF_V3_Descriptors_Project_Project.Group = None): - # The list of scans whose vertices were removed. - self.scans = scans - """ - The updated project data after undo or redo. - If undefined, then there was no change to the project. - """ - self.groups = groups - - diff --git a/maf_three/MF/V3/Descriptors/ScanData.py b/maf_three/MF/V3/Descriptors/ScanData.py deleted file mode 100644 index 0442683..0000000 --- a/maf_three/MF/V3/Descriptors/ScanData.py +++ /dev/null @@ -1,53 +0,0 @@ -from enum import Enum -from typing import List - - -class ScanData: - # Scan data descriptor. - class Buffer: - # Scan buffer descriptor. - class Component: - # Scan buffer component descriptor. - # Scan buffer component types. - class Type(Enum): - Position = "Position" # Vertex position. - Normal = "Normal" # Vertex normal. - Color = "Color" # Vertex color. - UV = "UV" # Vertex texture coordinate. - Triangle = "Triangle" # Triangle index. - Texture = "Texture" # Texture. - - def __init__(self, type: 'Type', size: int, offset: int, normalized: bool): - # Scan buffer component type. - self.type = type - # Scan buffer component size (ie. the number of elements). - self.size = size - """ - Scan buffer component offset. - This is the starting element for this component at every stride of the buffer. - """ - self.offset = offset - # Indicates if the data is normalized. - self.normalized = normalized - - def __init__(self, stride: int, components: List['Component'] = None): - # Scan buffer stride. This should be greater or equal to the sum of the component sizes. - self.stride = stride - # Scan buffer components. - self.components = components - - def __init__(self, index: int, name: str, buffers: List['Buffer'] = None, mean: List[float] = None, stddev: List[float] = None, axisAlignedBoundingBox: List[float] = None): - # Scan index. - self.index = index - # Scan name. - self.name = name - # Scan buffer descriptors. - self.buffers = buffers - # The mean (centroid) of the vertex positions. - self.mean = mean - # The standard deviation of the vertex positions. - self.stddev = stddev - # The axis-aligned bounding box of the vertex positions. - self.axisAlignedBoundingBox = axisAlignedBoundingBox - - diff --git a/maf_three/MF/V3/Descriptors/Settings/Advanced.py b/maf_three/MF/V3/Descriptors/Settings/Advanced.py deleted file mode 100644 index 423fb3e..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/Advanced.py +++ /dev/null @@ -1,284 +0,0 @@ -from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan -from typing import List - - -class Advanced: - # Advanced settings descriptor. - class Use: - # Use advanced settings. - def __init__(self, value: bool, default: bool): - self.value = value - self.default = default - - class Capture: - # Capture settings descriptor. - class HorizontalFrequencies: - def __init__(self, min: int, max: int, value: List[int] = None, default: List[int] = None): - self.min = min - self.max = max - self.value = value - self.default = default - - class VerticalFrequencies: - def __init__(self, min: int, max: int, value: List[int] = None, default: List[int] = None): - self.min = min - self.max = max - self.value = value - self.default = default - - def __init__(self, use: 'Advanced.Use', horizontalFrequencies: 'HorizontalFrequencies', verticalFrequencies: 'VerticalFrequencies'): - self.use = use - self.horizontalFrequencies = horizontalFrequencies - self.verticalFrequencies = verticalFrequencies - - class Sampling: - # Sampling settings descriptor. - class ProjectorSampleRate: - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - class ImageSampleRate: - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - def __init__(self, use: 'Advanced.Use', projectorSampleRate: 'ProjectorSampleRate', imageSampleRate: 'ImageSampleRate'): - # Use sampling settings. - self.use = use - self.projectorSampleRate = projectorSampleRate - self.imageSampleRate = imageSampleRate - - class EdgeDetection: - # Edge detection settings descriptor. - class Threshold: - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - class LaplacianKernelRadius: - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - class GaussianBlurRadius: - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - class GaussianBlurStdDev: - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - class MaximumWidthForProcessing: - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - def __init__(self, use: 'Advanced.Use', threshold: 'Threshold', laplacianKernelRadius: 'LaplacianKernelRadius', gaussianBlurRadius: 'GaussianBlurRadius', gaussianBlurStdDev: 'GaussianBlurStdDev', maximumWidthForProcessing: 'MaximumWidthForProcessing'): - self.use = use - self.threshold = threshold - self.laplacianKernelRadius = laplacianKernelRadius - self.gaussianBlurRadius = gaussianBlurRadius - self.gaussianBlurStdDev = gaussianBlurStdDev - self.maximumWidthForProcessing = maximumWidthForProcessing - - class PhaseFilter: - # Phase filter settings descriptor. - class KernelRadius: - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - class SpatialWeightStdDev: - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - def __init__(self, use: 'Advanced.Use', kernelRadius: 'KernelRadius', spatialWeightStdDev: 'SpatialWeightStdDev'): - self.use = use - self.kernelRadius = kernelRadius - self.spatialWeightStdDev = spatialWeightStdDev - - class AdaptiveSampling: - # Adaptive sampling settings descriptor. - class Type: - def __init__(self, value: MF_V3_Settings_Scan_Scan.Processing.AdaptiveSampling.Type, default: MF_V3_Settings_Scan_Scan.Processing.AdaptiveSampling.Type): - self.value = value - self.default = default - - class Rate: - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - def __init__(self, use: 'Advanced.Use', type: 'Type', rate: 'Rate'): - self.use = use - self.type = type - self.rate = rate - - class NormalEstimation: - # Normal estimation settings descriptor. - class Method: - def __init__(self, value: MF_V3_Settings_Scan_Scan.Processing.NormalEstimation.Method, default: MF_V3_Settings_Scan_Scan.Processing.NormalEstimation.Method): - self.value = value - self.default = default - - class MaximumNeighbourCount: - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - class MaximumNeighbourRadius: - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - class UseMaximumNeighbourCount: - def __init__(self, value: bool, default: bool): - self.value = value - self.default = default - - class UseMaximumNeighbourRadius: - def __init__(self, value: bool, default: bool): - self.value = value - self.default = default - - def __init__(self, use: 'Advanced.Use', method: 'Method', maximumNeighbourCount: 'MaximumNeighbourCount', maximumNeighbourRadius: 'MaximumNeighbourRadius', useMaximumNeighbourCount: 'UseMaximumNeighbourCount', useMaximumNeighbourRadius: 'UseMaximumNeighbourRadius'): - self.use = use - self.method = method - self.maximumNeighbourCount = maximumNeighbourCount - self.maximumNeighbourRadius = maximumNeighbourRadius - self.useMaximumNeighbourCount = useMaximumNeighbourCount - self.useMaximumNeighbourRadius = useMaximumNeighbourRadius - - class OutlierRemoval: - # Outlier removal settings descriptor. - class NeighbourCount: - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - class NeighbourRadius: - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - def __init__(self, use: 'Advanced.Use', neighbourCount: 'NeighbourCount', neighbourRadius: 'NeighbourRadius'): - self.use = use - self.neighbourCount = neighbourCount - self.neighbourRadius = neighbourRadius - - class Remesh: - # Remesh settings descriptor. - class VoxelSize: - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - class Depth: - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - class Scale: - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - class LinearInterpolation: - def __init__(self, value: bool, default: bool): - self.value = value - self.default = default - - def __init__(self, use: 'Advanced.Use', voxelSize: 'VoxelSize', depth: 'Depth', scale: 'Scale', linearInterpolation: 'LinearInterpolation'): - self.use = use - self.voxelSize = voxelSize - self.depth = depth - self.scale = scale - self.linearInterpolation = linearInterpolation - - class Camera: - # Camera settings descriptor. - class UseContinuousExposureValues: - # Use continuous exposure values settings descriptor. - def __init__(self, value: bool, default: bool): - self.value = value - self.default = default - - def __init__(self, useContinuousExposureValues: 'UseContinuousExposureValues'): - # Use continuous exposure values settings descriptor. - self.useContinuousExposureValues = useContinuousExposureValues - - class Turntable: - # Turntable settings descriptor. - class RampAngle: - # The angle in degrees to slow down the turntable at the end of a rotation. - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - def __init__(self, rampAngle: 'RampAngle'): - # The angle in degrees to slow down the turntable at the end of a rotation. - self.rampAngle = rampAngle - - def __init__(self, capture: 'Capture', sampling: 'Sampling', edgeDetection: 'EdgeDetection', phaseFilter: 'PhaseFilter', adaptiveSampling: 'AdaptiveSampling', normalEstimation: 'NormalEstimation', outlierRemoval: 'OutlierRemoval', remesh: 'Remesh', camera: 'Camera', turntable: 'Turntable'): - # Capture settings descriptor. - self.capture = capture - # Sampling settings descriptor. - self.sampling = sampling - # Edge detection settings descriptor. - self.edgeDetection = edgeDetection - # Phase filter settings descriptor. - self.phaseFilter = phaseFilter - # Adaptive sampling settings descriptor. - self.adaptiveSampling = adaptiveSampling - # Normal estimation settings descriptor. - self.normalEstimation = normalEstimation - # Outlier removal settings descriptor. - self.outlierRemoval = outlierRemoval - # Remesh settings descriptor. - self.remesh = remesh - # Camera settings descriptor. - self.camera = camera - # Turntable settings descriptor. - self.turntable = turntable - - diff --git a/maf_three/MF/V3/Descriptors/Settings/Camera.py b/maf_three/MF/V3/Descriptors/Settings/Camera.py deleted file mode 100644 index df45cc0..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/Camera.py +++ /dev/null @@ -1,71 +0,0 @@ -from MF.V3.Settings.Rectangle import Rectangle as MF_V3_Settings_Rectangle_Rectangle -from typing import List - - -class Camera: - # Camera settings descriptor. - class AutoExposure: - # Auto exposure. - def __init__(self, value: bool, default: bool): - self.value = value - self.default = default - - class Exposure: - # Exposure. - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - class AnalogGain: - # Analog gain. - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - class DigitalGain: - # Digital gain. - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - class Focus: - # Focus settings descriptor. - class Value: - # Focus value. - def __init__(self, min: int, max: int, value: List[int] = None, default: List[int] = None): - self.min = min - self.max = max - self.value = value - self.default = default - - class Box: - # Auto focus box. - def __init__(self, value: List[MF_V3_Settings_Rectangle_Rectangle] = None, default: List[MF_V3_Settings_Rectangle_Rectangle] = None): - self.value = value - self.default = default - - def __init__(self, value: 'Value', box: 'Box'): - # Focus value. - self.value = value - # Auto focus box. - self.box = box - - def __init__(self, autoExposure: 'AutoExposure', exposure: 'Exposure', analogGain: 'AnalogGain', digitalGain: 'DigitalGain', focus: 'Focus'): - # Auto exposure. - self.autoExposure = autoExposure - # Exposure. - self.exposure = exposure - # Analog gain. - self.analogGain = analogGain - # Digital gain. - self.digitalGain = digitalGain - # Focus settings descriptor. - self.focus = focus - - diff --git a/maf_three/MF/V3/Descriptors/Settings/Capture.py b/maf_three/MF/V3/Descriptors/Settings/Capture.py deleted file mode 100644 index 8143c07..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/Capture.py +++ /dev/null @@ -1,46 +0,0 @@ -from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality - - -class Capture: - # Capture settings descriptor. - class Quality: - # Capture quality preset. - def __init__(self, value: MF_V3_Settings_Quality_Quality, default: MF_V3_Settings_Quality_Quality): - self.value = value - self.default = default - - class Texture: - # Capture texture. - def __init__(self, value: bool, default: bool): - self.value = value - self.default = default - - class BlendCount: - # Capture image blend count for noise reduction. - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - class BlendFrequency: - # The starting frequency for which multiple capture images are blended. - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - def __init__(self, quality: 'Quality', texture: 'Texture', blendCount: 'BlendCount', horizontalBlendFrequency: 'BlendFrequency', verticalBlendFrequency: 'BlendFrequency'): - # Capture quality preset. - self.quality = quality - # Capture texture. - self.texture = texture - # Capture blend count. - self.blendCount = blendCount - # Starting horizontal blend frequency. - self.horizontalBlendFrequency = horizontalBlendFrequency - # Starting vertical blend frequency. - self.verticalBlendFrequency = verticalBlendFrequency - - diff --git a/maf_three/MF/V3/Descriptors/Settings/I18n.py b/maf_three/MF/V3/Descriptors/Settings/I18n.py deleted file mode 100644 index f6ece28..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/I18n.py +++ /dev/null @@ -1,16 +0,0 @@ -from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n - - -class I18n: - # I18n language settings descriptor. - class Language: - # Language settings descriptor. - def __init__(self, value: MF_V3_Settings_I18n_I18n.Language, default: MF_V3_Settings_I18n_I18n.Language): - self.value = value - self.default = default - - def __init__(self, language: 'Language'): - # Language settings descriptor. - self.language = language - - diff --git a/maf_three/MF/V3/Descriptors/Settings/Projector.py b/maf_three/MF/V3/Descriptors/Settings/Projector.py deleted file mode 100644 index 60310dc..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/Projector.py +++ /dev/null @@ -1,23 +0,0 @@ -class Projector: - # Projector settings descriptor. - class Brightness: - # Projector brightness. - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - class On: - # Projector on/off. - def __init__(self, value: bool, default: bool): - self.value = value - self.default = default - - def __init__(self, brightness: 'Brightness', on: 'On'): - # Projector brightness. - self.brightness = brightness - # Projector on/off. - self.on = on - - diff --git a/maf_three/MF/V3/Descriptors/Settings/Scanner.py b/maf_three/MF/V3/Descriptors/Settings/Scanner.py deleted file mode 100644 index f0d2e6a..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/Scanner.py +++ /dev/null @@ -1,37 +0,0 @@ -from MF.V3.Descriptors.Settings.Advanced import Advanced as MF_V3_Descriptors_Settings_Advanced_Advanced -from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera -from MF.V3.Descriptors.Settings.Capture import Capture as MF_V3_Descriptors_Settings_Capture_Capture -from MF.V3.Descriptors.Settings.I18n import I18n as MF_V3_Descriptors_Settings_I18n_I18n -from MF.V3.Descriptors.Settings.Projector import Projector as MF_V3_Descriptors_Settings_Projector_Projector -from MF.V3.Descriptors.Settings.Software import Software as MF_V3_Descriptors_Settings_Software_Software -from MF.V3.Descriptors.Settings.Style import Style as MF_V3_Descriptors_Settings_Style_Style -from MF.V3.Descriptors.Settings.Turntable import Turntable as MF_V3_Descriptors_Settings_Turntable_Turntable -from MF.V3.Descriptors.Settings.Tutorials import Tutorials as MF_V3_Descriptors_Settings_Tutorials_Tutorials -from MF.V3.Descriptors.Settings.Viewer import Viewer as MF_V3_Descriptors_Settings_Viewer_Viewer - - -class Scanner: - # Scanner settings descriptor. - def __init__(self, advanced: MF_V3_Descriptors_Settings_Advanced_Advanced, camera: MF_V3_Descriptors_Settings_Camera_Camera, capture: MF_V3_Descriptors_Settings_Capture_Capture, projector: MF_V3_Descriptors_Settings_Projector_Projector, i18n: MF_V3_Descriptors_Settings_I18n_I18n, style: MF_V3_Descriptors_Settings_Style_Style, turntable: MF_V3_Descriptors_Settings_Turntable_Turntable, tutorials: MF_V3_Descriptors_Settings_Tutorials_Tutorials, viewer: MF_V3_Descriptors_Settings_Viewer_Viewer, software: MF_V3_Descriptors_Settings_Software_Software): - # Advanced settings descriptor. - self.advanced = advanced - # Camera settings descriptor. - self.camera = camera - # Capture settings descriptor. - self.capture = capture - # Projector settings descriptor. - self.projector = projector - # Internalization setting descriptor. - self.i18n = i18n - # Style settings descriptor. - self.style = style - # Turntable settings descriptor. - self.turntable = turntable - # Tutorials settings descriptor. - self.tutorials = tutorials - # Viewer settings descriptor. - self.viewer = viewer - # Software settings descriptor. - self.software = software - - diff --git a/maf_three/MF/V3/Descriptors/Settings/Software.py b/maf_three/MF/V3/Descriptors/Settings/Software.py deleted file mode 100644 index 2bcc7bb..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/Software.py +++ /dev/null @@ -1,13 +0,0 @@ -class Software: - # Software settings descriptor. - class UpdateMajor: - # Enable major version updates which can have breaking API changes. - def __init__(self, value: bool, default: bool): - self.value = value - self.default = default - - def __init__(self, updateMajor: 'UpdateMajor'): - # Enable major version updates which can have breaking API changes. - self.updateMajor = updateMajor - - diff --git a/maf_three/MF/V3/Descriptors/Settings/Style.py b/maf_three/MF/V3/Descriptors/Settings/Style.py deleted file mode 100644 index 274447f..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/Style.py +++ /dev/null @@ -1,16 +0,0 @@ -from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style - - -class Style: - # Style settings descriptor. - class Theme: - # Theme settings descriptor. - def __init__(self, value: MF_V3_Settings_Style_Style.Theme, default: MF_V3_Settings_Style_Style.Theme): - self.value = value - self.default = default - - def __init__(self, theme: 'Theme'): - # Theme settings descriptor. - self.theme = theme - - diff --git a/maf_three/MF/V3/Descriptors/Settings/Turntable.py b/maf_three/MF/V3/Descriptors/Settings/Turntable.py deleted file mode 100644 index 1655db7..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/Turntable.py +++ /dev/null @@ -1,33 +0,0 @@ -class Turntable: - # Turntable settings descriptor. - class Scans: - # The number of turntable scans. - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - class Sweep: - # Turntable angle sweep in degrees. - def __init__(self, value: int, default: int, min: int, max: int): - self.value = value - self.default = default - self.min = min - self.max = max - - class Use: - # Use the turntable. - def __init__(self, value: bool, default: bool): - self.value = value - self.default = default - - def __init__(self, scans: 'Scans', sweep: 'Sweep', use: 'Use'): - # The number of turntable scans. - self.scans = scans - # Turntable angle sweep in degrees. - self.sweep = sweep - # Use the turntable. - self.use = use - - diff --git a/maf_three/MF/V3/Descriptors/Settings/Tutorials.py b/maf_three/MF/V3/Descriptors/Settings/Tutorials.py deleted file mode 100644 index ea01eea..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/Tutorials.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import List - - -class Tutorials: - # Tutorials settings descriptor. - class Show: - # Tutorials to show. - def __init__(self, value: bool, default: bool): - self.value = value - self.default = default - - class Viewed: - # Viewed tutorials. - class Pages: - # Viewed tutorials pages. - def __init__(self, value: List[str] = None, default: List[str] = None): - self.value = value - self.default = default - - def __init__(self, pages: 'Pages'): - # Viewed tutorials pages. - self.pages = pages - - def __init__(self, show: 'Show', viewed: 'Viewed'): - # Show tutorials. - self.show = show - # Viewed tutorials. - self.viewed = viewed - - diff --git a/maf_three/MF/V3/Descriptors/Settings/Viewer.py b/maf_three/MF/V3/Descriptors/Settings/Viewer.py deleted file mode 100644 index 296fead..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/Viewer.py +++ /dev/null @@ -1,15 +0,0 @@ -class Viewer: - # 3D Viewer settings descriptor. - class TextureOpacity: - # Texture opacity. - def __init__(self, value: float, default: float, min: float, max: float): - self.value = value - self.default = default - self.min = min - self.max = max - - def __init__(self, textureOpacity: 'TextureOpacity'): - # Texture opacity. - self.textureOpacity = textureOpacity - - diff --git a/maf_three/MF/V3/Descriptors/Settings/__init__.py b/maf_three/MF/V3/Descriptors/Settings/__init__.py deleted file mode 100644 index 03ad69e..0000000 --- a/maf_three/MF/V3/Descriptors/Settings/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from MF.V3.Descriptors.Settings.Advanced import * -from MF.V3.Descriptors.Settings.Camera import * -from MF.V3.Descriptors.Settings.Capture import * -from MF.V3.Descriptors.Settings.I18n import * -from MF.V3.Descriptors.Settings.Projector import * -from MF.V3.Descriptors.Settings.Scanner import * -from MF.V3.Descriptors.Settings.Software import * -from MF.V3.Descriptors.Settings.Style import * -from MF.V3.Descriptors.Settings.Turntable import * -from MF.V3.Descriptors.Settings.Tutorials import * -from MF.V3.Descriptors.Settings.Viewer import * diff --git a/maf_three/MF/V3/Descriptors/Software.py b/maf_three/MF/V3/Descriptors/Software.py deleted file mode 100644 index 4042713..0000000 --- a/maf_three/MF/V3/Descriptors/Software.py +++ /dev/null @@ -1,19 +0,0 @@ -class Software: - # Software descriptor. - class Package: - # Software package descriptor. - def __init__(self, installed: str, update: str, changelog: str): - # The package installed version. - self.installed = installed - # The package update version. Empty if no update is available. - self.update = update - # The package changelog. Empty if no update is available or the update is a downgrade. - self.changelog = changelog - - def __init__(self, frontend: 'Package', server: 'Package'): - # Frontend software package. - self.frontend = frontend - # Server software package. - self.server = server - - diff --git a/maf_three/MF/V3/Descriptors/System.py b/maf_three/MF/V3/Descriptors/System.py deleted file mode 100644 index 3c8b3a4..0000000 --- a/maf_three/MF/V3/Descriptors/System.py +++ /dev/null @@ -1,19 +0,0 @@ -class System: - # System descriptor. - class DiskSpace: - # Disk space descriptor. - def __init__(self, capacity: int, available: int): - # Disk space capacity in bytes. - self.capacity = capacity - # Available disk space in bytes. - self.available = available - - def __init__(self, serialNumber: str, diskSpace: 'DiskSpace', publicKey: str): - # Serial number; - self.serialNumber = serialNumber - # Used and available disk space. - self.diskSpace = diskSpace - # GPG public key. - self.publicKey = publicKey - - diff --git a/maf_three/MF/V3/Descriptors/Transform.py b/maf_three/MF/V3/Descriptors/Transform.py deleted file mode 100644 index 8638d74..0000000 --- a/maf_three/MF/V3/Descriptors/Transform.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import List - - -class Transform: - # V3 transform descriptor. - def __init__(self, rotation: List[float] = None, translation: List[float] = None): - """ - Axis-angle rotation vector. - The direction of the vector is the rotation axis. - The magnitude of the vector is rotation angle in radians. - """ - self.rotation = rotation - # Translation vector. - self.translation = translation - - diff --git a/maf_three/MF/V3/Descriptors/VideoFrame.py b/maf_three/MF/V3/Descriptors/VideoFrame.py deleted file mode 100644 index 286925c..0000000 --- a/maf_three/MF/V3/Descriptors/VideoFrame.py +++ /dev/null @@ -1,27 +0,0 @@ -from MF.V3.Descriptors.Calibration import DetectedCard as MF_V3_Descriptors_Calibration_DetectedCard -from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video - - -class VideoFrame: - # Video frame descriptor. - def __init__(self, codec: MF_V3_Settings_Video_Video.Codec, format: MF_V3_Settings_Video_Video.Format, width: int, height: int, step: int, number: int, timestamp: int, duration: int, calibrationCard: MF_V3_Descriptors_Calibration_DetectedCard): - # Video codec. - self.codec = codec - # Pixel format. - self.format = format - # Image width. - self.width = width - # Image height. - self.height = height - # Image row step in bytes. - self.step = step - # Frame number. - self.number = number - # Frame timestamp. - self.timestamp = timestamp - # Frame duration. - self.duration = duration - # Calibration card detection. - self.calibrationCard = calibrationCard - - diff --git a/maf_three/MF/V3/Descriptors/Wifi.py b/maf_three/MF/V3/Descriptors/Wifi.py deleted file mode 100644 index b2fe4b8..0000000 --- a/maf_three/MF/V3/Descriptors/Wifi.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import List - - -class Wifi: - # The wifi descriptor. - class Network: - # The wifi network descriptor. - def __init__(self, ssid: str, isPublic: bool, isActive: bool, password: str = None, quality: int = None): - # The service set identifier. - self.ssid = ssid - # Is the network public? - self.isPublic = isPublic - # Is the network active? - self.isActive = isActive - # The network password. - self.password = password - # Signal quality [0 ; 100]. - self.quality = quality - - def __init__(self, ssid: str, networks: List['Network'] = None): - # The wifi ssid. - self.ssid = ssid - # The list of wifi networks. - self.networks = networks - - diff --git a/maf_three/MF/V3/Descriptors/__init__.py b/maf_three/MF/V3/Descriptors/__init__.py deleted file mode 100644 index 0914107..0000000 --- a/maf_three/MF/V3/Descriptors/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from MF.V3.Descriptors.BoundingBox import * -from MF.V3.Descriptors.Export import * -from MF.V3.Descriptors.Image import * -from MF.V3.Descriptors.Merge import * -from MF.V3.Descriptors.Project import * -from MF.V3.Descriptors.ProjectActions import * -from MF.V3.Descriptors.RemoveVertices import * -from MF.V3.Descriptors.ScanData import * -from MF.V3.Descriptors.Software import * -from MF.V3.Descriptors.System import * -from MF.V3.Descriptors.Transform import * -from MF.V3.Descriptors.VideoFrame import * -from MF.V3.Descriptors.Wifi import * diff --git a/maf_three/MF/V3/Settings/Advanced.py b/maf_three/MF/V3/Settings/Advanced.py deleted file mode 100644 index a54ba9b..0000000 --- a/maf_three/MF/V3/Settings/Advanced.py +++ /dev/null @@ -1,185 +0,0 @@ -from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality -from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan -from typing import List - - -class Advanced: - # Advanced settings. - class Capture: - # Capture settings. - def __init__(self, horizontalFrequencies: List[int] = None, verticalFrequencies: List[int] = None, use: bool = None): - # Projector sample rate. - self.horizontalFrequencies = horizontalFrequencies - # Image sample rate. - self.verticalFrequencies = verticalFrequencies - # Use the capture settings. - self.use = use - - class Sampling: - # Sampling settings. - def __init__(self, projectorSampleRate: float = None, imageSampleRate: float = None, use: bool = None): - # Projector sample rate. - self.projectorSampleRate = projectorSampleRate - # Image sample rate. - self.imageSampleRate = imageSampleRate - # Use the sampling settings. - self.use = use - - class EdgeDetection: - # Edge detection settings. - def __init__(self, threshold: float = None, laplacianKernelRadius: int = None, gaussianBlurRadius: int = None, gaussianBlurStdDev: float = None, maximumWidthForProcessing: int = None, use: bool = None): - # The edge detection threshold. - self.threshold = threshold - # The Laplacian kernel radius. This must be in the range [1..5]. - self.laplacianKernelRadius = laplacianKernelRadius - """ - Gaussian blur kernel radius. (Optional) To disable, set to 0. - - The phase images can optionally blurred before taking the Laplacian to reduce noise. - However as a result, the detected edges are wider. - """ - self.gaussianBlurRadius = gaussianBlurRadius - """ - Gaussian blur kernel standard deviation. This parameter is ignored if - \p gaussianBlurSize is zero. - """ - self.gaussianBlurStdDev = gaussianBlurStdDev - """ - The maximum image width for processing. (Optional) To disable, set to 0. - - If this value is greater than zero, the phase images are resized to the maximum - width prior to computing the Laplacian and the the detected edges are then upsampled to the - original size. - - This would be done to speed up processing or to detect edges on a larger scale. - """ - self.maximumWidthForProcessing = maximumWidthForProcessing - # Use the edge detection settings. - self.use = use - - class PhaseFilter: - # Phase filter settings. - def __init__(self, kernelRadius: int = None, spatialWeightStdDev: float = None, use: bool = None): - """ - The filter kernel radius. - - A neighboring value must be within this radius to be included in the filter. - If the kernel radius is set to zero, the phase filtering is disabled. - """ - self.kernelRadius = kernelRadius - """ - The standard deviation of the spatial weights. - - The weight of a neighboring value is \f$ exp(-(r/s)^2) \f$ where \f$ r \f$ - is the distance to the central value and \f$ s \f$ is the spatial weight - standard deviation. - - If the spatial weight standard deviation is set to zero, all the spatial - weights are uniformly set to 1. - """ - self.spatialWeightStdDev = spatialWeightStdDev - # Use the phase filter settings. - self.use = use - - class AdaptiveSampling: - """ - Adaptive sampling settings - - Adaptive sampling will downsample points in regions of low detail - and keep points in regions of high detail. - """ - def __init__(self, rate: float, type: MF_V3_Settings_Scan_Scan.Processing.AdaptiveSampling.Type = None, use: bool = None): - # The sample rate [0..1] for the regions of low detail. - self.rate = rate - # Sampling type. - self.type = type - # Use the adaptive sampling settings. - self.use = use - - class PointClipping: - # Point32 clipping settings. - def __init__(self, type: MF_V3_Settings_Scan_Scan.Processing.PointClipping.Type = None, transform: List[float] = None, use: bool = None): - # Point32 clipping type. - self.type = type - # 4x4 transform mapping 3D points to the canonical point32 clipping coordinates. - self.transform = transform - # Use the point32 clipping settings. - self.use = use - - class NormalEstimation: - # Normal estimation settings. - def __init__(self, method: MF_V3_Settings_Scan_Scan.Processing.NormalEstimation.Method = None, maximumNeighbourCount: int = None, maximumNeighbourRadius: float = None, useMaximumNeighbourCount: bool = None, useMaximumNeighbourRadius: bool = None, use: bool = None): - # Normal estimation method. - self.method = method - """ - Maximum number of nearest neighbors used to compute the normal. - This value is only used with the NORMAL_OPEN3D method. - """ - self.maximumNeighbourCount = maximumNeighbourCount - # Maximum radius for a point32 to be considered a neighbour. - self.maximumNeighbourRadius = maximumNeighbourRadius - self.useMaximumNeighbourCount = useMaximumNeighbourCount - self.useMaximumNeighbourRadius = useMaximumNeighbourRadius - # Use the normal estimation settings. - self.use = use - - class OutlierRemoval: - # Radius outlier removal settings. - def __init__(self, neighbourCount: int = None, neighbourRadius: float = None, use: bool = None): - # The minimum number of points within the radius for a point32 to be retained. - self.neighbourCount = neighbourCount - # The neighbour search radius. - self.neighbourRadius = neighbourRadius - # Use the outlier removal settings. - self.use = use - - class Remesh: - # Remesh settings. - def __init__(self, quality: MF_V3_Settings_Quality_Quality = None, voxelSize: float = None, depth: int = None, scale: float = None, linearInterpolation: bool = None, use: bool = None): - # Remesh quality preset. - self.quality = quality - # Voxel size. - self.voxelSize = voxelSize - # Depth. - self.depth = depth - # Scale. - self.scale = scale - # Linear Interpolation. - self.linearInterpolation = linearInterpolation - # Use the remesh settings. - self.use = use - - class Camera: - # Camera settings. - def __init__(self, useContinuousExposureValues: bool = None): - self.useContinuousExposureValues = useContinuousExposureValues - - class Turntable: - # Turntable settings. - def __init__(self, rampAngle: int = None): - # The angle in degrees to slow down the turntable at the end of a rotation. - self.rampAngle = rampAngle - - def __init__(self, capture: 'Capture' = None, sampling: 'Sampling' = None, edgeDetection: 'EdgeDetection' = None, phaseFilter: 'PhaseFilter' = None, adaptiveSampling: 'AdaptiveSampling' = None, normalEstimation: 'NormalEstimation' = None, outlierRemoval: 'OutlierRemoval' = None, remesh: 'Remesh' = None, camera: 'Camera' = None, turntable: 'Turntable' = None): - # Capture settings. - self.capture = capture - # Sampling settings. - self.sampling = sampling - # Edge detection settings. - self.edgeDetection = edgeDetection - # Phase filter settings. - self.phaseFilter = phaseFilter - # Adaptive sampling settings. - self.adaptiveSampling = adaptiveSampling - # Normal estimation settings. - self.normalEstimation = normalEstimation - # Radius outlier removal settings. - self.outlierRemoval = outlierRemoval - # Remesh settings. - self.remesh = remesh - # Camera settings. - self.camera = camera - # Turntable settings. - self.turntable = turntable - - diff --git a/maf_three/MF/V3/Settings/Align.py b/maf_three/MF/V3/Settings/Align.py deleted file mode 100644 index c30616b..0000000 --- a/maf_three/MF/V3/Settings/Align.py +++ /dev/null @@ -1,82 +0,0 @@ -from enum import Enum -from typing import List - - -class Align: - # Alignment settings. - class Points: - # Point pair alignment settings. - def __init__(self, points: List[float] = None, absoluteError: float = None, relativeError: float = None, useAllPoints: bool = None): - # The set of corresponding point pairs. - self.points = points - # The maximum absolute error for a point pair to be an inlier to the model. - self.absoluteError = absoluteError - # The maximum error relative to the size of the aligned scans for a point pair to be an inlier to the model. - self.relativeError = relativeError - # Ignore alignment errors and use all selected points for alignment. - self.useAllPoints = useAllPoints - - class Ransac: - # Ransac alignment settings. - def __init__(self, downsampleVoxelSize: float = None, maximumFeatureRadius: float = None, maximumFeaturePointCount: int = None, maximumMatchDistance: float = None, minimumMatchSimilarity: float = None, mutualFilter: bool = None): - self.downsampleVoxelSize = downsampleVoxelSize - self.maximumFeatureRadius = maximumFeatureRadius - self.maximumFeaturePointCount = maximumFeaturePointCount - self.maximumMatchDistance = maximumMatchDistance - self.minimumMatchSimilarity = minimumMatchSimilarity - self.mutualFilter = mutualFilter - - class ICP: - # Iterative closest point alignment settings. - def __init__(self, matchDistance: float): - # The maximum distance for two points to be considered a match. - self.matchDistance = matchDistance - - class Rough: - # Rough alignment settings. - # Rough alignment methods. - class Method(Enum): - Empty = "None" # No rough alignment. - FastGlobal = "FastGlobal" # Fast global alignment. - Ransac = "Ransac" # Ransac alignment. - Points = "Points" # Point pair alignment. - - def __init__(self, method: 'Method', ransac: 'Align.Ransac' = None, points: 'Align.Points' = None): - # Rough alignment method. - self.method = method - # FastGlobal fastGlobal; - self.ransac = ransac - # Point pair alignment settings. - self.points = points - - class Fine: - # Fine alignment settings. - # Fine alignment methods. - class Method(Enum): - Empty = "None" # No fine alignment. - ICP = "ICP" # Iterative closest point alignment. - - class Transform: - def __init__(self, rotation: List[float] = None, translation: List[float] = None): - self.rotation = rotation - self.translation = translation - - def __init__(self, method: 'Method', icp: 'Align.ICP' = None, initialTransform: 'Transform' = None): - # Fine alignment method. - self.method = method - # Iterative closest point settings. - self.icp = icp - # The initial transform for fine alignment. - self.initialTransform = initialTransform - - def __init__(self, source: int, target: int, rough: 'Rough' = None, fine: 'Fine' = None): - # Index of the scan or group to align. - self.source = source - # Index of the scan or group to align to. - self.target = target - # Rough alignment settings. - self.rough = rough - # Fine alignment settings. - self.fine = fine - - diff --git a/maf_three/MF/V3/Settings/AutoFocus.py b/maf_three/MF/V3/Settings/AutoFocus.py deleted file mode 100644 index 8a5e494..0000000 --- a/maf_three/MF/V3/Settings/AutoFocus.py +++ /dev/null @@ -1,24 +0,0 @@ -from MF.V3.Settings.Rectangle import Rectangle as MF_V3_Settings_Rectangle_Rectangle -from typing import List - - -class AutoFocus: - # Auto focus settings. - class Camera: - # Auto focus camera settings. - def __init__(self, index: int, box: MF_V3_Settings_Rectangle_Rectangle = None): - # The index of the camera on which to apply auto focus. - self.index = index - # The image rectangle in video image pixels on which to apply auto focus. - self.box = box - - def __init__(self, applyAll: bool, cameras: List['Camera'] = None): - """ - Apply the final focus value to both cameras. - This setting is ignored if more than one camera is selected. - """ - self.applyAll = applyAll - # The set of cameras on which to apply auto focus. - self.cameras = cameras - - diff --git a/maf_three/MF/V3/Settings/BoundingBox.py b/maf_three/MF/V3/Settings/BoundingBox.py deleted file mode 100644 index 3dd48ac..0000000 --- a/maf_three/MF/V3/Settings/BoundingBox.py +++ /dev/null @@ -1,15 +0,0 @@ -from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection - - -class BoundingBox: - # Bounding box settings. - def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool): - # The scan selection. - self.selection = selection - """ - If `true`, align the bounding box with the world axes. - Otherwise orient the bounding box with the scans. - """ - self.axisAligned = axisAligned - - diff --git a/maf_three/MF/V3/Settings/Camera.py b/maf_three/MF/V3/Settings/Camera.py deleted file mode 100644 index 3054771..0000000 --- a/maf_three/MF/V3/Settings/Camera.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import List - - -class Camera: - # Camera settings. - def __init__(self, selection: List[int] = None, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None): - # Camera selection. Default is all cameras. - self.selection = selection - # Auto exposure. - self.autoExposure = autoExposure - # Exposure. - self.exposure = exposure - # Analog gain. - self.analogGain = analogGain - # Digital gain. - self.digitalGain = digitalGain - # Focus value. - self.focus = focus - - diff --git a/maf_three/MF/V3/Settings/Capture.py b/maf_three/MF/V3/Settings/Capture.py deleted file mode 100644 index 40834e6..0000000 --- a/maf_three/MF/V3/Settings/Capture.py +++ /dev/null @@ -1,25 +0,0 @@ -from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality -from typing import List - - -class Capture: - # Capture settings. - def __init__(self, quality: MF_V3_Settings_Quality_Quality = None, texture: bool = None, calibrationCard: bool = None, horizontalFrequencies: List[int] = None, verticalFrequencies: List[int] = None, blendCount: int = None, horizontalBlendFrequency: int = None, verticalBlendFrequency: int = None): - # Capture quality preset. - self.quality = quality - # Capture texture. - self.texture = texture - # Detect the calibration card. - self.calibrationCard = calibrationCard - # Horizontal pattern frequencies. - self.horizontalFrequencies = horizontalFrequencies - # Vertical pattern frequencies. - self.verticalFrequencies = verticalFrequencies - # The number of capture images blended together for noise reduction. - self.blendCount = blendCount - # The starting horizontal frequency for blending capture images for noise reduction. - self.horizontalBlendFrequency = horizontalBlendFrequency - # The starting vertical frequency for blending capture images for noise reduction. - self.verticalBlendFrequency = verticalBlendFrequency - - diff --git a/maf_three/MF/V3/Settings/CopyGroup.py b/maf_three/MF/V3/Settings/CopyGroup.py deleted file mode 100644 index 1e172c9..0000000 --- a/maf_three/MF/V3/Settings/CopyGroup.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import List - - -class CopyGroup: - # Copy scan group settings. - def __init__(self, sourceIndexes: List[int] = None, targetIndex: int = None, childPosition: int = None, nameSuffix: str = None): - # The indexes of the groups to copy. - self.sourceIndexes = sourceIndexes - """ - The index of the group into which the source group are copied. - If unspecified the copied groups are added to the root of the group tree. - """ - self.targetIndex = targetIndex - """ - The position among the target group's children where the copied groups are inserted. - If unspecified the copied groups are appended to the end of the target group's children. - """ - self.childPosition = childPosition - """ - Optional name suffix to append to the copied group names. - If unspecified the names are unchanged. - """ - self.nameSuffix = nameSuffix - - diff --git a/maf_three/MF/V3/Settings/CopyProject.py b/maf_three/MF/V3/Settings/CopyProject.py deleted file mode 100644 index 7000d81..0000000 --- a/maf_three/MF/V3/Settings/CopyProject.py +++ /dev/null @@ -1,9 +0,0 @@ -class CopyProject: - # Copy project settings. - def __init__(self, index: int, copyName: str = None): - # The index of the project to copy. - self.index = index - # The name of project copy. If unspecified a default copy name is generated. - self.copyName = copyName - - diff --git a/maf_three/MF/V3/Settings/Export.py b/maf_three/MF/V3/Settings/Export.py deleted file mode 100644 index 22a82ae..0000000 --- a/maf_three/MF/V3/Settings/Export.py +++ /dev/null @@ -1,29 +0,0 @@ -from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection -from enum import Enum - - -class Export: - # Export settings. - # Scan export formats. - class Format(Enum): - ply = "ply" # Polygon format. - dae = "dae" # Digital asset exchange format. - fbx = "fbx" # Autodesk format. - glb = "glb" # GL transmission format. - obj = "obj" # Wavefront format. - stl = "stl" # Stereolithography format. - xyz = "xyz" # Chemical format. - - def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: 'Format' = None, scale: float = None): - # The scan selection. - self.selection = selection - # Export textures. - self.texture = texture - # Merge the scans into a single file. - self.merge = merge - # The export format. - self.format = format - # Scale factor of the exported geometry. - self.scale = scale - - diff --git a/maf_three/MF/V3/Settings/Group.py b/maf_three/MF/V3/Settings/Group.py deleted file mode 100644 index ab28619..0000000 --- a/maf_three/MF/V3/Settings/Group.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import List - - -class Group: - # Scan group settings. - def __init__(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None): - # The unique group index that identifies the group within the group tree. - self.index = index - # Group name. - self.name = name - # Color in the renderer. - self.color = color - # Visibility in the renderer. - self.visible = visible - # Collapsed state in the group tree. - self.collapsed = collapsed - """ - Axis-angle rotation vector. - The direction of the vector is the rotation axis. - The magnitude of the vector is rotation angle in radians. - """ - self.rotation = rotation - # Translation vector. - self.translation = translation - - diff --git a/maf_three/MF/V3/Settings/I18n.py b/maf_three/MF/V3/Settings/I18n.py deleted file mode 100644 index b6d2957..0000000 --- a/maf_three/MF/V3/Settings/I18n.py +++ /dev/null @@ -1,16 +0,0 @@ -from enum import Enum - - -class I18n: - # I18n language settings. - # Available languages. - class Language(Enum): - en = "en" - fr = "fr" - de = "de" - - def __init__(self, language: 'Language' = None): - # The language setting. Supported languages are ["en", "fr", "de"]. - self.language = language - - diff --git a/maf_three/MF/V3/Settings/Merge.py b/maf_three/MF/V3/Settings/Merge.py deleted file mode 100644 index 1772137..0000000 --- a/maf_three/MF/V3/Settings/Merge.py +++ /dev/null @@ -1,85 +0,0 @@ -from MF.V3.Settings.Quality import Quality as MF_V3_Settings_Quality_Quality -from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection -from enum import Enum - - -class Merge: - # Scan merge settings. - class Remesh: - # Remesh settings. - # Remesh method. - class Method(Enum): - FlowTriangles = "FlowTriangles" # Flow remesh as triangles. - FlowQuads = "FlowQuads" # Flow remesh as quads. - FlowQuadDominant = "FlowQuadDominant" # Flow remesh as quad-dominant mesh. - PoissonTriangles = "PoissonTriangles" # Poisson remesh as triangles. - - class Flow: - # Flow remesh settings - def __init__(self, scale: float = None, faceCount: int = None, vertexCount: int = None, creaseAngleThreshold: float = None, extrinsicSmoothness: bool = None, alignToBoundaries: bool = None, smoothIterations: int = None, knnPoints: int = None, deterministic: bool = None): - # Output resolution scale. Smaller means more faces. - self.scale = scale - # The approximate number of remeshed faces. - self.faceCount = faceCount - # The approximate number of remeshed vertices. - self.vertexCount = vertexCount - # The crease angle threshold. - self.creaseAngleThreshold = creaseAngleThreshold - # Use extrinsic smoothness. - self.extrinsicSmoothness = extrinsicSmoothness - # Align mesh to boundaries. - self.alignToBoundaries = alignToBoundaries - # The number of smoothing iterations. - self.smoothIterations = smoothIterations - # The number of KNN points (point cloud input only). - self.knnPoints = knnPoints - # Use deterministic (repeatable) remeshing. - self.deterministic = deterministic - - class Poisson: - def __init__(self, voxelSize: float = None, depth: int = None, scale: float = None, linearInterpolation: bool = None): - # Voxel size. - self.voxelSize = voxelSize - # Depth. - self.depth = depth - # Scale. - self.scale = scale - # Linear Interpolation. - self.linearInterpolation = linearInterpolation - - def __init__(self, method: 'Method' = None, quality: MF_V3_Settings_Quality_Quality = None, flow: 'Flow' = None, poisson: 'Poisson' = None, voxelSize: float = None, depth: int = None, scale: float = None, linearInterpolation: bool = None): - # Remesh method. - self.method = method - # Remesh quality. - self.quality = quality - # Flow remesh options (Ignored if method is 'Poison'). - self.flow = flow - # Poisson remesh options (Ignored if method is not 'Poisson'). - self.poisson = poisson - """ Temporary for backwards compatibility - Voxel size.""" - self.voxelSize = voxelSize - # Depth. - self.depth = depth - # Scale. - self.scale = scale - # Linear Interpolation. - self.linearInterpolation = linearInterpolation - - class Simplify: - # Simplify settings. - def __init__(self, triangleCount: int): - # Target triangle count. - self.triangleCount = triangleCount - - def __init__(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: 'Remesh' = None, simplify: 'Simplify' = None, texturize: bool = None): - # The scan selection. - self.selection = selection - # Remesh settings. - self.remesh = remesh - # Simplify settings. - self.simplify = simplify - # Apply textures to the merged mesh. - self.texturize = texturize - - diff --git a/maf_three/MF/V3/Settings/NewGroup.py b/maf_three/MF/V3/Settings/NewGroup.py deleted file mode 100644 index f466965..0000000 --- a/maf_three/MF/V3/Settings/NewGroup.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import List - - -class NewGroup: - # Scan group settings. - def __init__(self, parentIndex: int = None, baseName: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None): - """ - The index of the parent group in which the new group is created. - If unspecified the new group is added to the root of the group tree. - """ - self.parentIndex = parentIndex - """ - Group base name. - The new group name will start with the base name followed by a unique index number chosen by the backend. - """ - self.baseName = baseName - # Group color. - self.color = color - # Group visibility. - self.visible = visible - # Collapsed state in the group tree. - self.collapsed = collapsed - """ - Group axis-angle rotation vector. - The direction of the vector is the rotation axis. - The magnitude of the vector is rotation angle in radians. - """ - self.rotation = rotation - # Group translation vector. - self.translation = translation - - diff --git a/maf_three/MF/V3/Settings/Project.py b/maf_three/MF/V3/Settings/Project.py deleted file mode 100644 index 9d5f56f..0000000 --- a/maf_three/MF/V3/Settings/Project.py +++ /dev/null @@ -1,10 +0,0 @@ -class Project: - # Project settings. - def __init__(self, index: int = None, name: str = None): - """ The index identifying which project the settings applies to. - If undefined the current open project is used.""" - self.index = index - # Project name. - self.name = name - - diff --git a/maf_three/MF/V3/Settings/Projector.py b/maf_three/MF/V3/Settings/Projector.py deleted file mode 100644 index 1740927..0000000 --- a/maf_three/MF/V3/Settings/Projector.py +++ /dev/null @@ -1,58 +0,0 @@ -from MF.V3.Settings.Rectangle import Rectangle as MF_V3_Settings_Rectangle_Rectangle -from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video -from enum import Enum -from typing import List - - -class Projector: - # Projector settings. - # Pattern orientation. - class Orientation(Enum): - Horizontal = "Horizontal" # Horizontal pattern. Image columns are identical. - Vertical = "Vertical" # Vertical pattern. Image rows are identical. - - class Pattern: - # Structured light pattern. - def __init__(self, orientation: 'Projector.Orientation', frequency: int, phase: int): - # Pattern orientation. - self.orientation = orientation - # Pattern frequency index. [0 - 8] - self.frequency = frequency - # Pattern phase. [0 - 2] - self.phase = phase - - class Image: - # Projector image settings - class Source: - # Image source. - def __init__(self, format: MF_V3_Settings_Video_Video.Format, width: int, height: int, step: int, fixAspectRatio: bool): - # Source image format - self.format = format - # Source image width. - self.width = width - # Source image height. - self.height = height - # Source image step in bytes. - self.step = step - # Fix the source aspect ratio to the target rectangle. - self.fixAspectRatio = fixAspectRatio - - def __init__(self, source: 'Source', target: MF_V3_Settings_Rectangle_Rectangle): - # Image source. - self.source = source - # Image target rectangle. - self.target = target - - def __init__(self, on: bool = None, brightness: float = None, pattern: 'Pattern' = None, image: 'Image' = None, color: List[float] = None): - # Projector on/off. - self.on = on - # Projector brightness. - self.brightness = brightness - # Structured light pattern. - self.pattern = pattern - # Image to project - self.image = image - # Solid color - self.color = color - - diff --git a/maf_three/MF/V3/Settings/Quality.py b/maf_three/MF/V3/Settings/Quality.py deleted file mode 100644 index a1d5011..0000000 --- a/maf_three/MF/V3/Settings/Quality.py +++ /dev/null @@ -1,10 +0,0 @@ -from enum import Enum - - -# Quality settings. -class Quality(Enum): - Low = "Low" # Low quality. - Medium = "Medium" # Medium quality. - High = "High" # High quality. - - diff --git a/maf_three/MF/V3/Settings/Rectangle.py b/maf_three/MF/V3/Settings/Rectangle.py deleted file mode 100644 index 8390e02..0000000 --- a/maf_three/MF/V3/Settings/Rectangle.py +++ /dev/null @@ -1,13 +0,0 @@ -class Rectangle: - # Rectangle settings. - def __init__(self, x: int, y: int, width: int, height: int): - # Rectangle x offset. - self.x = x - # Rectangle y offset. - self.y = y - # Rectangle width. - self.width = width - # Rectangle height. - self.height = height - - diff --git a/maf_three/MF/V3/Settings/Remesh.py b/maf_three/MF/V3/Settings/Remesh.py deleted file mode 100644 index 832d760..0000000 --- a/maf_three/MF/V3/Settings/Remesh.py +++ /dev/null @@ -1,36 +0,0 @@ -from enum import Enum - - -class Remesh: - # Field aligned remesh settings. - # Types of remesh output. - class Type(Enum): - triangle = "triangle" # Triangle mesh output. - quad = "quad" # Quad mesh output. - quadDominant = "quadDominant" # Quad-dominant mesh output. - - def __init__(self, scan: int, type: 'Type' = None, scale: float = None, faceCount: int = None, vertexCount: int = None, creaseAngleThreshold: float = None, extrinsicSmoothness: bool = None, alignToBoundaries: bool = None, smoothIterations: int = None, knnPoints: int = None, deterministic: bool = None): - # The scan index. - self.scan = scan - # The type of output mesh. - self.type = type - # Scale - self.scale = scale - # The approximate number of remeshed faces. - self.faceCount = faceCount - # The approximate number of remeshed vertices. - self.vertexCount = vertexCount - # The crease angle threshold. - self.creaseAngleThreshold = creaseAngleThreshold - # Use extrinsic smoothness. - self.extrinsicSmoothness = extrinsicSmoothness - # Align mesh to boundaries. - self.alignToBoundaries = alignToBoundaries - # The number of smoothing iterations. - self.smoothIterations = smoothIterations - # The number of KNN points (point cloud input only). - self.knnPoints = knnPoints - # Use deterministic (repeatable) remeshing. - self.deterministic = deterministic - - diff --git a/maf_three/MF/V3/Settings/RemoveVertices.py b/maf_three/MF/V3/Settings/RemoveVertices.py deleted file mode 100644 index 1e133de..0000000 --- a/maf_three/MF/V3/Settings/RemoveVertices.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import List - - -class RemoveVertices: - # Remove vertices. - def __init__(self, scans: List[int] = None): - # The scans indexes for which vertices are removed. - self.scans = scans - - diff --git a/maf_three/MF/V3/Settings/Scan.py b/maf_three/MF/V3/Settings/Scan.py deleted file mode 100644 index 7067b3b..0000000 --- a/maf_three/MF/V3/Settings/Scan.py +++ /dev/null @@ -1,157 +0,0 @@ -from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera -from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture -from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector -from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable -from enum import Enum -from typing import List - - -class Scan: - # Scan settings. - class Processing: - # Scan processing settings. - class PhaseEdgeDetection: - """ - Phase edge detection settings. - - Phase edge detection produces a binary mask indicating the edges of a horizontal/vertical pair of phase images. Since flat geometries give a constant phase image gradient, we use the second derivative (Laplacian) of the phase image to detect edges rather than the gradient. - - The edge mask generated by phase edge detection is an input to both phase filtering and adaptive sampling. If neither of these are enabled, the phase edge detection settings have no effect on the output point cloud. - """ - def __init__(self, threshold: float, laplacianKernelRadius: int, gaussianBlurRadius: int, gaussianBlurStdDev: float, maximumWidthForProcessing: int): - # The edge detection threshold. - self.threshold = threshold - # The Laplacian kernel radius. This must be in the range [1..5]. - self.laplacianKernelRadius = laplacianKernelRadius - """ - Gaussian blur kernel radius. (Optional) To disable, set to 0. - The phase images can optionally blurred before taking the Laplacian to reduce noise. - However as a result, the detected edges are wider. - """ - self.gaussianBlurRadius = gaussianBlurRadius - """ - Gaussian blur kernel standard deviation. - This parameter is ignored if `gaussianBlurSize` is zero. - """ - self.gaussianBlurStdDev = gaussianBlurStdDev - """ - The maximum image width for processing. (Optional) To disable, set to 0. - If this value is greater than zero, the phase images are resized to the maximum width prior - to computing the Laplacian and the the detected edges are then upsampled to the original size. - This would be done to speed up processing or to detect edges on a larger scale. - """ - self.maximumWidthForProcessing = maximumWidthForProcessing - - class PhaseFilter: - # Phase filter settings. - def __init__(self, kernelRadius: int, spatialWeightStdDev: float): - """ - The filter kernel radius. - A neighboring value must be within this radius to be included in the filter. - If the kernel radius is set to zero, the phase filtering is disabled. - """ - self.kernelRadius = kernelRadius - """ - The standard deviation of the spatial weights. - The weight of a neighboring value is $\exp(-(r/s)^2)$ where $r$ is the distance - to the central value and $s$ is the spatial weight standard deviation. - If the spatial weight standard deviation is set to zero, all the spatial - weights are uniformly set to 1. - """ - self.spatialWeightStdDev = spatialWeightStdDev - - class AdaptiveSampling: - """ - Adaptive sampling settings - - Adaptive sampling will downsample points in regions of low detail - and keep points in regions of high detail. - """ - class Type(Enum): - NONE = "NONE" # Do not use adaptive sampling. - REGULAR = "REGULAR" # Use a regular sampling mask in regions of low detail. - RANDOM = "RANDOM" # Use a random sampling mask in regions of low detail. - - def __init__(self, type: 'Type', rate: float): - # Sampling type. - self.type = type - # The sample rate [0..1] for the regions of low detail. - self.rate = rate - - class PointClipping: - # Point clipping settings. - # Point clipping type. - class Type(Enum): - OutsideCube = "OutsideCube" # Clip points outside a unit cube. - OutsideCylinder = "OutsideCylinder" # Clip points outside a unit cylinder. - OutsideSphere = "OutsideSphere" # Clip points outside a unit sphere. - InsideCube = "InsideCube" # Clip points inside a unit cube. - InsideCylinder = "InsideCylinder" # Clip points inside a unit cylinder. - InsideSphere = "InsideSphere" # Clip points inside a unit sphere. - - def __init__(self, type: 'Type', transform: List[float] = None): - # Point clipping type. - self.type = type - # 4x4 transform mapping 3D points to the canonical point clipping coordinates. - self.transform = transform - - class NormalEstimation: - # Normal estimation settings. - class Method(Enum): - NORMAL_LLS = "NORMAL_LLS" # Linear least squares method - NORMAL_OPEN3D = "NORMAL_OPEN3D" # Open3D method using KD tree search for nearest neighbors - - def __init__(self, method: 'Method', maximumNeighbourCount: int, maximumNeighbourRadius: float, useMaximumNeighbourCount: bool, useMaximumNeighbourRadius: bool): - # Normal estimation method. - self.method = method - """ - Maximum number of nearest neighbors used to compute the normal. - This value is only used with the NORMAL_OPEN3D method. - """ - self.maximumNeighbourCount = maximumNeighbourCount - # Maximum radius for a point to be considered a neighbour. - self.maximumNeighbourRadius = maximumNeighbourRadius - # Use the maximum neighbour count. - self.useMaximumNeighbourCount = useMaximumNeighbourCount - # Use the maximum neighbour radius. - self.useMaximumNeighbourRadius = useMaximumNeighbourRadius - - class OutlierRemoval: - # Outlier removal settings. - def __init__(self, neighbourCount: int, neighbourRadius: float): - # The minimum number of points within the radius for a point to be retained. - self.neighbourCount = neighbourCount - # The neighbour search radius. - self.neighbourRadius = neighbourRadius - - def __init__(self, projectorSampleRate: float = None, imageSampleRate: float = None, edgeDetection: 'PhaseEdgeDetection' = None, phaseFilter: 'PhaseFilter' = None, adaptiveSampling: 'AdaptiveSampling' = None, pointClipping: List['PointClipping'] = None, normalEstimation: 'NormalEstimation' = None, outlierRemoval: 'OutlierRemoval' = None): - # Projector sample rate. - self.projectorSampleRate = projectorSampleRate - # Image sample rate. - self.imageSampleRate = imageSampleRate - # Phase edge detection settings. - self.edgeDetection = edgeDetection - # Phase filter settings. - self.phaseFilter = phaseFilter - # Adaptive sampling settings. - self.adaptiveSampling = adaptiveSampling - # Point clipping settings. - self.pointClipping = pointClipping - # Normal estimation settings. - self.normalEstimation = normalEstimation - # Outlier removal settings. - self.outlierRemoval = outlierRemoval - - def __init__(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: 'Processing' = None): - # Camera settings. - self.camera = camera - # Projector settings. - self.projector = projector - # Turntable settings. - self.turntable = turntable - # Capture settings. - self.capture = capture - # Processing settings. - self.processing = processing - - diff --git a/maf_three/MF/V3/Settings/ScanData.py b/maf_three/MF/V3/Settings/ScanData.py deleted file mode 100644 index 5bc5314..0000000 --- a/maf_three/MF/V3/Settings/ScanData.py +++ /dev/null @@ -1,40 +0,0 @@ -from enum import Enum -from typing import List - - -class ScanData: - # Scan data request. - # Scan buffer type. - class Buffer(Enum): - Position = "Position" # Vertex position. - Normal = "Normal" # Vertex normal. - Color = "Color" # Vertex color. - UV = "UV" # Vertex UVs - Triangle = "Triangle" # Triangle index. - Texture = "Texture" # Texture. - All = "All" # All buffer types. - - # Scan metadata type. - class Metadata(Enum): - Mean = "Mean" # The mean (centroid) of the vertex positions. - StdDev = "StdDev" # The standard deviation of the vertex positions. - AxisAlignedBoundingBox = "AxisAlignedBoundingBox" # The axis-aligned bounding box of the vertex positions. - - # The merge processing step. - class MergeStep(Enum): - Combined = "Combined" # The scan meshes are simply combined into a single mesh. - Remeshed = "Remeshed" # The combined mesh is remeshed to give a single geometric surface. - Simplified = "Simplified" # The combined or remeshed mesh is simplified to a reduced number of triangles. - Textured = "Textured" # The merged mesh has been textured. - - def __init__(self, index: int, mergeStep: 'MergeStep' = None, buffers: List['Buffer'] = None, metadata: List['Metadata'] = None): - # Requested index of the scan in the current open project. - self.index = index - # The merge process step if requesting merge data. - self.mergeStep = mergeStep - # Requested scan buffers. - self.buffers = buffers - # Requested scan metadata. - self.metadata = metadata - - diff --git a/maf_three/MF/V3/Settings/ScanSelection.py b/maf_three/MF/V3/Settings/ScanSelection.py deleted file mode 100644 index 8c5977d..0000000 --- a/maf_three/MF/V3/Settings/ScanSelection.py +++ /dev/null @@ -1,22 +0,0 @@ -from enum import Enum -from typing import List - - -class ScanSelection: - # Scan selection. - # Scan selection mode. - class Mode(Enum): - selected = "selected" # Select user-selected groups. - visible = "visible" # Select visible scans. - all = "all" # Select all scans. - - def __init__(self, mode: 'Mode', groups: List[int] = None): - # The scan selection mode. - self.mode = mode - """ - The set of user-selected groups. - These are only used if the selection mode is 'selected'. - """ - self.groups = groups - - diff --git a/maf_three/MF/V3/Settings/Scanner.py b/maf_three/MF/V3/Settings/Scanner.py deleted file mode 100644 index 402d3fe..0000000 --- a/maf_three/MF/V3/Settings/Scanner.py +++ /dev/null @@ -1,37 +0,0 @@ -from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced -from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera -from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture -from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n -from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector -from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software -from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style -from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable -from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials -from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer - - -class Scanner: - # Scanner settings. - def __init__(self, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None): - # Advanced settings. - self.advanced = advanced - # Camera settings. - self.camera = camera - # Capture settings. - self.capture = capture - # I18n settings. - self.i18n = i18n - # Projector settings. - self.projector = projector - # Style settings. - self.style = style - # Turntable settings. - self.turntable = turntable - # Tutorials settings. - self.tutorials = tutorials - # Viewer settings. - self.viewer = viewer - # Software update settings. - self.software = software - - diff --git a/maf_three/MF/V3/Settings/Software.py b/maf_three/MF/V3/Settings/Software.py deleted file mode 100644 index 1ebb23c..0000000 --- a/maf_three/MF/V3/Settings/Software.py +++ /dev/null @@ -1,9 +0,0 @@ -class Software: - # Software settings. - def __init__(self, updateMajor: bool = None, updateNightly: bool = None): - # Enable major version updates which can have breaking API changes. - self.updateMajor = updateMajor - # Enable nightly release candidate updates. - self.updateNightly = updateNightly - - diff --git a/maf_three/MF/V3/Settings/Style.py b/maf_three/MF/V3/Settings/Style.py deleted file mode 100644 index 1cfdfc3..0000000 --- a/maf_three/MF/V3/Settings/Style.py +++ /dev/null @@ -1,15 +0,0 @@ -from enum import Enum - - -class Style: - # Style settings. - # Themes. - class Theme(Enum): - Light = "Light" # Light mode. - Dark = "Dark" # Dark mode. - - def __init__(self, theme: 'Theme' = None): - # Theme setting. - self.theme = theme - - diff --git a/maf_three/MF/V3/Settings/Turntable.py b/maf_three/MF/V3/Settings/Turntable.py deleted file mode 100644 index b3b3063..0000000 --- a/maf_three/MF/V3/Settings/Turntable.py +++ /dev/null @@ -1,11 +0,0 @@ -class Turntable: - # Turntable settings. - def __init__(self, scans: int, sweep: int, use: bool = None): - # The number of turntable scans. - self.scans = scans - # Turntable angle sweep in degrees. - self.sweep = sweep - # Use the turntable. - self.use = use - - diff --git a/maf_three/MF/V3/Settings/Tutorials.py b/maf_three/MF/V3/Settings/Tutorials.py deleted file mode 100644 index 569d51a..0000000 --- a/maf_three/MF/V3/Settings/Tutorials.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import List - - -class Tutorials: - # Tutorials settings. - class Viewed: - # Viewed tutorials. - def __init__(self, pages: List[str] = None): - # Viewed tutorials pages. - self.pages = pages - - def __init__(self, show: bool = None, viewed: 'Viewed' = None): - # Show tutorials. - self.show = show - # Viewed tutorials. - self.viewed = viewed - - diff --git a/maf_three/MF/V3/Settings/Video.py b/maf_three/MF/V3/Settings/Video.py deleted file mode 100644 index 8a68ce2..0000000 --- a/maf_three/MF/V3/Settings/Video.py +++ /dev/null @@ -1,31 +0,0 @@ -from enum import Enum - - -class Video: - # Video settings. - # Video codecs. - class Codec(Enum): - NoCodec = "NoCodec" # No codec specified. - RAW = "RAW" # Raw encoding. - JPEG = "JPEG" # JPEG encoding. - H264 = "H264" # H264 encoding. - - # Pixel formats. - class Format(Enum): - NoFormat = "NoFormat" # No format specified. - RGB565 = "RGB565" # RGB565 16-bit - RGB888 = "RGB888" # RGB888 24-bit. - BGR888 = "BGR888" # BGR888 24-bit. - YUV420 = "YUV420" # YUV 420 planar. - - def __init__(self, codec: 'Codec', format: 'Format', width: int, height: int): - # Video codec. - self.codec = codec - # Pixel format. - self.format = format - # Image width. - self.width = width - # Image height. - self.height = height - - diff --git a/maf_three/MF/V3/Settings/Viewer.py b/maf_three/MF/V3/Settings/Viewer.py deleted file mode 100644 index f797ad1..0000000 --- a/maf_three/MF/V3/Settings/Viewer.py +++ /dev/null @@ -1,7 +0,0 @@ -class Viewer: - # 3D Viewer settings. - def __init__(self, textureOpacity: float = None): - # Texture opacity. - self.textureOpacity = textureOpacity - - diff --git a/maf_three/MF/V3/Settings/Wifi.py b/maf_three/MF/V3/Settings/Wifi.py deleted file mode 100644 index bc7b529..0000000 --- a/maf_three/MF/V3/Settings/Wifi.py +++ /dev/null @@ -1,9 +0,0 @@ -class Wifi: - # Wifi connection settings. - def __init__(self, ssid: str, password: str): - # The wifi ssid. - self.ssid = ssid - # The wifi password. - self.password = password - - diff --git a/maf_three/MF/V3/Settings/__init__.py b/maf_three/MF/V3/Settings/__init__.py deleted file mode 100644 index 9fadccd..0000000 --- a/maf_three/MF/V3/Settings/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -from MF.V3.Settings.Advanced import * -from MF.V3.Settings.Align import * -from MF.V3.Settings.AutoFocus import * -from MF.V3.Settings.BoundingBox import * -from MF.V3.Settings.Camera import * -from MF.V3.Settings.Capture import * -from MF.V3.Settings.CopyGroup import * -from MF.V3.Settings.CopyProject import * -from MF.V3.Settings.Export import * -from MF.V3.Settings.Group import * -from MF.V3.Settings.I18n import * -from MF.V3.Settings.Merge import * -from MF.V3.Settings.NewGroup import * -from MF.V3.Settings.Project import * -from MF.V3.Settings.Projector import * -from MF.V3.Settings.Quality import * -from MF.V3.Settings.Rectangle import * -from MF.V3.Settings.Remesh import * -from MF.V3.Settings.RemoveVertices import * -from MF.V3.Settings.Scan import * -from MF.V3.Settings.ScanData import * -from MF.V3.Settings.ScanSelection import * -from MF.V3.Settings.Scanner import * -from MF.V3.Settings.Software import * -from MF.V3.Settings.Style import * -from MF.V3.Settings.Turntable import * -from MF.V3.Settings.Tutorials import * -from MF.V3.Settings.Video import * -from MF.V3.Settings.Viewer import * -from MF.V3.Settings.Wifi import * diff --git a/maf_three/MF/V3/Task.py b/maf_three/MF/V3/Task.py deleted file mode 100644 index b2dbb98..0000000 --- a/maf_three/MF/V3/Task.py +++ /dev/null @@ -1,89 +0,0 @@ -from enum import Enum -from google.protobuf import any_pb2 as _any_pb2 - - -class TaskState(Enum): - Empty = "None" # The task state is not defined. - Sent = "Sent" # The task has been sent by the client. - Received = "Received" # The task has been received by the server. - Started = "Started" # The task started by the server. - Completed = "Completed" # The task is completed by the server. - Cancelled = "Cancelled" # The task has been cancelled by the client. - Failed = "Failed" # The task has failed. A string describing the error is returned with the task. - Dropped = "Dropped" # The task has not been received by the server, or task IDs were sent out of sequence. - Disconnected = "Disconnected" # The client has been disconnected from the server before the task could finish. - - -class Task: - """* - Generic task message for the Three Scanner. - - The task message is the generic message used for requesting a task of the Three Scanner and receiving updates and results. - - Example: Apply camera settings with the "SetCameras" task. - - > Example request: - - ```json - { - "Task":{ - "Index":1, - "Type":"SetCameras" - "Input":{ - "analogGain":256, - "digitalGain":128, - "exposure":18000 - }, - } - } - ``` - - > Example response: - - ```json - { - "Task":{ - "Index":1, - "Type":"SetCameras" - "Input":{ - "analogGain":256, - "digitalGain":512, - "exposure":18000 - }, - "Output":{ - "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, - "digitalGain":{"default":256,"max":65536,"min":256,"value":512}, - "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, - }, - "State":"Completed" - } - } - ``` - """ - class Progress: - # V3 Task Progress Descriptor - def __init__(self, current: int, step: str, total: int): - # The current step of the scan. - self.current = current - # The string description of the current step. - self.step = step - # The total steps in the progress. - self.total = total - - def __init__(self, Index: int, Type: str, Input: _any_pb2 = None, Output: _any_pb2 = None, State: 'TaskState' = None, Error: str = None, Progress: _any_pb2 = None): - # A unique identifier generated by the client. This identifier associates all incoming and outgoing task messages with a specific task requested by the client. - self.Index = Index - # The string identifying the task type. See task definitions for the list of valid task strings. - self.Type = Type - # Optional input message. See each task definition for details. - self.Input = Input - # Optional output message. See each task definition for details. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - # A Progress object for tasks that give updates on long running tasks - self.Progress = Progress - - diff --git a/maf_three/MF/V3/Tasks/AddMergeToProject.py b/maf_three/MF/V3/Tasks/AddMergeToProject.py deleted file mode 100644 index 45d53ff..0000000 --- a/maf_three/MF/V3/Tasks/AddMergeToProject.py +++ /dev/null @@ -1,66 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class AddMergeToProject: - """* - Add a merged scan to the current project. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"AddMergeToProject" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"AddMergeToProject", - "Output":{ - "groups":[ - { - "index":1, - "name":"Scan-1", - "scan": 1, - "color":[0.5, 0.8, 0.3] - } - ] - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `AddMergeToProject` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "AddMergeToProject" - self.Type = Type - - class Response: - # Server response for the `AddMergeToProject` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "AddMergeToProject" - self.Type = Type - # The root scan group in the current open project. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/Align.py b/maf_three/MF/V3/Tasks/Align.py deleted file mode 100644 index ba8fe37..0000000 --- a/maf_three/MF/V3/Tasks/Align.py +++ /dev/null @@ -1,77 +0,0 @@ -from MF.V3.Descriptors.Transform import Transform as MF_V3_Descriptors_Transform_Transform -from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class Align: - """* - Align two scan groups. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"Align", - "Input":{ - "source":1, - "target":2, - "rough":{"method": "FastGlobal"}, - "fine":{"method": "ICP"} - } - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"Align", - "Input":{ - "source":1, - "target":2, - "rough":{"method": "FastGlobal"}, - "fine":{"method": "ICP"} - }, - "Output":{ - "rotation":[0.2, 0.4, 0.6], - "translation":[11, -10, 24] - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `Align` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Align_Align): - # A unique identifier generated by the client. - self.Index = Index - # "Align" - self.Type = Type - # The align settings. - self.Input = Input - - class Response: - # Server response for the `Align` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Align_Align, Output: MF_V3_Descriptors_Transform_Transform, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "Align" - self.Type = Type - # The requested align settings. - self.Input = Input - # The transform that aligns the source scan group to the target scan group. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/AutoFocus.py b/maf_three/MF/V3/Tasks/AutoFocus.py deleted file mode 100644 index d21722d..0000000 --- a/maf_three/MF/V3/Tasks/AutoFocus.py +++ /dev/null @@ -1,94 +0,0 @@ -from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera -from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class AutoFocus: - """* - Auto focus one or both cameras. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"AutoFocus", - "Input":{ - "cameras":[{ - "index":1, - "box":{"x":196,"y":130,"width":64,"height":64} - }], - "applyAll":false - } - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"AutoFocus", - "Input":{ - "cameras":[{ - "index":1, - "box":{"x":196,"y":130,"width":64,"height":64} - }], - "applyAll":false - } - "Output":{ - "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, - "autoExposure":{"default":false,"value":true}, - "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, - "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, - "focus":{ - "box":{ - "default":[ - {"height":64,"width":64,"x":224,"y":158}, - {"height":64,"width":64,"x":224,"y":158} - ], - "value":[ - {"height":64,"width":64,"x":271,"y":134}, - {"height":64,"width":64,"x":196,"y":130} - ] - }, - "value":{"default":[350,350],"max":1024,"min":0,"value":[396,392]} - } - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `AutoFocus` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_AutoFocus_AutoFocus = None): - # A unique identifier generated by the client. - self.Index = Index - # "AutoFocus" - self.Type = Type - # AutoFocus settings. - self.Input = Input - - class Response: - # Server response for the `AutoFocus` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_AutoFocus_AutoFocus = None, Output: MF_V3_Descriptors_Settings_Camera_Camera = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "AutoFocus" - self.Type = Type - # Requested auto focus settings. - self.Input = Input - # Actual camera settings after auto focusing the camera(s). - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/BoundingBox.py b/maf_three/MF/V3/Tasks/BoundingBox.py deleted file mode 100644 index 4a92fd2..0000000 --- a/maf_three/MF/V3/Tasks/BoundingBox.py +++ /dev/null @@ -1,82 +0,0 @@ -from MF.V3.Descriptors.BoundingBox import BoundingBox as MF_V3_Descriptors_BoundingBox_BoundingBox -from MF.V3.Settings.BoundingBox import BoundingBox as MF_V3_Settings_BoundingBox_BoundingBox -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class BoundingBox: - """* - Get the bounding box of a set of scan groups. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"BoundingBox", - "Input":{ - "selection":{"mode":"visible"}, - "axisAligned":false - } - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"BoundingBox", - "Input":{ - "selection":{"mode":"visible"}, - "axisAligned":false - }, - "Output":{ - "center":[11.9,-10.1,94.5], - "rotation":[ - 0.7, -0.7, 0.0, - 0.7, 0.7, 0.0, - 0.0, 0.0, 1.0], - "size":[442.2,253.1,447.1], - "transform":[ - 221, 0.0, 0.0, 11.9, - 0.0, 126, 0.0, -10.1, - 0.0, 0.0, 223, 94.5, - 0.0, 0.0, 0.0, 1.0] - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `BoundingBox` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_BoundingBox_BoundingBox): - # A unique identifier generated by the client. - self.Index = Index - # "BoundingBox" - self.Type = Type - # The bounding box settings. - self.Input = Input - - class Response: - # Server response for the `BoundingBox` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_BoundingBox_BoundingBox, Output: MF_V3_Descriptors_BoundingBox_BoundingBox, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "BoundingBox" - self.Type = Type - # The requested bounding box settings. - self.Input = Input - # The root scan group in the current open project. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/CalibrateCameras.py b/maf_three/MF/V3/Tasks/CalibrateCameras.py deleted file mode 100644 index b56dfa7..0000000 --- a/maf_three/MF/V3/Tasks/CalibrateCameras.py +++ /dev/null @@ -1,58 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class CalibrateCameras: - """* - Calibrate the cameras. - - This task starts the camera calibration capture sequence where the user is guided to place the calibration card with a card outline drawn on the video feed. Once each calibration card pose is captured, the cameras are calibrated and the calibration results are returned as a string. If the cameras cannot be calibrated the task finishes in a `Failed` state. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"CalibrateCameras" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"CalibrateCameras", - "Output":"Camera calibration results: ...", - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `CalibrateCameras` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "CalibrateCameras" - self.Type = Type - - class Response: - # Server response for the `CalibrateCameras` task. - def __init__(self, Index: int, Type: str, Output: str = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "CalibrateCameras" - self.Type = Type - # Camera calibration results. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/CalibrateTurntable.py b/maf_three/MF/V3/Tasks/CalibrateTurntable.py deleted file mode 100644 index 546383c..0000000 --- a/maf_three/MF/V3/Tasks/CalibrateTurntable.py +++ /dev/null @@ -1,61 +0,0 @@ -from MF.V3.Descriptors.Calibration import Turntable as MF_V3_Descriptors_Calibration_Turntable -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class CalibrateTurntable: - """* - Calibrate the turntable. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"CalibrateTurntable" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"CalibrateTurntable", - "Output":{ - "date":[2024,4,27,16,57,35], - "quality":"Excellent", - "focus":[300,320] - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `CalibrateTurntable` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "CalibrateTurntable" - self.Type = Type - - class Response: - # Server response for the `CalibrateTurntable` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_Turntable = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "CalibrateTurntable" - self.Type = Type - # The Turntable calibration descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/CalibrationCaptureTargets.py b/maf_three/MF/V3/Tasks/CalibrationCaptureTargets.py deleted file mode 100644 index 6505b0f..0000000 --- a/maf_three/MF/V3/Tasks/CalibrationCaptureTargets.py +++ /dev/null @@ -1,66 +0,0 @@ -from MF.V3.Descriptors.Calibration import CaptureTarget as MF_V3_Descriptors_Calibration_CaptureTarget -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class CalibrationCaptureTargets: - """* - Get the camera calibration targets. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"CalibrationCaptureTargets" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"CalibrationCaptureTargets", - "Output":{[ - { - "camera":0, - "quads":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] - }, - { - "camera":1, - "quads":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] - }, - ]}, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `CalibrationCaptureTargets` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "CalibrationCaptureTargets" - self.Type = Type - - class Response: - # Server response for the `CalibrationCaptureTargets` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_CaptureTarget = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "CalibrationCaptureTargets" - self.Type = Type - # The calibration capture target descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/CameraCalibration.py b/maf_three/MF/V3/Tasks/CameraCalibration.py deleted file mode 100644 index cabf59a..0000000 --- a/maf_three/MF/V3/Tasks/CameraCalibration.py +++ /dev/null @@ -1,60 +0,0 @@ -from MF.V3.Descriptors.Calibration import Camera as MF_V3_Descriptors_Calibration_Camera -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class CameraCalibration: - """* - Get the camera calibration descriptor. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"CameraCalibration" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"CameraCalibration", - "Output":{ - "date":[2024,4,27,16,57,35], - "quality":"Excellent" - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `CameraCalibration` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "CameraCalibration" - self.Type = Type - - class Response: - # Server response for the `CameraCalibration` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_Camera = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "CameraCalibration" - self.Type = Type - # The camera calibration descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/CloseProject.py b/maf_three/MF/V3/Tasks/CloseProject.py deleted file mode 100644 index 9f17ced..0000000 --- a/maf_three/MF/V3/Tasks/CloseProject.py +++ /dev/null @@ -1,53 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class CloseProject: - """* - Close the current open project. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"CloseProject", - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"CloseProject", - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `CloseProject` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "CloseProject" - self.Type = Type - - class Response: - # Server response for the `CloseProject` task. - def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "CloseProject" - self.Type = Type - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ConnectWifi.py b/maf_three/MF/V3/Tasks/ConnectWifi.py deleted file mode 100644 index 911ef46..0000000 --- a/maf_three/MF/V3/Tasks/ConnectWifi.py +++ /dev/null @@ -1,67 +0,0 @@ -from MF.V3.Settings.Wifi import Wifi as MF_V3_Settings_Wifi_Wifi -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class ConnectWifi: - """* - Connect to a wifi network. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ConnectWifi", - "Input":{ - "ssid":"Network1" - "password":"password" - } - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ConnectWifi", - "Input":{ - { - "ssid":"Network1" - "password":"password" - } - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ConnectWifi` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Wifi_Wifi): - # A unique identifier generated by the client. - self.Index = Index - # "ConnectWifi" - self.Type = Type - # Wifi settings. - self.Input = Input - - class Response: - # Server response for the `ConnectWifi` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Wifi_Wifi, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ConnectWifi" - self.Type = Type - # The requested wifi settings. - self.Input = Input - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/DepthMap.py b/maf_three/MF/V3/Tasks/DepthMap.py deleted file mode 100644 index 4dfcff3..0000000 --- a/maf_three/MF/V3/Tasks/DepthMap.py +++ /dev/null @@ -1,141 +0,0 @@ -from MF.V3.Descriptors.Image import Image as MF_V3_Descriptors_Image_Image -from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan -from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task -from typing import List - - -class DepthMap: - """* - Capture a new scan. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"DepthMap" - "Input":{ - "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, - "capture":{"quality":"Medium","texture":true}, - "projector":{"brightness":0.8} - }, - } - } - ``` - - > Depth map buffer message from server. - - ```json - { - "Buffer":{ - "Index":0, - "Size":13128960, - "Descriptor":{ - "cols":2104, - "rows":1560, - "step":8416, - "type":5 - }, - "Task":{ - "Index":1, - "Type":"DepthMap", - "Input":{ - "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, - "capture":{"quality":"Medium","texture":true}, - "projector":{"brightness":0.8} - } - } - } - } - ``` - - > Depth map binary data transfer from server [13128960 bytes]. - - > Texture buffer message from server. - - ```json - { - "Buffer":{ - "Index":1, - "Size":9846720, - "Descriptor":{ - "cols":2104, - "rows":1560, - "step":6312, - "type":16 - }, - "Task":{ - "Index":1, - "Type":"DepthMap", - "Input":{ - "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, - "capture":{"quality":"Medium","texture":true}, - "projector":{"brightness":0.8} - } - } - } - } - ``` - - > Texture binary data transfer from server [9846720 bytes]. - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"DepthMap" - "Input":{ - "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, - "capture":{"quality":"Medium","texture":true}, - "projector":{"brightness":0.8} - }, - "Output":[2500,0,1052,0,2500,780,0,0,1], - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `DepthMap` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None): - # A unique identifier generated by the client. - self.Index = Index - # "DepthMap" - self.Type = Type - # Scan settings. - self.Input = Input - - class Response: - # Server response for the `DepthMap` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None, Output: List[float] = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "DepthMap" - self.Type = Type - # Requested scan settings. - self.Input = Input - # The 9 values of the camera matrix corresponding to the depth map (row-major). - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - class Buffer: - # Server buffer message for the `DepthMap` task. - def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: MF_V3_Descriptors_Image_Image): - # The zero-based index identifying the data buffer. - self.Index = Index - # The size of the incoming data buffer in bytes. - self.Size = Size - # The requested DepthMap task. - self.Task = Task - # The image descriptor. - self.Descriptor = Descriptor - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/DetectCalibrationCard.py b/maf_three/MF/V3/Tasks/DetectCalibrationCard.py deleted file mode 100644 index 1127f4f..0000000 --- a/maf_three/MF/V3/Tasks/DetectCalibrationCard.py +++ /dev/null @@ -1,65 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class DetectCalibrationCard: - """* - Detect the calibration card on one or both cameras. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"DetectCalibrationCard", - "Input":3 - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Input":3, - "Type":"DetectCalibrationCard", - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `DetectCalibrationCard` task. - def __init__(self, Index: int, Type: str, Input: int): - # A unique identifier generated by the client. - self.Index = Index - # "DetectCalibrationCard" - self.Type = Type - """ - Flag specifying on which camera(s) to detect the calibration card. - [0: neither camera (disable), 1: left camera, 2: right camera, 3: both cameras] - """ - self.Input = Input - - class Response: - # Server response for the `DetectCalibrationCard` task. - def __init__(self, Index: int, Type: str, Input: int, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "DetectCalibrationCard" - self.Type = Type - """ - Flag sent in the request specifying on which camera(s) to detect the calibration card. - [0: neither camera (disable), 1: left camera, 2: right camera, 3: both cameras] - """ - self.Input = Input - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/DownloadProject.py b/maf_three/MF/V3/Tasks/DownloadProject.py deleted file mode 100644 index eb34bd1..0000000 --- a/maf_three/MF/V3/Tasks/DownloadProject.py +++ /dev/null @@ -1,89 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task - - -class DownloadProject: - """* - Download a project from the scanner. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"DownloadProject", - "Input":5 - } - } - ``` - - > Buffer message from server. - - ```json - { - "Buffer":{ - "Descriptor":"Project-5.zip", - "Index":0, - "Size":15682096, - "Task":{ - "Index":1, - "Type":"DownloadProject", - "Input":5 - } - } - } - ``` - - > Binary data transfer from server: The project zip file [15682096 bytes]. - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"DownloadProject" - "Input":5, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `DownloadProject` task. - def __init__(self, Index: int, Type: str, Input: int): - # A unique identifier generated by the client. - self.Index = Index - # "DownloadProject" - self.Type = Type - # Index of the project to download. - self.Input = Input - - class Response: - # Server response for the `DownloadProject` task. - def __init__(self, Index: int, Type: str, Input: int, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "DownloadProject" - self.Type = Type - # Requested index of the project to download. - self.Input = Input - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - class Buffer: - # Server buffer message for the `DownloadProject` task. - def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: str): - # The zero-based index identifying the data buffer. - self.Index = Index - # The size of the incoming data buffer in bytes. - self.Size = Size - # The requested DownloadProject task. - self.Task = Task - # The downloaded project filename. - self.Descriptor = Descriptor - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/Export.py b/maf_three/MF/V3/Tasks/Export.py deleted file mode 100644 index 36209cc..0000000 --- a/maf_three/MF/V3/Tasks/Export.py +++ /dev/null @@ -1,103 +0,0 @@ -from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export -from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task - - -class Export: - """* - Export a group of scans. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"Export", - "Input":{ - "selection":{"mode":"visible"}, - "format":"obj", - "texture":true, - "merge":false - } - } - } - ``` - - > Export file buffer message from server. - - ```json - { - "Buffer":{ - "Index":0, - "Size":8413737, - "Task":{ - "Index":1, - "Type":"Export", - "Input":{ - "selection":{"mode":"visible"}, - "format":"obj", - "texture":true, - "merge":false - } - } - } - } - ``` - - > Export file binary data transfer from server [8413737 bytes]. - - > Response from server: - - ```json - { - "Task":{ - "Index":1, - "Type":"Export" - "Input":{ - "selection":{"mode":"visible"}, - "format":"obj", - "texture":true, - "merge":false - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `Export` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export): - # A unique identifier generated by the client. - self.Index = Index - # "Export" - self.Type = Type - # Export settings. - self.Input = Input - - class Response: - # Server response for the `Export` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "Export" - self.Type = Type - # Requested export settings. - self.Input = Input - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - class Buffer: - # Server buffer message for the `Export` task. - def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): - # The zero-based index identifying the data buffer. - self.Index = Index - # The size of the incoming data buffer in bytes. - self.Size = Size - # The requested Export task. - self.Task = Task - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ExportLogs.py b/maf_three/MF/V3/Tasks/ExportLogs.py deleted file mode 100644 index bb933f6..0000000 --- a/maf_three/MF/V3/Tasks/ExportLogs.py +++ /dev/null @@ -1,87 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task - - -class ExportLogs: - """* - Export scanner logs. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ExportLogs", - "Input":true - } - } - ``` - - > Export file buffer message from server. - - ```json - { - "Buffer":{ - "Index":0, - "Size":41337, - "Task":{ - "Index":1, - "Type":"ExportLogs", - "Input":true - } - } - } - ``` - - > Export file binary data transfer from server [41337 bytes]. - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ExportLogs" - "Input":true, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ExportLogs` task. - def __init__(self, Index: int, Type: str, Input: bool = None): - # A unique identifier generated by the client. - self.Index = Index - # "ExportLogs" - self.Type = Type - # Export log images. If unspecified, log images are not exported. - self.Input = Input - - class Response: - # Server response for the `ExportLogs` task. - def __init__(self, Index: int, Type: str, Input: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ExportLogs" - self.Type = Type - # Requested export log images. - self.Input = Input - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - class Buffer: - # Server buffer message for the `ExportLogs` task. - def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): - # The zero-based index identifying the data buffer. - self.Index = Index - # The size of the incoming data buffer in bytes. - self.Size = Size - # The requested ExportLogs task. - self.Task = Task - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ExportMerge.py b/maf_three/MF/V3/Tasks/ExportMerge.py deleted file mode 100644 index 78a1e45..0000000 --- a/maf_three/MF/V3/Tasks/ExportMerge.py +++ /dev/null @@ -1,97 +0,0 @@ -from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export -from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task - - -class ExportMerge: - """* - Export a merged scan. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ExportMerge", - "Input":{ - "format":"obj", - "texture":true - } - } - } - ``` - - > Export file buffer message from server. - - ```json - { - "Buffer":{ - "Index":0, - "Size":8413737, - "Task":{ - "Index":1, - "Type":"ExportMerge", - "Input":{ - "format":"obj", - "texture":true - } - } - } - } - ``` - - > Export file binary data transfer from server [8413737 bytes]. - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ExportMerge" - "Input":{ - "format":"obj", - "texture":true - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ExportMerge` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export): - # A unique identifier generated by the client. - self.Index = Index - # "ExportMerge" - self.Type = Type - # Export settings. - self.Input = Input - - class Response: - # Server response for the `ExportMerge` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Export_Export, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ExportMerge" - self.Type = Type - # Requested export settings. - self.Input = Input - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - class Buffer: - # Server buffer message for the `ExportMerge` task. - def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): - # The zero-based index identifying the data buffer. - self.Index = Index - # The size of the incoming data buffer in bytes. - self.Size = Size - # The requested ExportMerge task. - self.Task = Task - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/FlattenGroup.py b/maf_three/MF/V3/Tasks/FlattenGroup.py deleted file mode 100644 index c772c6a..0000000 --- a/maf_three/MF/V3/Tasks/FlattenGroup.py +++ /dev/null @@ -1,72 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class FlattenGroup: - """* - Flatten a scan group such that it only consists of single scans. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"FlattenGroup", - "Input":0 - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"FlattenGroup", - "Input":0, - "Output":{ - "groups":[{ - "index":2, - "name":"Group 2", - "groups":[{ - "index":1, - "name":"Group 1" - }] - }], - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `FlattenGroup` task. - def __init__(self, Index: int, Type: str, Input: int): - # A unique identifier generated by the client. - self.Index = Index - # "FlattenGroup" - self.Type = Type - # The index of the group to flatten. - self.Input = Input - - class Response: - # Server response for the `FlattenGroup` task. - def __init__(self, Index: int, Type: str, Input: int, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "FlattenGroup" - self.Type = Type - # The requested index of the group to flatten. - self.Input = Input - # The root scan group in the current open project. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ForgetWifi.py b/maf_three/MF/V3/Tasks/ForgetWifi.py deleted file mode 100644 index 7b192ed..0000000 --- a/maf_three/MF/V3/Tasks/ForgetWifi.py +++ /dev/null @@ -1,53 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class ForgetWifi: - """* - Forget all wifi connections. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ForgetWifi" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ForgetWifi" - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ForgetWifi` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "ForgetWifi" - self.Type = Type - - class Response: - # Server response for the `ForgetWifi` task. - def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ForgetWifi" - self.Type = Type - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/HasCameras.py b/maf_three/MF/V3/Tasks/HasCameras.py deleted file mode 100644 index 0bf9c8d..0000000 --- a/maf_three/MF/V3/Tasks/HasCameras.py +++ /dev/null @@ -1,56 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class HasCameras: - """* - Check if the scanner has working cameras. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"HasCameras" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"HasCameras", - "Output":true, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `HasCameras` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "HasCameras" - self.Type = Type - - class Response: - # Server response for the `HasCameras` task. - def __init__(self, Index: int, Type: str, Output: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "HasCameras" - self.Type = Type - # The working state of the cameras. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/HasProjector.py b/maf_three/MF/V3/Tasks/HasProjector.py deleted file mode 100644 index 9b40f11..0000000 --- a/maf_three/MF/V3/Tasks/HasProjector.py +++ /dev/null @@ -1,56 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class HasProjector: - """* - Check if the scanner has a working projector. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"HasProjector" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"HasProjector", - "Output":true, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `HasProjector` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "HasProjector" - self.Type = Type - - class Response: - # Server response for the `HasProjector` task. - def __init__(self, Index: int, Type: str, Output: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "HasProjector" - self.Type = Type - # The working state of the projector. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/HasTurntable.py b/maf_three/MF/V3/Tasks/HasTurntable.py deleted file mode 100644 index d56fc1a..0000000 --- a/maf_three/MF/V3/Tasks/HasTurntable.py +++ /dev/null @@ -1,56 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class HasTurntable: - """* - Check if the scanner is connected to a working turntable. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"HasTurntable" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"HasTurntable", - "Output":true, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `HasTurntable` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "HasTurntable" - self.Type = Type - - class Response: - # Server response for the `HasTurntable` task. - def __init__(self, Index: int, Type: str, Output: bool = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "HasTurntable" - self.Type = Type - # The working start of the connected turntable. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ListExportFormats.py b/maf_three/MF/V3/Tasks/ListExportFormats.py deleted file mode 100644 index 326b812..0000000 --- a/maf_three/MF/V3/Tasks/ListExportFormats.py +++ /dev/null @@ -1,86 +0,0 @@ -from MF.V3.Descriptors.Export import Export as MF_V3_Descriptors_Export_Export -from MF.V3.Task import TaskState as MF_V3_Task_TaskState -from typing import List - - -class ListExportFormats: - """* - List all export formats and the geometry elements they support. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListExportFormats" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListExportFormats", - "Output":{[ - { - "format": "ply", - "colors": true, - "description": "Polygon format", - "extension": ".ply", - "faces": ["Point","Triangle","Quad"], - "normals": true, - "textures": "Single" - }, - { - "format": "obj", - "colors": true, - "description": "Wavefront format", - "extension": ".obj", - "faces": ["Point","Triangle","Quad"], - "normals": true, - "textures": "Multiple" - }, - { - "format": "stl", - "colors": false, - "description": "Stereolithography format", - "extension": ".stl", - "faces": ["Point","Triangle"], - "normals": true, - "textures": "None" - } - ]}, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ListExportFormats` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "ListExportFormats" - self.Type = Type - - class Response: - # Server response for the `ListExportFormats` task. - def __init__(self, Index: int, Type: str, Output: List[MF_V3_Descriptors_Export_Export] = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ListExportFormats" - self.Type = Type - # The list of export format descriptors. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ListGroups.py b/maf_three/MF/V3/Tasks/ListGroups.py deleted file mode 100644 index 10ba504..0000000 --- a/maf_three/MF/V3/Tasks/ListGroups.py +++ /dev/null @@ -1,85 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class ListGroups: - """* - List the scan groups in the current open project. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListGroups" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListGroups", - "Output":{ - "groups":[ - { - "index":1, - "scan":1, - "name":"Scan-1", - "color":[0.75,0.5,0.2,1.0], - "rotation":[0.03,0.1,-0.01], - "translation":[-101,67,-561], - "visible":true - }, - { - "index":2, - "scan":2, - "name":"Scan-2", - "color":[0.7,0.9,0.6,1.0], - "rotation":[0.1,0.2,0.5], - "translation":[-90,64,-553], - "visible":true - }, - { - "index":3, - "scan":3, - "name":"Scan-3", - "color":[0.6,0.8,0.9,1.0], - "visible":true - } - ] - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ListGroups` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "ListGroups" - self.Type = Type - - class Response: - # Server response for the `ListGroups` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ListGroups" - self.Type = Type - # The root scan group in the current open project. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ListNetworkInterfaces.py b/maf_three/MF/V3/Tasks/ListNetworkInterfaces.py deleted file mode 100644 index 763cb9d..0000000 --- a/maf_three/MF/V3/Tasks/ListNetworkInterfaces.py +++ /dev/null @@ -1,61 +0,0 @@ -from MF.V3.Descriptors.Network import Interface as MF_V3_Descriptors_Network_Interface -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class ListNetworkInterfaces: - """* - List network interfaces. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListNetworkInterfaces" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListNetworkInterfaces", - "Output":[ - {"ip":"192.168.1.234","name":"eth0","ssid":""}, - {"ip":"127.0.0.1","name":"lo","ssid":""} - {"ip":"192.168.2.345","name":"wlan0","ssid":"Network1"} - ], - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ListNetworkInterfaces` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "ListNetworkInterfaces" - self.Type = Type - - class Response: - # Server response for the `ListNetworkInterfaces` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Network_Interface = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ListNetworkInterfaces" - self.Type = Type - # Network interface descriptors. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ListProjects.py b/maf_three/MF/V3/Tasks/ListProjects.py deleted file mode 100644 index 6216681..0000000 --- a/maf_three/MF/V3/Tasks/ListProjects.py +++ /dev/null @@ -1,61 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class ListProjects: - """* - List all projects. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListProjects" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListProjects", - "Output":[ - {"index":1,"modified":[2024,5,12,11,23,17],"name":"Project 1","size":35409834}, - {"index":2,"modified":[2024,5,12,11,2,37],"name":"Project 2","size":175025367}, - {"index":3,"modified":[2024,5,6,17,15,53],"name":"Project 3","size":24314083} - ], - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ListProjects` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "ListProjects" - self.Type = Type - - class Response: - # Server response for the `ListProjects` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Brief = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ListProjects" - self.Type = Type - # Brief project descriptors. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ListScans.py b/maf_three/MF/V3/Tasks/ListScans.py deleted file mode 100644 index 8926274..0000000 --- a/maf_three/MF/V3/Tasks/ListScans.py +++ /dev/null @@ -1,77 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState -from typing import List - - -class ListScans: - """* - List the scans in the current open project. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListScans" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListScans", - "Output":{[ - { - "color":[0.8,0.5,0.6,1.0], - "index":1, - "name":"Scan-1", - "scan":1, - "rotation":[0.2,0.8,-0.1], - "translation":[-275,-32,-134], - "visible":true - }, - { - "color":[0.5,0.7,0.2,1.0], - "index":2, - "name":"Scan-2", - "scan":2, - "rotation":[0.7,-0.5,0.3], - "translation":[75,-62,38], - "visible":true - }, - ]}, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ListScans` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "ListScans" - self.Type = Type - - class Response: - # Server response for the `ListScans` task. - def __init__(self, Index: int, Type: str, Output: List[MF_V3_Descriptors_Project_Project.Group] = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ListScans" - self.Type = Type - # The list of scans in the current open project. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ListSettings.py b/maf_three/MF/V3/Tasks/ListSettings.py deleted file mode 100644 index 238935c..0000000 --- a/maf_three/MF/V3/Tasks/ListSettings.py +++ /dev/null @@ -1,86 +0,0 @@ -from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class ListSettings: - """* - Get scanner settings. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListSettings" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListSettings", - "Output":{ - "camera":{ - "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, - "autoExposure":{"default":false,"value":false}, - "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, - "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, - }, - "projector":{ - "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, - "on":{"default":false,"value":true} - }, - "turntable":{ - "scans":{"default":8,"max":24,"min":1,"value":3}, - "sweep":{"default":360,"max":360,"min":5,"value":90}, - "use":{"default":true,"value":true} - }, - "capture":{ - "quality":{"default":"Medium","value":"Medium"}, - "texture":{"default":true,"value":true} - }, - "i18n":{ - "language":{"default":"en","value":"en"} - }, - "style":{ - "theme":{"default":"Dark","value":"Dark"} - }, - "viewer":{ - "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} - } - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ListSettings` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "ListSettings" - self.Type = Type - - class Response: - # Server response for the `ListSettings` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ListSettings" - self.Type = Type - # The scanner settings descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ListWifi.py b/maf_three/MF/V3/Tasks/ListWifi.py deleted file mode 100644 index 223010e..0000000 --- a/maf_three/MF/V3/Tasks/ListWifi.py +++ /dev/null @@ -1,64 +0,0 @@ -from MF.V3.Descriptors.Wifi import Wifi as MF_V3_Descriptors_Wifi_Wifi -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class ListWifi: - """* - List available wifi networks. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListWifi" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ListWifi", - "Output":{ - "networks":[ - {"ssid":"Network1","isActive":true,"isPublic":false,"quality":90}, - {"ssid":"Network2","isActive":true,"isPublic":true,"quality":50}, - {"ssid":"Network3","isActive":true,"isPublic":true,"quality":75} - ], - "ssid":"Network1" - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ListWifi` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "ListWifi" - self.Type = Type - - class Response: - # Server response for the `ListWifi` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Wifi_Wifi = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ListWifi" - self.Type = Type - # The wifi descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/Merge.py b/maf_three/MF/V3/Tasks/Merge.py deleted file mode 100644 index 70ab574..0000000 --- a/maf_three/MF/V3/Tasks/Merge.py +++ /dev/null @@ -1,104 +0,0 @@ -from MF.V3.Descriptors.Merge import Merge as MF_V3_Descriptors_Merge_Merge -from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class Merge: - """* - Merge two or more scan groups. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"Merge", - "Input":{ - "selection":{"mode":"visible"}, - "remesh":{ - "method": "FlowTriangles", - "quality": "Medium" - }, - "simplify":{"triangleCount": 20000 } - } - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"Merge", - "Input":{ - "selection":{"mode":"visible"}, - "remesh":{ - "method": "FlowTriangles", - "quality": "Medium" - }, - "simplify":{"triangleCount": 20000 } - }, - "Output":{ - "meshes":[ - { - "name":"Combined", - "positions":237757, - "normals":237757, - "triangles":459622, - "size":11221632 - }, - { - "name":"Remeshed", - "positions":34311, - "normals":0, - "triangles":29738, - "size":945540 - }, - { - "name":"Simplified", - "positions":32415, - "normals":0, - "triangles":20000, - "size":628980 - } - ], - "scans":3, - "textures":3 - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `Merge` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Merge_Merge): - # A unique identifier generated by the client. - self.Index = Index - # "Merge" - self.Type = Type - # The merge settings. - self.Input = Input - - class Response: - # Server response for the `Merge` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Merge_Merge, Output: MF_V3_Descriptors_Merge_Merge, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "Merge" - self.Type = Type - # The requested merge settings. - self.Input = Input - # The merge descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/MergeData.py b/maf_three/MF/V3/Tasks/MergeData.py deleted file mode 100644 index b9c0d68..0000000 --- a/maf_three/MF/V3/Tasks/MergeData.py +++ /dev/null @@ -1,239 +0,0 @@ -from MF.V3.Descriptors.ScanData import ScanData as MF_V3_Descriptors_ScanData_ScanData -from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData -from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task - - -class MergeData: - """* - Download the raw scan data for the current merge process. - - > Request example: - - ``` - { - "Task":{ - "Index":1, - "Type":"MergeData", - "Input":{ - "index":-1, - "buffers":["All"] - } - } - } - ``` - - > Vertex position buffer message from server. - - ```json - { - "Buffer":{ - "Index":0, - "Size":1558188, - "Descriptor":{ - "components":[{ - "type":"Position" - "size":3, - "offset":0, - "normalized":false, - }], - "stride":3 - }, - "Task":{ - "Index":1, - "Type":"MergeData", - "Input":{ - "index":1, - "buffers":["All"] - } - } - } - } - ``` - - > Vertex position binary data transfer from server [1558188 bytes]. - - > Vertex normal buffer message from server. - - ```json - { - "Buffer":{ - "Index":1, - "Size":1558188, - "Descriptor":{ - "components":[{ - "type":"Normal" - "size":3, - "offset":0, - "normalized":false, - }], - "stride":3 - }, - "Task":{ - "Index":1, - "Type":"MergeData", - "Input":{ - "index":1, - "buffers":["All"] - } - } - } - } - ``` - - > Vertex normal binary data transfer from server [1558188 bytes]. - - > Vertex texture coordinate buffer message from server. - - ```json - { - "Buffer":{ - "Index":2, - "Size":1038792, - "Descriptor":{ - "components":[{ - "type":"UV" - "size":2, - "offset":0, - "normalized":false, - }], - "stride":2 - }, - "Task":{ - "Index":1, - "Type":"MergeData", - "Input":{ - "index":1, - "buffers":["All"] - } - } - } - } - ``` - - > Vertex texture coordinate binary data transfer from server [1038792 bytes]. - - > Texture image buffer message from server. - - ```json - { - "Buffer":{ - "Index":3, - "Size":3504494, - "Descriptor":{ - "components":[{ - "type":"Texture" - "size":0, - "offset":0, - "normalized":false, - }], - "stride":0 - }, - "Task":{ - "Index":1, - "Type":"MergeData", - "Input":{ - "index":1, - "buffers":["All"] - } - } - } - } - ``` - - > Texture binary data transfer from server [3504494 bytes]. - - > Triangle index buffer message from server. - - ```json - { - "Buffer":{ - "Index":4, - "Size":1996356, - "Descriptor":{ - "components":[{ - "type":"Triangle" - "size":1, - "offset":0, - "normalized":false, - }], - "stride":1 - }, - "Task":{ - "Index":1, - "Type":"MergeData", - "Input":{ - "index":1, - "buffers":["All"] - } - } - } - } - ``` - - > Triangle index binary data transfer from server [1996356 bytes]. - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"MergeData" - "Input":{"index":-1,"buffers":["All"]}, - "Output":{ - "buffers":[ - {"components":[{"normalized":false,"offset":0,"size":3,"type":"Position"}],"stride":3}, - {"components":[{"normalized":false,"offset":0,"size":3,"type":"Normal"}],"stride":3}, - {"components":[{"normalized":false,"offset":0,"size":2,"type":"UV"}],"stride":2}, - {"components":[{"normalized":false,"offset":0,"size":0,"type":"Texture"}],"stride":0}, - {"components":[{"normalized":false,"offset":0,"size":1,"type":"Triangle"}],"stride":1} - ], - "index":1, - "name":"Scan-1" - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `MergeData` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData): - # A unique identifier generated by the client. - self.Index = Index - # "MergeData" - self.Type = Type - # Requested scan data. - self.Input = Input - - class Response: - # Server response for the `MergeData` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData, Output: MF_V3_Descriptors_ScanData_ScanData, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "MergeData" - self.Type = Type - # The scan data requested by the client. - self.Input = Input - # The scan data sent from the server. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - class Buffer: - # Server buffer message for the `MergeData` task. - def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: MF_V3_Descriptors_ScanData_ScanData.Buffer): - # The zero-based index identifying the data buffer. - self.Index = Index - # The size of the incoming data buffer in bytes. - self.Size = Size - # The requested MergeData task. - self.Task = Task - # The scan data buffer descriptor. - self.Descriptor = Descriptor - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/MoveGroup.py b/maf_three/MF/V3/Tasks/MoveGroup.py deleted file mode 100644 index ba5d1aa..0000000 --- a/maf_three/MF/V3/Tasks/MoveGroup.py +++ /dev/null @@ -1,79 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState -from typing import List - - -class MoveGroup: - """* - Move a scan group. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"MoveGroup", - "Input":[1,2,0] - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"MoveGroup", - "Input":[1,2,0], - "Output":{ - "groups":[{ - "index":2, - "name":"Group 2", - "groups":[{ - "index":1, - "name":"Group 1" - }] - }], - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `MoveGroup` task. - def __init__(self, Index: int, Type: str, Input: List[int] = None): - # A unique identifier generated by the client. - self.Index = Index - # "MoveGroup" - self.Type = Type - """ - The requested source and destination move indices. - An Array of group indexes where - 1. The first is the index of the _source group_: the group to be moved. - 2. The second is the index of the _parent group_: the group into which the source group is moved. - 3. (Optional) The third is the zero-based order in which the source group is placed the other children of the parent group. Use `0` to insert the source group at the beginning of the parent group's children. If omitted, the source group is inserted at the end of the parent group's children. - """ - self.Input = Input - - class Response: - # Server response for the `MoveGroup` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, Input: List[int] = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "MoveGroup" - self.Type = Type - # The root scan group in the current open project. - self.Output = Output - # The requested source and destination move indices. - self.Input = Input - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/NewGroup.py b/maf_three/MF/V3/Tasks/NewGroup.py deleted file mode 100644 index 93db660..0000000 --- a/maf_three/MF/V3/Tasks/NewGroup.py +++ /dev/null @@ -1,77 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Settings.NewGroup import NewGroup as MF_V3_Settings_NewGroup_NewGroup -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class NewGroup: - """* - Create a new scan group. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"NewGroup", - "Input":{ - "parentIndex":0, - "baseName":"Group" - } - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"NewGroup", - "Input":{ - "parentIndex":0, - "baseName":"Group" - }, - "Output":{ - "groups":[ - { - "index":1, - "name":"Group 1" - } - ] - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `NewGroup` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_NewGroup_NewGroup = None): - # A unique identifier generated by the client. - self.Index = Index - # "NewGroup" - self.Type = Type - # The requested new group settings. - self.Input = Input - - class Response: - # Server response for the `NewGroup` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, Input: MF_V3_Settings_NewGroup_NewGroup = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "NewGroup" - self.Type = Type - # The root scan group in the current open project. - self.Output = Output - # The requested new group settings. - self.Input = Input - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/NewProject.py b/maf_three/MF/V3/Tasks/NewProject.py deleted file mode 100644 index 28ebce7..0000000 --- a/maf_three/MF/V3/Tasks/NewProject.py +++ /dev/null @@ -1,69 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class NewProject: - """* - Create a new project. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"NewProject", - "Input":"New Project Name" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"NewProject", - "Input":{ - "name":"New Project Name" - }, - "Output":{ - "index":5, - "name":"New Project Name" - } - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `NewProject` task. - def __init__(self, Index: int, Type: str, Input: str = None): - # A unique identifier generated by the client. - self.Index = Index - # "NewProject" - self.Type = Type - # Optional new project name. - self.Input = Input - - class Response: - # Server response for the `NewProject` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Project_Project = None, Output: MF_V3_Descriptors_Project_Project = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "NewProject" - self.Type = Type - # Requested new project name. - self.Input = Input - # The new project descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/NewScan.py b/maf_three/MF/V3/Tasks/NewScan.py deleted file mode 100644 index 2107534..0000000 --- a/maf_three/MF/V3/Tasks/NewScan.py +++ /dev/null @@ -1,82 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class NewScan: - """* - Capture a new scan. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"NewScan" - "Input":{ - "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, - "capture":{"quality":"Medium","texture":true}, - "projector":{"brightness":0.8} - }, - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"NewScan" - "Input":{ - "camera":{"exposure":18000,"analogGain":256,"digitalGain":256}, - "capture":{"quality":"Medium","texture":true}, - "projector":{"brightness":0.8} - }, - "Output":{ - "groups":[{ - "color":[0.8,0.5,0.6,1.0], - "index":1, - "name":"Scan-1", - "scan":1, - "rotation":[0.2,0.8,-0.1], - "translation":[-275,-32,-134], - "visible":true - }], - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `NewScan` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None): - # A unique identifier generated by the client. - self.Index = Index - # "NewScan" - self.Type = Type - # Scan settings. - self.Input = Input - - class Response: - # Server response for the `NewScan` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scan_Scan = None, Output: MF_V3_Descriptors_Project_Project.Group = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "NewScan" - self.Type = Type - # Requested scan settings. - self.Input = Input - # Project group descriptor with the updated list of scans. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/OpenProject.py b/maf_three/MF/V3/Tasks/OpenProject.py deleted file mode 100644 index 06c6fa2..0000000 --- a/maf_three/MF/V3/Tasks/OpenProject.py +++ /dev/null @@ -1,66 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class OpenProject: - """* - Create a new project. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"OpenProject", - "Input":5 - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"OpenProject", - "Input":5, - "Output":{ - "index":5, - "name":"Project 5" - } - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `OpenProject` task. - def __init__(self, Index: int, Type: str, Input: int): - # A unique identifier generated by the client. - self.Index = Index - # "OpenProject" - self.Type = Type - # The index of the project to open. Project indices can be obtained from the `ListProjects` task. - self.Input = Input - - class Response: - # Server response for the `OpenProject` task. - def __init__(self, Index: int, Type: str, Input: int, Output: MF_V3_Descriptors_Project_Project = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "OpenProject" - self.Type = Type - # The index of the project requested to open. - self.Input = Input - # The open project descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/PopSettings.py b/maf_three/MF/V3/Tasks/PopSettings.py deleted file mode 100644 index 80916e5..0000000 --- a/maf_three/MF/V3/Tasks/PopSettings.py +++ /dev/null @@ -1,92 +0,0 @@ -from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class PopSettings: - """* - Pop and restore scanner settings from the stack and optionally apply the popped settings. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"PopSettings", - "Input":true - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"PopSettings", - "Input":true, - "Output":{ - "camera":{ - "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, - "autoExposure":{"default":false,"value":false}, - "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, - "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, - }, - "projector":{ - "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, - "on":{"default":false,"value":true} - }, - "turntable":{ - "scans":{"default":8,"max":24,"min":1,"value":3}, - "sweep":{"default":360,"max":360,"min":5,"value":90}, - "use":{"default":true,"value":true} - }, - "capture":{ - "quality":{"default":"Medium","value":"Medium"}, - "texture":{"default":true,"value":true} - }, - "i18n":{ - "language":{"default":"en","value":"en"} - }, - "style":{ - "theme":{"default":"Dark","value":"Dark"} - }, - "viewer":{ - "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} - } - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `PopSettings` task. - def __init__(self, Index: int, Type: str, Input: bool = None): - # A unique identifier generated by the client. - self.Index = Index - # "PopSettings" - self.Type = Type - # Apply the popped settings. If unspecified popped settings are not applied. - self.Input = Input - - class Response: - # Server response for the `PopSettings` task. - def __init__(self, Index: int, Type: str, Input: bool = None, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "PopSettings" - self.Type = Type - # Request to apply the popped settings. - self.Input = Input - # The scanner settings descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/PushSettings.py b/maf_three/MF/V3/Tasks/PushSettings.py deleted file mode 100644 index feaf6b0..0000000 --- a/maf_three/MF/V3/Tasks/PushSettings.py +++ /dev/null @@ -1,86 +0,0 @@ -from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class PushSettings: - """* - Push the current scanner settings to a stack so they can be restored with PopSettings. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"PushSettings" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"PushSettings", - "Output":{ - "camera":{ - "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, - "autoExposure":{"default":false,"value":false}, - "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, - "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, - }, - "projector":{ - "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, - "on":{"default":false,"value":true} - }, - "turntable":{ - "scans":{"default":8,"max":24,"min":1,"value":3}, - "sweep":{"default":360,"max":360,"min":5,"value":90}, - "use":{"default":true,"value":true} - }, - "capture":{ - "quality":{"default":"Medium","value":"Medium"}, - "texture":{"default":true,"value":true} - }, - "i18n":{ - "language":{"default":"en","value":"en"} - }, - "style":{ - "theme":{"default":"Dark","value":"Dark"} - }, - "viewer":{ - "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} - } - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `PushSettings` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "PushSettings" - self.Type = Type - - class Response: - # Server response for the `PushSettings` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "PushSettings" - self.Type = Type - # The scanner settings descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/Reboot.py b/maf_three/MF/V3/Tasks/Reboot.py deleted file mode 100644 index c954807..0000000 --- a/maf_three/MF/V3/Tasks/Reboot.py +++ /dev/null @@ -1,53 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class Reboot: - """* - Reboot the scanner. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"Reboot" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"Reboot" - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `Reboot` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "Reboot" - self.Type = Type - - class Response: - # Server response for the `Reboot` task. - def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "Reboot" - self.Type = Type - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/RemoveGroups.py b/maf_three/MF/V3/Tasks/RemoveGroups.py deleted file mode 100644 index cc0cbd3..0000000 --- a/maf_three/MF/V3/Tasks/RemoveGroups.py +++ /dev/null @@ -1,64 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState -from typing import List - - -class RemoveGroups: - """* - Remove selected scan groups. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"RemoveGroups", - "Input":[1,2] - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"RemoveGroups", - "Input":[1,2], - "Output":{"groups":[]}, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `RemoveGroups` task. - def __init__(self, Index: int, Type: str, Input: List[int] = None): - # A unique identifier generated by the client. - self.Index = Index - # "RemoveGroups" - self.Type = Type - # The list of indices of the scan groups to remove. - self.Input = Input - - class Response: - # Server response for the `RemoveGroups` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Project_Project.Group, Input: List[int] = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "RemoveGroups" - self.Type = Type - # The root scan group in the current open project. - self.Output = Output - # The requested of indices of the scan groups to remove. - self.Input = Input - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/RemoveProjects.py b/maf_three/MF/V3/Tasks/RemoveProjects.py deleted file mode 100644 index aef7e61..0000000 --- a/maf_three/MF/V3/Tasks/RemoveProjects.py +++ /dev/null @@ -1,68 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState -from typing import List - - -class RemoveProjects: - """* - Remove selected projects. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"RemoveProjects", - "Input":[1,3,6] - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"RemoveProjects", - "Input":[1,3,6], - "Output":[ - {"index":2,"modified":[2024,5,12,11,23,17],"name":"Project 2","size":35409834}, - {"index":4,"modified":[2024,5,12,11,2,37],"name":"Project 4","size":175025367}, - {"index":5,"modified":[2024,5,6,17,15,53],"name":"Project 5","size":24314083} - ], - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `RemoveProjects` task. - def __init__(self, Index: int, Type: str, Input: List[int] = None): - # A unique identifier generated by the client. - self.Index = Index - # "RemoveProjects" - self.Type = Type - # The list of indices of the projects to remove. - self.Input = Input - - class Response: - # Server response for the `RemoveProjects` task. - def __init__(self, Index: int, Type: str, Input: List[int] = None, Output: MF_V3_Descriptors_Project_Project.Brief = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "RemoveProjects" - self.Type = Type - # The list of indices of the requested projects to remove. - self.Input = Input - # Brief descriptors of the remaining projects. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/RestoreFactoryCalibration.py b/maf_three/MF/V3/Tasks/RestoreFactoryCalibration.py deleted file mode 100644 index 4caea88..0000000 --- a/maf_three/MF/V3/Tasks/RestoreFactoryCalibration.py +++ /dev/null @@ -1,53 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class RestoreFactoryCalibration: - """* - Restore factory calibration. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"RestoreFactoryCalibration" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"RestoreFactoryCalibration", - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `RestoreFactoryCalibration` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "RestoreFactoryCalibration" - self.Type = Type - - class Response: - # Server response for the `RestoreFactoryCalibration` task. - def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "RestoreFactoryCalibration" - self.Type = Type - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/RotateTurntable.py b/maf_three/MF/V3/Tasks/RotateTurntable.py deleted file mode 100644 index 219c752..0000000 --- a/maf_three/MF/V3/Tasks/RotateTurntable.py +++ /dev/null @@ -1,59 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class RotateTurntable: - """* - Rotate the turntable. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"RotateTurntable", - "Input":15 - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"RotateTurntable", - "Input":15, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `RotateTurntable` task. - def __init__(self, Index: int, Type: str, Input: int): - # A unique identifier generated by the client. - self.Index = Index - # "RotateTurntable" - self.Type = Type - # The rotation angle in degrees. - self.Input = Input - - class Response: - # Server response for the `RotateTurntable` task. - def __init__(self, Index: int, Type: str, Input: int, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "RotateTurntable" - self.Type = Type - # The requested rotation angle in degrees. - self.Input = Input - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/ScanData.py b/maf_three/MF/V3/Tasks/ScanData.py deleted file mode 100644 index c5ecab3..0000000 --- a/maf_three/MF/V3/Tasks/ScanData.py +++ /dev/null @@ -1,239 +0,0 @@ -from MF.V3.Descriptors.ScanData import ScanData as MF_V3_Descriptors_ScanData_ScanData -from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData -from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task - - -class ScanData: - """* - Download the raw scan data for a scan in the current open project. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ScanData", - "Input":{ - "index":1, - "buffers":["All"] - } - } - } - ``` - - > Vertex position buffer message from server. - - ```json - { - "Buffer":{ - "Index":0, - "Size":1558188, - "Descriptor":{ - "components":[{ - "type":"Position" - "size":3, - "offset":0, - "normalized":false, - }], - "stride":3 - }, - "Task":{ - "Index":1, - "Type":"ScanData", - "Input":{ - "index":1, - "buffers":["All"] - } - } - } - } - ``` - - > Vertex position binary data transfer from server [1558188 bytes]. - - > Vertex normal buffer message from server. - - ```json - { - "Buffer":{ - "Index":1, - "Size":1558188, - "Descriptor":{ - "components":[{ - "type":"Normal" - "size":3, - "offset":0, - "normalized":false, - }], - "stride":3 - }, - "Task":{ - "Index":1, - "Type":"ScanData", - "Input":{ - "index":1, - "buffers":["All"] - } - } - } - } - ``` - - > Vertex normal binary data transfer from server [1558188 bytes]. - - > Vertex texture coordinate buffer message from server. - - ```json - { - "Buffer":{ - "Index":2, - "Size":1038792, - "Descriptor":{ - "components":[{ - "type":"UV" - "size":2, - "offset":0, - "normalized":false, - }], - "stride":2 - }, - "Task":{ - "Index":1, - "Type":"ScanData", - "Input":{ - "index":1, - "buffers":["All"] - } - } - } - } - ``` - - > Vertex texture coordinate binary data transfer from server [1038792 bytes]. - - > Texture image buffer message from server. - - ```json - { - "Buffer":{ - "Index":3, - "Size":3504494, - "Descriptor":{ - "components":[{ - "type":"Texture" - "size":0, - "offset":0, - "normalized":false, - }], - "stride":0 - }, - "Task":{ - "Index":1, - "Type":"ScanData", - "Input":{ - "index":1, - "buffers":["All"] - } - } - } - } - ``` - - > Texture binary data transfer from server [3504494 bytes]. - - > Triangle index buffer message from server. - - ```json - { - "Buffer":{ - "Index":4, - "Size":1996356, - "Descriptor":{ - "components":[{ - "type":"Triangle" - "size":1, - "offset":0, - "normalized":false, - }], - "stride":1 - }, - "Task":{ - "Index":1, - "Type":"ScanData", - "Input":{ - "index":1, - "buffers":["All"] - } - } - } - } - ``` - - > Triangle index binary data transfer from server [1996356 bytes]. - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"ScanData", - "Input":{"buffers":["All"],"index":1}, - "Output":{ - "buffers":[ - {"components":[{"normalized":false,"offset":0,"size":3,"type":"Position"}],"stride":3}, - {"components":[{"normalized":false,"offset":0,"size":3,"type":"Normal"}],"stride":3}, - {"components":[{"normalized":false,"offset":0,"size":2,"type":"UV"}],"stride":2}, - {"components":[{"normalized":false,"offset":0,"size":0,"type":"Texture"}],"stride":0}, - {"components":[{"normalized":false,"offset":0,"size":1,"type":"Triangle"}],"stride":1} - ], - "index":1, - "name":"Scan-1" - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `ScanData` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData): - # A unique identifier generated by the client. - self.Index = Index - # "ScanData" - self.Type = Type - # Requested scan data. - self.Input = Input - - class Response: - # Server response for the `ScanData` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_ScanData_ScanData, Output: MF_V3_Descriptors_ScanData_ScanData, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "ScanData" - self.Type = Type - # The scan data requested by the client. - self.Input = Input - # The scan data sent from the server. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - class Buffer: - # Server buffer message for the `ScanData` task. - def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task, Descriptor: MF_V3_Descriptors_ScanData_ScanData.Buffer): - # The zero-based index identifying the data buffer. - self.Index = Index - # The size of the incoming data buffer in bytes. - self.Size = Size - # The requested ScanData task. - self.Task = Task - # The scan data buffer descriptor. - self.Descriptor = Descriptor - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/SetCameras.py b/maf_three/MF/V3/Tasks/SetCameras.py deleted file mode 100644 index 188e93c..0000000 --- a/maf_three/MF/V3/Tasks/SetCameras.py +++ /dev/null @@ -1,76 +0,0 @@ -from MF.V3.Descriptors.Settings.Camera import Camera as MF_V3_Descriptors_Settings_Camera_Camera -from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class SetCameras: - """* - Apply camera settings to one or both cameras. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"SetCameras", - "Input":{ - "analogGain":256, - "digitalGain":128, - "exposure":18000 - }, - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"SetCameras" - "Input":{ - "analogGain":256, - "digitalGain":512, - "exposure":18000 - }, - "Output":{ - "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, - "digitalGain":{"default":256,"max":65536,"min":256,"value":512}, - "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `SetCameras` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Camera_Camera = None): - # A unique identifier generated by the client. - self.Index = Index - # "SetCameras" - self.Type = Type - # Camera settings. - self.Input = Input - - class Response: - # Server response for the `SetCameras` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Camera_Camera = None, Output: MF_V3_Descriptors_Settings_Camera_Camera = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "SetCameras" - self.Type = Type - # Requested camera settings. - self.Input = Input - # Actual camera settings after applying the requested settings. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/SetGroup.py b/maf_three/MF/V3/Tasks/SetGroup.py deleted file mode 100644 index ab4933c..0000000 --- a/maf_three/MF/V3/Tasks/SetGroup.py +++ /dev/null @@ -1,104 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Settings.Group import Group as MF_V3_Settings_Group_Group -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class SetGroup: - """* - Set scan group properties. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"SetGroup", - "Input":{ - "index":2, - "name":"Amazing Scan" - "color":[1,0,0,1], - "rotation":[0,3.14,0], - "translation":[0,10,25] - } - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"SetGroup", - "Input":{ - "index":2, - "name":"Amazing Scan" - "color":[1,0,0,1], - "rotation":[0,3.14,0], - "translation":[0,10,25] - } - "Output":{ - "groups":[ - { - "index":1, - "scan":1, - "name":"Scan-1", - "color":[0.75,0.5,0.2,1.0], - "rotation":[0.03,0.1,-0.01], - "translation":[-101,67,-561], - "visible":true - }, - { - "index":2, - "scan":2, - "name":"Amazing Scan", - "color":[1,0,0,1], - "rotation":[0,3.14,0], - "translation":[0,10,25], - "visible":true - }, - { - "index":3, - "scan":3, - "name":"Scan-3", - "color":[0.6,0.8,0.9,1.0], - "visible":true - } - ] - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `SetGroup` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group): - # A unique identifier generated by the client. - self.Index = Index - # "SetGroup" - self.Type = Type - # The requested group settings. - self.Input = Input - - class Response: - # Server response for the `SetGroup` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "SetGroup" - self.Type = Type - # The requested group settings. - self.Input = Input - # The root scan group in the current open project. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/SetProject.py b/maf_three/MF/V3/Tasks/SetProject.py deleted file mode 100644 index c2d785f..0000000 --- a/maf_three/MF/V3/Tasks/SetProject.py +++ /dev/null @@ -1,80 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class SetProject: - """* - Apply settings to the current open project. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"SetProject", - "Input":{ - "name":"My Project" - }, - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"SetProject", - "Input":{ - "name":"My Project" - }, - "Output":{ - "index":5, - "name":"My Project", - "groups":[{ - "color":[0.8,0.5,0.6,1.0], - "index":1, - "name":"Scan-1", - "scan":1, - "rotation":[0.2,0.8,-0.1], - "translation":[-275,-32,-134], - "visible":true - }], - } - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `SetProject` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Project_Project = None): - # A unique identifier generated by the client. - self.Index = Index - # "SetProject" - self.Type = Type - # Project settings. - self.Input = Input - - class Response: - # Server response for the `SetProject` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Project_Project = None, Output: MF_V3_Descriptors_Project_Project = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "SetProject" - self.Type = Type - # Requested project settings. - self.Input = Input - # Actual project settings after applying the requested settings. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/SetProjector.py b/maf_three/MF/V3/Tasks/SetProjector.py deleted file mode 100644 index 2fe887c..0000000 --- a/maf_three/MF/V3/Tasks/SetProjector.py +++ /dev/null @@ -1,75 +0,0 @@ -from MF.V3.Descriptors.Settings.Projector import Projector as MF_V3_Descriptors_Settings_Projector_Projector -from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class SetProjector: - """* - Apply projector settings. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"SetProjector" - "Input":{ - "on":true, - "brightness":0.75, - "color":[1.0, 1.0, 1.0] - }, - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"SetProjector" - "Input":{ - "on":true, - "brightness":0.75, - "color":[1.0, 1.0, 1.0] - }, - "Output":{ - "on":{"default":false,"value":true}, - "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.75} - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `SetProjector` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Projector_Projector = None): - # A unique identifier generated by the client. - self.Index = Index - # "SetProjector" - self.Type = Type - # Projector settings. - self.Input = Input - - class Response: - # Server response for the `SetProjector` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Projector_Projector = None, Output: MF_V3_Descriptors_Settings_Projector_Projector = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "SetProjector" - self.Type = Type - # Requested projector settings. - self.Input = Input - # Actual projector settings after applying the requested settings. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/Shutdown.py b/maf_three/MF/V3/Tasks/Shutdown.py deleted file mode 100644 index c6928ef..0000000 --- a/maf_three/MF/V3/Tasks/Shutdown.py +++ /dev/null @@ -1,53 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class Shutdown: - """* - Shutdown the scanner. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"Shutdown" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"Shutdown" - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `Shutdown` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "Shutdown" - self.Type = Type - - class Response: - # Server response for the `Shutdown` task. - def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "Shutdown" - self.Type = Type - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/SplitGroup.py b/maf_three/MF/V3/Tasks/SplitGroup.py deleted file mode 100644 index 7efbce8..0000000 --- a/maf_three/MF/V3/Tasks/SplitGroup.py +++ /dev/null @@ -1,74 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class SplitGroup: - """* - Split a scan group (ie. move its subgroups to its parent group). - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"SplitGroup", - "Input":0 - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"SplitGroup", - "Input":0, - "Output":{ - "groups":[ - { - "index":1, - "name":"Group 1", - }, - { - "index":2, - "name":"Group 2" - } - ] - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `SplitGroup` task. - def __init__(self, Index: int, Type: str, Input: int): - # A unique identifier generated by the client. - self.Index = Index - # "SplitGroup" - self.Type = Type - # The index of the group to split. - self.Input = Input - - class Response: - # Server response for the `SplitGroup` task. - def __init__(self, Index: int, Type: str, Input: int, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "SplitGroup" - self.Type = Type - # The requested index of the group to split. - self.Input = Input - # The root scan group in the current open project. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/StartVideo.py b/maf_three/MF/V3/Tasks/StartVideo.py deleted file mode 100644 index da7f6b2..0000000 --- a/maf_three/MF/V3/Tasks/StartVideo.py +++ /dev/null @@ -1,64 +0,0 @@ -from MF.V3.Settings.Video import Video as MF_V3_Settings_Video_Video -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class StartVideo: - """* - Start the video stream. - - The video frames are sent as task buffers associated with the reserved video task index -1. The left and right camera frames are sent in buffer 0 and 1, respectively. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"StartVideo" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"StartVideo", - "Output":{ - "codec":"JPEG", - "format":"YUV420", - "width":510, - "height":380 - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `StartVideo` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "StartVideo" - self.Type = Type - - class Response: - # Server response for the `StartVideo` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Settings_Video_Video = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "StartVideo" - self.Type = Type - # The video settings. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/StopVideo.py b/maf_three/MF/V3/Tasks/StopVideo.py deleted file mode 100644 index 68662b0..0000000 --- a/maf_three/MF/V3/Tasks/StopVideo.py +++ /dev/null @@ -1,53 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class StopVideo: - """* - Stop the video stream. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"StopVideo" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"StopVideo", - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `StopVideo` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "StopVideo" - self.Type = Type - - class Response: - # Server response for the `StopVideo` task. - def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "StopVideo" - self.Type = Type - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/SystemInfo.py b/maf_three/MF/V3/Tasks/SystemInfo.py deleted file mode 100644 index 59d8d4e..0000000 --- a/maf_three/MF/V3/Tasks/SystemInfo.py +++ /dev/null @@ -1,92 +0,0 @@ -from MF.V3.Descriptors.System import System as MF_V3_Descriptors_System_System -from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class SystemInfo: - """* - Get system information including the serial number, disk space and installed and available software versions. - - Request example: - ``` - { - "Task":{ - "Index":1, - "Type":"SystemInfo", - "Input":{ - "installed":["server","frontend"], - "available":["server","frontend"] - } - } - } - ``` - Response example: - ``` - { - "Task":{ - "Index":1, - "Type":"SystemInfo" - "Input":{ - "installed":["server","frontend"], - "available":["server","frontend"] - } - "Output":{ - "serialNumber":"1000000012345678", - "diskSpace":{"available":8523210752,"capacity":15082610688}, - "software:{ - "installed":[ - { - "name":"server", - "version":{ - "major":2, - "minor":21, - "patch":119, - "string":"2.21.119" - } - }, - { - "name":"frontend", - "version":{ - "major":2, - "minor":14, - "patch":39, - "string":"2.14.39" - } - } - }, - ] - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `SystemInfo` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Software_Software = None): - # A unique identifier generated by the client. - self.Index = Index - # "SystemInfo" - self.Type = Type - # Software settings. - self.Input = Input - - class Response: - # Server response for the `SystemInfo` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_System_System, Input: MF_V3_Settings_Software_Software = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "SystemInfo" - self.Type = Type - # The system descriptor. - self.Output = Output - # The requested software settings. - self.Input = Input - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/TransformGroup.py b/maf_three/MF/V3/Tasks/TransformGroup.py deleted file mode 100644 index f706e6b..0000000 --- a/maf_three/MF/V3/Tasks/TransformGroup.py +++ /dev/null @@ -1,81 +0,0 @@ -from MF.V3.Descriptors.Project import Project as MF_V3_Descriptors_Project_Project -from MF.V3.Settings.Group import Group as MF_V3_Settings_Group_Group -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class TransformGroup: - """* - Apply a rigid transformation to a group. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"TransformGroup", - "Input":{ - "index":1, - "rotation":[0.5, 1.0, 1.5], - "translation":[10, 20, 30] - } - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"TransformGroup", - "Input":{ - "index":1, - "rotation":[0.5, 1.0, 1.5], - "translation":[10, 20, 30] - }, - "Output":{ - "groups":[ - { - "index":1, - "name":"Group 1", - "rotation":[0.5, 1.0, 1.5], - "translation":[10, 20, 30] - } - ] - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `TransformGroup` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group): - # A unique identifier generated by the client. - self.Index = Index - # "TransformGroup" - self.Type = Type - # The group settings containing the requested rotation and translation. - self.Input = Input - - class Response: - # Server response for the `TransformGroup` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Group_Group, Output: MF_V3_Descriptors_Project_Project.Group, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "TransformGroup" - self.Type = Type - # The group settings containing the requested rotation and translation. - self.Input = Input - # The root scan group in the current open project. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/TurntableCalibration.py b/maf_three/MF/V3/Tasks/TurntableCalibration.py deleted file mode 100644 index 67308a8..0000000 --- a/maf_three/MF/V3/Tasks/TurntableCalibration.py +++ /dev/null @@ -1,61 +0,0 @@ -from MF.V3.Descriptors.Calibration import Turntable as MF_V3_Descriptors_Calibration_Turntable -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class TurntableCalibration: - """* - Get the turntable calibration descriptor. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"TurntableCalibration" - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"TurntableCalibration", - "Output":{ - "date":[2024,4,27,16,57,35], - "quality":"Excellent", - "focus":[300,320] - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `TurntableCalibration` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "TurntableCalibration" - self.Type = Type - - class Response: - # Server response for the `TurntableCalibration` task. - def __init__(self, Index: int, Type: str, Output: MF_V3_Descriptors_Calibration_Turntable = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "TurntableCalibration" - self.Type = Type - # The turntable calibration descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/UpdateSettings.py b/maf_three/MF/V3/Tasks/UpdateSettings.py deleted file mode 100644 index 26818f7..0000000 --- a/maf_three/MF/V3/Tasks/UpdateSettings.py +++ /dev/null @@ -1,105 +0,0 @@ -from MF.V3.Descriptors.Settings.Scanner import Scanner as MF_V3_Descriptors_Settings_Scanner_Scanner -from MF.V3.Settings.Scanner import Scanner as MF_V3_Settings_Scanner_Scanner -from MF.V3.Task import TaskState as MF_V3_Task_TaskState - - -class UpdateSettings: - """* - Update scanner settings. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"UpdateSettings", - "Input":{ - "camera":{ - "analogGain":256, - "digitalGain":320, - "exposure":18000 - } - } - } - } - ``` - - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"UpdateSettings", - "Input":{ - "camera":{ - "analogGain":256, - "digitalGain":320, - "exposure":18000 - } - }, - "Output":{ - "camera":{ - "analogGain":{"default":512.0,"max":1024.0,"min":256.0,"value":256.0}, - "autoExposure":{"default":false,"value":false}, - "digitalGain":{"default":256,"max":65536,"min":256,"value":320}, - "exposure":{"default":27000,"max":90000,"min":9000,"value":18000}, - }, - "projector":{ - "brightness":{"default":0.5,"max":1.0,"min":0.0,"value":0.800000011920929}, - "on":{"default":false,"value":true} - }, - "turntable":{ - "scans":{"default":8,"max":24,"min":1,"value":3}, - "sweep":{"default":360,"max":360,"min":5,"value":90}, - "use":{"default":true,"value":true} - }, - "capture":{ - "quality":{"default":"Medium","value":"Medium"}, - "texture":{"default":true,"value":true} - }, - "i18n":{ - "language":{"default":"en","value":"en"} - }, - "style":{ - "theme":{"default":"Dark","value":"Dark"} - }, - "viewer":{ - "textureOpacity":{"default":0.5,"max":1.0,"min":0.0,"value":1.0} - } - }, - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `UpdateSettings` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scanner_Scanner): - # A unique identifier generated by the client. - self.Index = Index - # "UpdateSettings" - self.Type = Type - # Scanner settings. - self.Input = Input - - class Response: - # Server response for the `UpdateSettings` task. - def __init__(self, Index: int, Type: str, Input: MF_V3_Settings_Scanner_Scanner, Output: MF_V3_Descriptors_Settings_Scanner_Scanner = None, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "UpdateSettings" - self.Type = Type - # The requested scanner settings. - self.Input = Input - # The scanner settings descriptor. - self.Output = Output - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/UploadProject.py b/maf_three/MF/V3/Tasks/UploadProject.py deleted file mode 100644 index 8314523..0000000 --- a/maf_three/MF/V3/Tasks/UploadProject.py +++ /dev/null @@ -1,79 +0,0 @@ -from MF.V3.Task import TaskState as MF_V3_Task_TaskState, Task as MF_V3_Task_Task - - -class UploadProject: - """* - Upload a project to the scanner. The project must be archived in a ZIP file. - - > Request example: - - ```json - { - "Task":{ - "Index":1, - "Type":"UploadProject" - } - } - ``` - - > Buffer message from client. - - ```json - { - "Buffer":{ - "Index":0, - "Size":15682096, - "Task":{ - "Index":1, - "Type":"UploadProject" - } - } - } - ``` - - > Binary data transfer from client: The project zip file [15682096 bytes]. - > Response example: - - ```json - { - "Task":{ - "Index":1, - "Type":"UploadProject" - "State":"Completed" - } - } - ``` - """ - class Request: - # Client request for the `UploadProject` task. - def __init__(self, Index: int, Type: str): - # A unique identifier generated by the client. - self.Index = Index - # "UploadProject" - self.Type = Type - - class Response: - # Server response for the `UploadProject` task. - def __init__(self, Index: int, Type: str, State: MF_V3_Task_TaskState = None, Error: str = None): - # The unique identifier generated by the client. - self.Index = Index - # "UploadProject" - self.Type = Type - # The current state of the task. - self.State = State - # A string describing the error if the task has failed. - self.Error = Error - - class Buffer: - # Client buffer message for the `UploadProject` task. - def __init__(self, Index: int, Size: int, Task: MF_V3_Task_Task): - # The zero-based index identifying the data buffer. - self.Index = Index - # The size of the incoming data buffer in bytes. - self.Size = Size - # The requested UploadProject task. - self.Task = Task - - def __init__(self): - pass - diff --git a/maf_three/MF/V3/Tasks/__init__.py b/maf_three/MF/V3/Tasks/__init__.py deleted file mode 100644 index d91979d..0000000 --- a/maf_three/MF/V3/Tasks/__init__.py +++ /dev/null @@ -1,56 +0,0 @@ -from MF.V3.Tasks.AddMergeToProject import * -from MF.V3.Tasks.Align import * -from MF.V3.Tasks.AutoFocus import * -from MF.V3.Tasks.BoundingBox import * -from MF.V3.Tasks.CalibrateCameras import * -from MF.V3.Tasks.CalibrateTurntable import * -from MF.V3.Tasks.CalibrationCaptureTargets import * -from MF.V3.Tasks.CameraCalibration import * -from MF.V3.Tasks.CloseProject import * -from MF.V3.Tasks.ConnectWifi import * -from MF.V3.Tasks.DepthMap import * -from MF.V3.Tasks.DetectCalibrationCard import * -from MF.V3.Tasks.DownloadProject import * -from MF.V3.Tasks.Export import * -from MF.V3.Tasks.ExportLogs import * -from MF.V3.Tasks.ExportMerge import * -from MF.V3.Tasks.FlattenGroup import * -from MF.V3.Tasks.ForgetWifi import * -from MF.V3.Tasks.HasCameras import * -from MF.V3.Tasks.HasProjector import * -from MF.V3.Tasks.HasTurntable import * -from MF.V3.Tasks.ListExportFormats import * -from MF.V3.Tasks.ListGroups import * -from MF.V3.Tasks.ListNetworkInterfaces import * -from MF.V3.Tasks.ListProjects import * -from MF.V3.Tasks.ListScans import * -from MF.V3.Tasks.ListSettings import * -from MF.V3.Tasks.ListWifi import * -from MF.V3.Tasks.Merge import * -from MF.V3.Tasks.MergeData import * -from MF.V3.Tasks.MoveGroup import * -from MF.V3.Tasks.NewGroup import * -from MF.V3.Tasks.NewProject import * -from MF.V3.Tasks.NewScan import * -from MF.V3.Tasks.OpenProject import * -from MF.V3.Tasks.PopSettings import * -from MF.V3.Tasks.PushSettings import * -from MF.V3.Tasks.Reboot import * -from MF.V3.Tasks.RemoveGroups import * -from MF.V3.Tasks.RemoveProjects import * -from MF.V3.Tasks.RestoreFactoryCalibration import * -from MF.V3.Tasks.RotateTurntable import * -from MF.V3.Tasks.ScanData import * -from MF.V3.Tasks.SetCameras import * -from MF.V3.Tasks.SetGroup import * -from MF.V3.Tasks.SetProject import * -from MF.V3.Tasks.SetProjector import * -from MF.V3.Tasks.Shutdown import * -from MF.V3.Tasks.SplitGroup import * -from MF.V3.Tasks.StartVideo import * -from MF.V3.Tasks.StopVideo import * -from MF.V3.Tasks.SystemInfo import * -from MF.V3.Tasks.TransformGroup import * -from MF.V3.Tasks.TurntableCalibration import * -from MF.V3.Tasks.UpdateSettings import * -from MF.V3.Tasks.UploadProject import * diff --git a/maf_three/MF/V3/Three.py b/maf_three/MF/V3/Three.py deleted file mode 100644 index 150a228..0000000 --- a/maf_three/MF/V3/Three.py +++ /dev/null @@ -1,1160 +0,0 @@ -from MF.V3 import Task -from MF.V3.Settings.Advanced import Advanced as MF_V3_Settings_Advanced_Advanced -from MF.V3.Settings.Align import Align as MF_V3_Settings_Align_Align -from MF.V3.Settings.AutoFocus import AutoFocus as MF_V3_Settings_AutoFocus_AutoFocus -from MF.V3.Settings.BoundingBox import BoundingBox as MF_V3_Settings_BoundingBox_BoundingBox -from MF.V3.Settings.Camera import Camera as MF_V3_Settings_Camera_Camera -from MF.V3.Settings.Capture import Capture as MF_V3_Settings_Capture_Capture -from MF.V3.Settings.Export import Export as MF_V3_Settings_Export_Export -from MF.V3.Settings.Group import Group as MF_V3_Settings_Group_Group -from MF.V3.Settings.I18n import I18n as MF_V3_Settings_I18n_I18n -from MF.V3.Settings.Merge import Merge as MF_V3_Settings_Merge_Merge -from MF.V3.Settings.NewGroup import NewGroup as MF_V3_Settings_NewGroup_NewGroup -from MF.V3.Settings.Project import Project as MF_V3_Settings_Project_Project -from MF.V3.Settings.Projector import Projector as MF_V3_Settings_Projector_Projector -from MF.V3.Settings.Scan import Scan as MF_V3_Settings_Scan_Scan -from MF.V3.Settings.ScanData import ScanData as MF_V3_Settings_ScanData_ScanData -from MF.V3.Settings.ScanSelection import ScanSelection as MF_V3_Settings_ScanSelection_ScanSelection -from MF.V3.Settings.Scanner import Scanner as MF_V3_Settings_Scanner_Scanner -from MF.V3.Settings.Software import Software as MF_V3_Settings_Software_Software -from MF.V3.Settings.Style import Style as MF_V3_Settings_Style_Style -from MF.V3.Settings.Turntable import Turntable as MF_V3_Settings_Turntable_Turntable -from MF.V3.Settings.Tutorials import Tutorials as MF_V3_Settings_Tutorials_Tutorials -from MF.V3.Settings.Viewer import Viewer as MF_V3_Settings_Viewer_Viewer -from MF.V3.Settings.Wifi import Wifi as MF_V3_Settings_Wifi_Wifi -from MF.V3.Tasks.AddMergeToProject import AddMergeToProject as MF_V3_Tasks_AddMergeToProject -from MF.V3.Tasks.Align import Align as MF_V3_Tasks_Align -from MF.V3.Tasks.AutoFocus import AutoFocus as MF_V3_Tasks_AutoFocus -from MF.V3.Tasks.BoundingBox import BoundingBox as MF_V3_Tasks_BoundingBox -from MF.V3.Tasks.CalibrateCameras import CalibrateCameras as MF_V3_Tasks_CalibrateCameras -from MF.V3.Tasks.CalibrateTurntable import CalibrateTurntable as MF_V3_Tasks_CalibrateTurntable -from MF.V3.Tasks.CalibrationCaptureTargets import CalibrationCaptureTargets as MF_V3_Tasks_CalibrationCaptureTargets -from MF.V3.Tasks.CameraCalibration import CameraCalibration as MF_V3_Tasks_CameraCalibration -from MF.V3.Tasks.CloseProject import CloseProject as MF_V3_Tasks_CloseProject -from MF.V3.Tasks.ConnectWifi import ConnectWifi as MF_V3_Tasks_ConnectWifi -from MF.V3.Tasks.DepthMap import DepthMap as MF_V3_Tasks_DepthMap -from MF.V3.Tasks.DetectCalibrationCard import DetectCalibrationCard as MF_V3_Tasks_DetectCalibrationCard -from MF.V3.Tasks.DownloadProject import DownloadProject as MF_V3_Tasks_DownloadProject -from MF.V3.Tasks.Export import Export as MF_V3_Tasks_Export -from MF.V3.Tasks.ExportLogs import ExportLogs as MF_V3_Tasks_ExportLogs -from MF.V3.Tasks.ExportMerge import ExportMerge as MF_V3_Tasks_ExportMerge -from MF.V3.Tasks.FlattenGroup import FlattenGroup as MF_V3_Tasks_FlattenGroup -from MF.V3.Tasks.ForgetWifi import ForgetWifi as MF_V3_Tasks_ForgetWifi -from MF.V3.Tasks.HasCameras import HasCameras as MF_V3_Tasks_HasCameras -from MF.V3.Tasks.HasProjector import HasProjector as MF_V3_Tasks_HasProjector -from MF.V3.Tasks.HasTurntable import HasTurntable as MF_V3_Tasks_HasTurntable -from MF.V3.Tasks.ListExportFormats import ListExportFormats as MF_V3_Tasks_ListExportFormats -from MF.V3.Tasks.ListGroups import ListGroups as MF_V3_Tasks_ListGroups -from MF.V3.Tasks.ListNetworkInterfaces import ListNetworkInterfaces as MF_V3_Tasks_ListNetworkInterfaces -from MF.V3.Tasks.ListProjects import ListProjects as MF_V3_Tasks_ListProjects -from MF.V3.Tasks.ListScans import ListScans as MF_V3_Tasks_ListScans -from MF.V3.Tasks.ListSettings import ListSettings as MF_V3_Tasks_ListSettings -from MF.V3.Tasks.ListWifi import ListWifi as MF_V3_Tasks_ListWifi -from MF.V3.Tasks.Merge import Merge as MF_V3_Tasks_Merge -from MF.V3.Tasks.MergeData import MergeData as MF_V3_Tasks_MergeData -from MF.V3.Tasks.MoveGroup import MoveGroup as MF_V3_Tasks_MoveGroup -from MF.V3.Tasks.NewGroup import NewGroup as MF_V3_Tasks_NewGroup -from MF.V3.Tasks.NewProject import NewProject as MF_V3_Tasks_NewProject -from MF.V3.Tasks.NewScan import NewScan as MF_V3_Tasks_NewScan -from MF.V3.Tasks.OpenProject import OpenProject as MF_V3_Tasks_OpenProject -from MF.V3.Tasks.PopSettings import PopSettings as MF_V3_Tasks_PopSettings -from MF.V3.Tasks.PushSettings import PushSettings as MF_V3_Tasks_PushSettings -from MF.V3.Tasks.Reboot import Reboot as MF_V3_Tasks_Reboot -from MF.V3.Tasks.RemoveGroups import RemoveGroups as MF_V3_Tasks_RemoveGroups -from MF.V3.Tasks.RemoveProjects import RemoveProjects as MF_V3_Tasks_RemoveProjects -from MF.V3.Tasks.RestoreFactoryCalibration import RestoreFactoryCalibration as MF_V3_Tasks_RestoreFactoryCalibration -from MF.V3.Tasks.RotateTurntable import RotateTurntable as MF_V3_Tasks_RotateTurntable -from MF.V3.Tasks.ScanData import ScanData as MF_V3_Tasks_ScanData -from MF.V3.Tasks.SetCameras import SetCameras as MF_V3_Tasks_SetCameras -from MF.V3.Tasks.SetGroup import SetGroup as MF_V3_Tasks_SetGroup -from MF.V3.Tasks.SetProject import SetProject as MF_V3_Tasks_SetProject -from MF.V3.Tasks.SetProjector import SetProjector as MF_V3_Tasks_SetProjector -from MF.V3.Tasks.Shutdown import Shutdown as MF_V3_Tasks_Shutdown -from MF.V3.Tasks.SplitGroup import SplitGroup as MF_V3_Tasks_SplitGroup -from MF.V3.Tasks.StartVideo import StartVideo as MF_V3_Tasks_StartVideo -from MF.V3.Tasks.StopVideo import StopVideo as MF_V3_Tasks_StopVideo -from MF.V3.Tasks.SystemInfo import SystemInfo as MF_V3_Tasks_SystemInfo -from MF.V3.Tasks.TransformGroup import TransformGroup as MF_V3_Tasks_TransformGroup -from MF.V3.Tasks.TurntableCalibration import TurntableCalibration as MF_V3_Tasks_TurntableCalibration -from MF.V3.Tasks.UpdateSettings import UpdateSettings as MF_V3_Tasks_UpdateSettings -from MF.V3.Tasks.UploadProject import UploadProject as MF_V3_Tasks_UploadProject -from typing import List - - -def list_network_interfaces(self) -> Task: - # List available wifi networks. - list_network_interfaces_request = MF_V3_Tasks_ListNetworkInterfaces.Request( - Index=0, - Type="ListNetworkInterfaces" - ) - list_network_interfaces_response = MF_V3_Tasks_ListNetworkInterfaces.Response( - Index=0, - Type="ListNetworkInterfaces" - ) - task = Task(Index=0, Type="ListNetworkInterfaces", Input=list_network_interfaces_request, Output=list_network_interfaces_response) - self.SendTask(task) - return task - - -def list_wifi(self) -> Task: - # List available wifi networks. - list_wifi_request = MF_V3_Tasks_ListWifi.Request( - Index=0, - Type="ListWifi" - ) - list_wifi_response = MF_V3_Tasks_ListWifi.Response( - Index=0, - Type="ListWifi" - ) - task = Task(Index=0, Type="ListWifi", Input=list_wifi_request, Output=list_wifi_response) - self.SendTask(task) - return task - - -def connect_wifi(self, ssid: str, password: str) -> Task: - # Connect to a wifi network. - connect_wifi_request = MF_V3_Tasks_ConnectWifi.Request( - Index=0, - Type="ConnectWifi", - Input=MF_V3_Settings_Wifi_Wifi( - ssid=ssid, - password=password, - ) - ) - connect_wifi_response = MF_V3_Tasks_ConnectWifi.Response( - Index=0, - Type="ConnectWifi", - Input=MF_V3_Settings_Wifi_Wifi( - ssid=ssid, - password=password, - ) - ) - task = Task(Index=0, Type="ConnectWifi", Input=connect_wifi_request, Output=connect_wifi_response) - self.SendTask(task) - return task - - -def forget_wifi(self) -> Task: - # Forget all wifi connections. - forget_wifi_request = MF_V3_Tasks_ForgetWifi.Request( - Index=0, - Type="ForgetWifi" - ) - forget_wifi_response = MF_V3_Tasks_ForgetWifi.Response( - Index=0, - Type="ForgetWifi" - ) - task = Task(Index=0, Type="ForgetWifi", Input=forget_wifi_request, Output=forget_wifi_response) - self.SendTask(task) - return task - - -def list_settings(self) -> Task: - # Get scanner settings. - list_settings_request = MF_V3_Tasks_ListSettings.Request( - Index=0, - Type="ListSettings" - ) - list_settings_response = MF_V3_Tasks_ListSettings.Response( - Index=0, - Type="ListSettings" - ) - task = Task(Index=0, Type="ListSettings", Input=list_settings_request, Output=list_settings_response) - self.SendTask(task) - return task - - -def push_settings(self) -> Task: - # Push the current scanner settings to the settings stack. - push_settings_request = MF_V3_Tasks_PushSettings.Request( - Index=0, - Type="PushSettings" - ) - push_settings_response = MF_V3_Tasks_PushSettings.Response( - Index=0, - Type="PushSettings" - ) - task = Task(Index=0, Type="PushSettings", Input=push_settings_request, Output=push_settings_response) - self.SendTask(task) - return task - - -def pop_settings(self, Input: bool = None) -> Task: - # Pop and restore scanner settings from the settings stack. - pop_settings_request = MF_V3_Tasks_PopSettings.Request( - Index=0, - Type="PopSettings", - Input=Input - ) - pop_settings_response = MF_V3_Tasks_PopSettings.Response( - Index=0, - Type="PopSettings" - ) - task = Task(Index=0, Type="PopSettings", Input=pop_settings_request, Output=pop_settings_response) - self.SendTask(task) - return task - - -def update_settings(self, advanced: MF_V3_Settings_Advanced_Advanced = None, camera: MF_V3_Settings_Camera_Camera = None, capture: MF_V3_Settings_Capture_Capture = None, i18n: MF_V3_Settings_I18n_I18n = None, projector: MF_V3_Settings_Projector_Projector = None, style: MF_V3_Settings_Style_Style = None, turntable: MF_V3_Settings_Turntable_Turntable = None, tutorials: MF_V3_Settings_Tutorials_Tutorials = None, viewer: MF_V3_Settings_Viewer_Viewer = None, software: MF_V3_Settings_Software_Software = None) -> Task: - # Update scanner settings. - update_settings_request = MF_V3_Tasks_UpdateSettings.Request( - Index=0, - Type="UpdateSettings", - Input=MF_V3_Settings_Scanner_Scanner( - advanced=advanced, - camera=camera, - capture=capture, - i18n=i18n, - projector=projector, - style=style, - turntable=turntable, - tutorials=tutorials, - viewer=viewer, - software=software, - ) - ) - update_settings_response = MF_V3_Tasks_UpdateSettings.Response( - Index=0, - Type="UpdateSettings", - Input=MF_V3_Settings_Scanner_Scanner( - advanced=advanced, - camera=camera, - capture=capture, - i18n=i18n, - projector=projector, - style=style, - turntable=turntable, - tutorials=tutorials, - viewer=viewer, - software=software, - ) - ) - task = Task(Index=0, Type="UpdateSettings", Input=update_settings_request, Output=update_settings_response) - self.SendTask(task) - return task - - -def list_projects(self) -> Task: - # List all projects. - list_projects_request = MF_V3_Tasks_ListProjects.Request( - Index=0, - Type="ListProjects" - ) - list_projects_response = MF_V3_Tasks_ListProjects.Response( - Index=0, - Type="ListProjects" - ) - task = Task(Index=0, Type="ListProjects", Input=list_projects_request, Output=list_projects_response) - self.SendTask(task) - return task - - -def download_project(self, Input: int) -> Task: - # Download a project from the scanner. - download_project_request = MF_V3_Tasks_DownloadProject.Request( - Index=0, - Type="DownloadProject", - Input=Input - ) - download_project_response = MF_V3_Tasks_DownloadProject.Response( - Index=0, - Type="DownloadProject", - Input=Input - ) - task = Task(Index=0, Type="DownloadProject", Input=download_project_request, Output=download_project_response) - self.SendTask(task) - return task - - -def upload_project(self, buffer: bytes) -> Task: - # Upload a project to the scanner. - upload_project_request = MF_V3_Tasks_UploadProject.Request( - Index=0, - Type="UploadProject" - ) - upload_project_response = MF_V3_Tasks_UploadProject.Response( - Index=0, - Type="UploadProject" - ) - task = Task(Index=0, Type="UploadProject", Input=upload_project_request, Output=upload_project_response) - self.SendTask(task, buffer) - return task - - -def new_project(self, Input: str = None) -> Task: - # Create a new project. - new_project_request = MF_V3_Tasks_NewProject.Request( - Index=0, - Type="NewProject", - Input=Input - ) - new_project_response = MF_V3_Tasks_NewProject.Response( - Index=0, - Type="NewProject" - ) - task = Task(Index=0, Type="NewProject", Input=new_project_request, Output=new_project_response) - self.SendTask(task) - return task - - -def open_project(self, Input: int) -> Task: - # Open an existing project. - open_project_request = MF_V3_Tasks_OpenProject.Request( - Index=0, - Type="OpenProject", - Input=Input - ) - open_project_response = MF_V3_Tasks_OpenProject.Response( - Index=0, - Type="OpenProject", - Input=Input - ) - task = Task(Index=0, Type="OpenProject", Input=open_project_request, Output=open_project_response) - self.SendTask(task) - return task - - -def close_project(self) -> Task: - # Close the current open project. - close_project_request = MF_V3_Tasks_CloseProject.Request( - Index=0, - Type="CloseProject" - ) - close_project_response = MF_V3_Tasks_CloseProject.Response( - Index=0, - Type="CloseProject" - ) - task = Task(Index=0, Type="CloseProject", Input=close_project_request, Output=close_project_response) - self.SendTask(task) - return task - - -def remove_projects(self, Input: List[int] = None) -> Task: - # Remove selected projects. - remove_projects_request = MF_V3_Tasks_RemoveProjects.Request( - Index=0, - Type="RemoveProjects", - Input=Input - ) - remove_projects_response = MF_V3_Tasks_RemoveProjects.Response( - Index=0, - Type="RemoveProjects" - ) - task = Task(Index=0, Type="RemoveProjects", Input=remove_projects_request, Output=remove_projects_response) - self.SendTask(task) - return task - - -def list_groups(self) -> Task: - # List the scan groups in the current open project. - list_groups_request = MF_V3_Tasks_ListGroups.Request( - Index=0, - Type="ListGroups" - ) - list_groups_response = MF_V3_Tasks_ListGroups.Response( - Index=0, - Type="ListGroups", - Output=None - ) - task = Task(Index=0, Type="ListGroups", Input=list_groups_request, Output=list_groups_response) - self.SendTask(task) - return task - - -def list_scans(self) -> Task: - # List the scans in the current open project. - list_scans_request = MF_V3_Tasks_ListScans.Request( - Index=0, - Type="ListScans" - ) - list_scans_response = MF_V3_Tasks_ListScans.Response( - Index=0, - Type="ListScans" - ) - task = Task(Index=0, Type="ListScans", Input=list_scans_request, Output=list_scans_response) - self.SendTask(task) - return task - - -def scan_data(self, index: int, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None, buffers: List[MF_V3_Settings_ScanData_ScanData.Buffer] = None, metadata: List[MF_V3_Settings_ScanData_ScanData.Metadata] = None) -> Task: - # Download the raw scan data for a scan in the current open project. - scan_data_request = MF_V3_Tasks_ScanData.Request( - Index=0, - Type="ScanData", - Input=MF_V3_Settings_ScanData_ScanData( - index=index, - mergeStep=mergeStep, - buffers=buffers, - metadata=metadata, - ) - ) - scan_data_response = MF_V3_Tasks_ScanData.Response( - Index=0, - Type="ScanData", - Input=MF_V3_Settings_ScanData_ScanData( - index=index, - mergeStep=mergeStep, - buffers=buffers, - metadata=metadata, - ), - Output=None - ) - task = Task(Index=0, Type="ScanData", Input=scan_data_request, Output=scan_data_response) - self.SendTask(task) - return task - - -def set_project(self, index: int = None, name: str = None) -> Task: - # Apply settings to the current open project. - set_project_request = MF_V3_Tasks_SetProject.Request( - Index=0, - Type="SetProject", - Input=MF_V3_Settings_Project_Project( - index=index, - name=name, - ) - ) - set_project_response = MF_V3_Tasks_SetProject.Response( - Index=0, - Type="SetProject" - ) - task = Task(Index=0, Type="SetProject", Input=set_project_request, Output=set_project_response) - self.SendTask(task) - return task - - -def set_group(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> Task: - # Set scan group properties. - set_group_request = MF_V3_Tasks_SetGroup.Request( - Index=0, - Type="SetGroup", - Input=MF_V3_Settings_Group_Group( - index=index, - name=name, - color=color, - visible=visible, - collapsed=collapsed, - rotation=rotation, - translation=translation, - ) - ) - set_group_response = MF_V3_Tasks_SetGroup.Response( - Index=0, - Type="SetGroup", - Input=MF_V3_Settings_Group_Group( - index=index, - name=name, - color=color, - visible=visible, - collapsed=collapsed, - rotation=rotation, - translation=translation, - ), - Output=None - ) - task = Task(Index=0, Type="SetGroup", Input=set_group_request, Output=set_group_response) - self.SendTask(task) - return task - - -def new_group(self, parentIndex: int = None, baseName: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> Task: - # Create a new scan group. - new_group_request = MF_V3_Tasks_NewGroup.Request( - Index=0, - Type="NewGroup", - Input=MF_V3_Settings_NewGroup_NewGroup( - parentIndex=parentIndex, - baseName=baseName, - color=color, - visible=visible, - collapsed=collapsed, - rotation=rotation, - translation=translation, - ) - ) - new_group_response = MF_V3_Tasks_NewGroup.Response( - Index=0, - Type="NewGroup", - Output=None - ) - task = Task(Index=0, Type="NewGroup", Input=new_group_request, Output=new_group_response) - self.SendTask(task) - return task - - -def move_group(self, Input: List[int] = None) -> Task: - # Move a scan group. - move_group_request = MF_V3_Tasks_MoveGroup.Request( - Index=0, - Type="MoveGroup", - Input=Input - ) - move_group_response = MF_V3_Tasks_MoveGroup.Response( - Index=0, - Type="MoveGroup", - Output=None - ) - task = Task(Index=0, Type="MoveGroup", Input=move_group_request, Output=move_group_response) - self.SendTask(task) - return task - - -def flatten_group(self, Input: int) -> Task: - # Flatten a scan group such that it only consists of single scans. - flatten_group_request = MF_V3_Tasks_FlattenGroup.Request( - Index=0, - Type="FlattenGroup", - Input=Input - ) - flatten_group_response = MF_V3_Tasks_FlattenGroup.Response( - Index=0, - Type="FlattenGroup", - Input=Input, - Output=None - ) - task = Task(Index=0, Type="FlattenGroup", Input=flatten_group_request, Output=flatten_group_response) - self.SendTask(task) - return task - - -def split_group(self, Input: int) -> Task: - # Split a scan group (ie. move its subgroups to its parent group). - split_group_request = MF_V3_Tasks_SplitGroup.Request( - Index=0, - Type="SplitGroup", - Input=Input - ) - split_group_response = MF_V3_Tasks_SplitGroup.Response( - Index=0, - Type="SplitGroup", - Input=Input, - Output=None - ) - task = Task(Index=0, Type="SplitGroup", Input=split_group_request, Output=split_group_response) - self.SendTask(task) - return task - - -def transform_group(self, index: int, name: str = None, color: List[float] = None, visible: bool = None, collapsed: bool = None, rotation: List[float] = None, translation: List[float] = None) -> Task: - # Apply a rigid transformation to a group. - transform_group_request = MF_V3_Tasks_TransformGroup.Request( - Index=0, - Type="TransformGroup", - Input=MF_V3_Settings_Group_Group( - index=index, - name=name, - color=color, - visible=visible, - collapsed=collapsed, - rotation=rotation, - translation=translation, - ) - ) - transform_group_response = MF_V3_Tasks_TransformGroup.Response( - Index=0, - Type="TransformGroup", - Input=MF_V3_Settings_Group_Group( - index=index, - name=name, - color=color, - visible=visible, - collapsed=collapsed, - rotation=rotation, - translation=translation, - ), - Output=None - ) - task = Task(Index=0, Type="TransformGroup", Input=transform_group_request, Output=transform_group_response) - self.SendTask(task) - return task - - -def remove_groups(self, Input: List[int] = None) -> Task: - # Remove selected scan groups. - remove_groups_request = MF_V3_Tasks_RemoveGroups.Request( - Index=0, - Type="RemoveGroups", - Input=Input - ) - remove_groups_response = MF_V3_Tasks_RemoveGroups.Response( - Index=0, - Type="RemoveGroups", - Output=None - ) - task = Task(Index=0, Type="RemoveGroups", Input=remove_groups_request, Output=remove_groups_response) - self.SendTask(task) - return task - - -def bounding_box(self, selection: MF_V3_Settings_ScanSelection_ScanSelection, axisAligned: bool) -> Task: - # Get the bounding box of a set of scan groups. - bounding_box_request = MF_V3_Tasks_BoundingBox.Request( - Index=0, - Type="BoundingBox", - Input=MF_V3_Settings_BoundingBox_BoundingBox( - selection=selection, - axisAligned=axisAligned, - ) - ) - bounding_box_response = MF_V3_Tasks_BoundingBox.Response( - Index=0, - Type="BoundingBox", - Input=MF_V3_Settings_BoundingBox_BoundingBox( - selection=selection, - axisAligned=axisAligned, - ), - Output=None - ) - task = Task(Index=0, Type="BoundingBox", Input=bounding_box_request, Output=bounding_box_response) - self.SendTask(task) - return task - - -def align(self, source: int, target: int, rough: MF_V3_Settings_Align_Align.Rough = None, fine: MF_V3_Settings_Align_Align.Fine = None) -> Task: - # Align two scan groups. - align_request = MF_V3_Tasks_Align.Request( - Index=0, - Type="Align", - Input=MF_V3_Settings_Align_Align( - source=source, - target=target, - rough=rough, - fine=fine, - ) - ) - align_response = MF_V3_Tasks_Align.Response( - Index=0, - Type="Align", - Input=MF_V3_Settings_Align_Align( - source=source, - target=target, - rough=rough, - fine=fine, - ), - Output=None - ) - task = Task(Index=0, Type="Align", Input=align_request, Output=align_response) - self.SendTask(task) - return task - - -def merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, remesh: MF_V3_Settings_Merge_Merge.Remesh = None, simplify: MF_V3_Settings_Merge_Merge.Simplify = None, texturize: bool = None) -> Task: - # Merge two or more scan groups. - merge_request = MF_V3_Tasks_Merge.Request( - Index=0, - Type="Merge", - Input=MF_V3_Settings_Merge_Merge( - selection=selection, - remesh=remesh, - simplify=simplify, - texturize=texturize, - ) - ) - merge_response = MF_V3_Tasks_Merge.Response( - Index=0, - Type="Merge", - Input=MF_V3_Settings_Merge_Merge( - selection=selection, - remesh=remesh, - simplify=simplify, - texturize=texturize, - ), - Output=None - ) - task = Task(Index=0, Type="Merge", Input=merge_request, Output=merge_response) - self.SendTask(task) - return task - - -def merge_data(self, index: int, mergeStep: MF_V3_Settings_ScanData_ScanData.MergeStep = None, buffers: List[MF_V3_Settings_ScanData_ScanData.Buffer] = None, metadata: List[MF_V3_Settings_ScanData_ScanData.Metadata] = None) -> Task: - # Download the raw scan data for the current merge process. - merge_data_request = MF_V3_Tasks_MergeData.Request( - Index=0, - Type="MergeData", - Input=MF_V3_Settings_ScanData_ScanData( - index=index, - mergeStep=mergeStep, - buffers=buffers, - metadata=metadata, - ) - ) - merge_data_response = MF_V3_Tasks_MergeData.Response( - Index=0, - Type="MergeData", - Input=MF_V3_Settings_ScanData_ScanData( - index=index, - mergeStep=mergeStep, - buffers=buffers, - metadata=metadata, - ), - Output=None - ) - task = Task(Index=0, Type="MergeData", Input=merge_data_request, Output=merge_data_response) - self.SendTask(task) - return task - - -def add_merge_to_project(self) -> Task: - # Add a merged scan to the current project. - add_merge_to_project_request = MF_V3_Tasks_AddMergeToProject.Request( - Index=0, - Type="AddMergeToProject" - ) - add_merge_to_project_response = MF_V3_Tasks_AddMergeToProject.Response( - Index=0, - Type="AddMergeToProject", - Output=None - ) - task = Task(Index=0, Type="AddMergeToProject", Input=add_merge_to_project_request, Output=add_merge_to_project_response) - self.SendTask(task) - return task - - -def list_export_formats(self) -> Task: - # List all export formats. - list_export_formats_request = MF_V3_Tasks_ListExportFormats.Request( - Index=0, - Type="ListExportFormats" - ) - list_export_formats_response = MF_V3_Tasks_ListExportFormats.Response( - Index=0, - Type="ListExportFormats" - ) - task = Task(Index=0, Type="ListExportFormats", Input=list_export_formats_request, Output=list_export_formats_response) - self.SendTask(task) - return task - - -def export(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None, scale: float = None) -> Task: - # Export a group of scans. - export_request = MF_V3_Tasks_Export.Request( - Index=0, - Type="Export", - Input=MF_V3_Settings_Export_Export( - selection=selection, - texture=texture, - merge=merge, - format=format, - scale=scale, - ) - ) - export_response = MF_V3_Tasks_Export.Response( - Index=0, - Type="Export", - Input=MF_V3_Settings_Export_Export( - selection=selection, - texture=texture, - merge=merge, - format=format, - scale=scale, - ) - ) - task = Task(Index=0, Type="Export", Input=export_request, Output=export_response) - self.SendTask(task) - return task - - -def export_merge(self, selection: MF_V3_Settings_ScanSelection_ScanSelection = None, texture: bool = None, merge: bool = None, format: MF_V3_Settings_Export_Export.Format = None, scale: float = None) -> Task: - # Export a merged scan. - export_merge_request = MF_V3_Tasks_ExportMerge.Request( - Index=0, - Type="ExportMerge", - Input=MF_V3_Settings_Export_Export( - selection=selection, - texture=texture, - merge=merge, - format=format, - scale=scale, - ) - ) - export_merge_response = MF_V3_Tasks_ExportMerge.Response( - Index=0, - Type="ExportMerge", - Input=MF_V3_Settings_Export_Export( - selection=selection, - texture=texture, - merge=merge, - format=format, - scale=scale, - ) - ) - task = Task(Index=0, Type="ExportMerge", Input=export_merge_request, Output=export_merge_response) - self.SendTask(task) - return task - - -def export_logs(self, Input: bool = None) -> Task: - # Export scanner logs. - export_logs_request = MF_V3_Tasks_ExportLogs.Request( - Index=0, - Type="ExportLogs", - Input=Input - ) - export_logs_response = MF_V3_Tasks_ExportLogs.Response( - Index=0, - Type="ExportLogs" - ) - task = Task(Index=0, Type="ExportLogs", Input=export_logs_request, Output=export_logs_response) - self.SendTask(task) - return task - - -def has_cameras(self) -> Task: - # Check if the scanner has working cameras. - has_cameras_request = MF_V3_Tasks_HasCameras.Request( - Index=0, - Type="HasCameras" - ) - has_cameras_response = MF_V3_Tasks_HasCameras.Response( - Index=0, - Type="HasCameras" - ) - task = Task(Index=0, Type="HasCameras", Input=has_cameras_request, Output=has_cameras_response) - self.SendTask(task) - return task - - -def has_projector(self) -> Task: - # Check if the scanner has a working projector. - has_projector_request = MF_V3_Tasks_HasProjector.Request( - Index=0, - Type="HasProjector" - ) - has_projector_response = MF_V3_Tasks_HasProjector.Response( - Index=0, - Type="HasProjector" - ) - task = Task(Index=0, Type="HasProjector", Input=has_projector_request, Output=has_projector_response) - self.SendTask(task) - return task - - -def has_turntable(self) -> Task: - # Check if the scanner is connected to a working turntable. - has_turntable_request = MF_V3_Tasks_HasTurntable.Request( - Index=0, - Type="HasTurntable" - ) - has_turntable_response = MF_V3_Tasks_HasTurntable.Response( - Index=0, - Type="HasTurntable" - ) - task = Task(Index=0, Type="HasTurntable", Input=has_turntable_request, Output=has_turntable_response) - self.SendTask(task) - return task - - -def system_info(self, updateMajor: bool = None, updateNightly: bool = None) -> Task: - # Get system information. - system_info_request = MF_V3_Tasks_SystemInfo.Request( - Index=0, - Type="SystemInfo", - Input=MF_V3_Settings_Software_Software( - updateMajor=updateMajor, - updateNightly=updateNightly, - ) - ) - system_info_response = MF_V3_Tasks_SystemInfo.Response( - Index=0, - Type="SystemInfo", - Output=None - ) - task = Task(Index=0, Type="SystemInfo", Input=system_info_request, Output=system_info_response) - self.SendTask(task) - return task - - -def camera_calibration(self) -> Task: - # Get the camera calibration descriptor. - camera_calibration_request = MF_V3_Tasks_CameraCalibration.Request( - Index=0, - Type="CameraCalibration" - ) - camera_calibration_response = MF_V3_Tasks_CameraCalibration.Response( - Index=0, - Type="CameraCalibration" - ) - task = Task(Index=0, Type="CameraCalibration", Input=camera_calibration_request, Output=camera_calibration_response) - self.SendTask(task) - return task - - -def turntable_calibration(self) -> Task: - # Get the turntable calibration descriptor. - turntable_calibration_request = MF_V3_Tasks_TurntableCalibration.Request( - Index=0, - Type="TurntableCalibration" - ) - turntable_calibration_response = MF_V3_Tasks_TurntableCalibration.Response( - Index=0, - Type="TurntableCalibration" - ) - task = Task(Index=0, Type="TurntableCalibration", Input=turntable_calibration_request, Output=turntable_calibration_response) - self.SendTask(task) - return task - - -def calibration_capture_targets(self) -> Task: - # Get the calibration capture target for each camera calibration capture. - calibration_capture_targets_request = MF_V3_Tasks_CalibrationCaptureTargets.Request( - Index=0, - Type="CalibrationCaptureTargets" - ) - calibration_capture_targets_response = MF_V3_Tasks_CalibrationCaptureTargets.Response( - Index=0, - Type="CalibrationCaptureTargets" - ) - task = Task(Index=0, Type="CalibrationCaptureTargets", Input=calibration_capture_targets_request, Output=calibration_capture_targets_response) - self.SendTask(task) - return task - - -def calibrate_cameras(self) -> Task: - # Calibrate the cameras. - calibrate_cameras_request = MF_V3_Tasks_CalibrateCameras.Request( - Index=0, - Type="CalibrateCameras" - ) - calibrate_cameras_response = MF_V3_Tasks_CalibrateCameras.Response( - Index=0, - Type="CalibrateCameras" - ) - task = Task(Index=0, Type="CalibrateCameras", Input=calibrate_cameras_request, Output=calibrate_cameras_response) - self.SendTask(task) - return task - - -def calibrate_turntable(self) -> Task: - # Calibrate the turntable. - calibrate_turntable_request = MF_V3_Tasks_CalibrateTurntable.Request( - Index=0, - Type="CalibrateTurntable" - ) - calibrate_turntable_response = MF_V3_Tasks_CalibrateTurntable.Response( - Index=0, - Type="CalibrateTurntable" - ) - task = Task(Index=0, Type="CalibrateTurntable", Input=calibrate_turntable_request, Output=calibrate_turntable_response) - self.SendTask(task) - return task - - -def detect_calibration_card(self, Input: int) -> Task: - # Detect the calibration card on one or both cameras. - detect_calibration_card_request = MF_V3_Tasks_DetectCalibrationCard.Request( - Index=0, - Type="DetectCalibrationCard", - Input=Input - ) - detect_calibration_card_response = MF_V3_Tasks_DetectCalibrationCard.Response( - Index=0, - Type="DetectCalibrationCard", - Input=Input - ) - task = Task(Index=0, Type="DetectCalibrationCard", Input=detect_calibration_card_request, Output=detect_calibration_card_response) - self.SendTask(task) - return task - - -def restore_factory_calibration(self) -> Task: - # Restore factory calibration. - restore_factory_calibration_request = MF_V3_Tasks_RestoreFactoryCalibration.Request( - Index=0, - Type="RestoreFactoryCalibration" - ) - restore_factory_calibration_response = MF_V3_Tasks_RestoreFactoryCalibration.Response( - Index=0, - Type="RestoreFactoryCalibration" - ) - task = Task(Index=0, Type="RestoreFactoryCalibration", Input=restore_factory_calibration_request, Output=restore_factory_calibration_response) - self.SendTask(task) - return task - - -def start_video(self) -> Task: - # Start the video stream. - start_video_request = MF_V3_Tasks_StartVideo.Request( - Index=0, - Type="StartVideo" - ) - start_video_response = MF_V3_Tasks_StartVideo.Response( - Index=0, - Type="StartVideo" - ) - task = Task(Index=0, Type="StartVideo", Input=start_video_request, Output=start_video_response) - self.SendTask(task) - return task - - -def stop_video(self) -> Task: - # Stop the video stream. - stop_video_request = MF_V3_Tasks_StopVideo.Request( - Index=0, - Type="StopVideo" - ) - stop_video_response = MF_V3_Tasks_StopVideo.Response( - Index=0, - Type="StopVideo" - ) - task = Task(Index=0, Type="StopVideo", Input=stop_video_request, Output=stop_video_response) - self.SendTask(task) - return task - - -def set_cameras(self, selection: List[int] = None, autoExposure: bool = None, exposure: int = None, analogGain: float = None, digitalGain: int = None, focus: int = None) -> Task: - # Apply camera settings to one or both cameras. - set_cameras_request = MF_V3_Tasks_SetCameras.Request( - Index=0, - Type="SetCameras", - Input=MF_V3_Settings_Camera_Camera( - selection=selection, - autoExposure=autoExposure, - exposure=exposure, - analogGain=analogGain, - digitalGain=digitalGain, - focus=focus, - ) - ) - set_cameras_response = MF_V3_Tasks_SetCameras.Response( - Index=0, - Type="SetCameras" - ) - task = Task(Index=0, Type="SetCameras", Input=set_cameras_request, Output=set_cameras_response) - self.SendTask(task) - return task - - -def set_projector(self, on: bool = None, brightness: float = None, pattern: MF_V3_Settings_Projector_Projector.Pattern = None, image: MF_V3_Settings_Projector_Projector.Image = None, color: List[float] = None, buffer: bytes = None) -> Task: - # Apply projector settings. - set_projector_request = MF_V3_Tasks_SetProjector.Request( - Index=0, - Type="SetProjector", - Input=MF_V3_Settings_Projector_Projector( - on=on, - brightness=brightness, - pattern=pattern, - image=image, - color=color, - ) - ) - set_projector_response = MF_V3_Tasks_SetProjector.Response( - Index=0, - Type="SetProjector" - ) - task = Task(Index=0, Type="SetProjector", Input=set_projector_request, Output=set_projector_response) - self.SendTask(task, buffer) - return task - - -def auto_focus(self, applyAll: bool, cameras: List[MF_V3_Settings_AutoFocus_AutoFocus.Camera] = None) -> Task: - # Auto focus one or both cameras. - auto_focus_request = MF_V3_Tasks_AutoFocus.Request( - Index=0, - Type="AutoFocus", - Input=MF_V3_Settings_AutoFocus_AutoFocus( - applyAll=applyAll, - cameras=cameras, - ) - ) - auto_focus_response = MF_V3_Tasks_AutoFocus.Response( - Index=0, - Type="AutoFocus" - ) - task = Task(Index=0, Type="AutoFocus", Input=auto_focus_request, Output=auto_focus_response) - self.SendTask(task) - return task - - -def rotate_turntable(self, Input: int) -> Task: - # Rotate the turntable. - rotate_turntable_request = MF_V3_Tasks_RotateTurntable.Request( - Index=0, - Type="RotateTurntable", - Input=Input - ) - rotate_turntable_response = MF_V3_Tasks_RotateTurntable.Response( - Index=0, - Type="RotateTurntable", - Input=Input - ) - task = Task(Index=0, Type="RotateTurntable", Input=rotate_turntable_request, Output=rotate_turntable_response) - self.SendTask(task) - return task - - -def new_scan(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: - # Capture a new scan. - new_scan_request = MF_V3_Tasks_NewScan.Request( - Index=0, - Type="NewScan", - Input=MF_V3_Settings_Scan_Scan( - camera=camera, - projector=projector, - turntable=turntable, - capture=capture, - processing=processing, - ) - ) - new_scan_response = MF_V3_Tasks_NewScan.Response( - Index=0, - Type="NewScan" - ) - task = Task(Index=0, Type="NewScan", Input=new_scan_request, Output=new_scan_response) - self.SendTask(task) - return task - - -def depth_map(self, camera: MF_V3_Settings_Camera_Camera = None, projector: MF_V3_Settings_Projector_Projector = None, turntable: MF_V3_Settings_Turntable_Turntable = None, capture: MF_V3_Settings_Capture_Capture = None, processing: MF_V3_Settings_Scan_Scan.Processing = None) -> Task: - # Capture a depth map. - depth_map_request = MF_V3_Tasks_DepthMap.Request( - Index=0, - Type="DepthMap", - Input=MF_V3_Settings_Scan_Scan( - camera=camera, - projector=projector, - turntable=turntable, - capture=capture, - processing=processing, - ) - ) - depth_map_response = MF_V3_Tasks_DepthMap.Response( - Index=0, - Type="DepthMap" - ) - task = Task(Index=0, Type="DepthMap", Input=depth_map_request, Output=depth_map_response) - self.SendTask(task) - return task - - -def reboot(self) -> Task: - # Reboot the scanner. - reboot_request = MF_V3_Tasks_Reboot.Request( - Index=0, - Type="Reboot" - ) - reboot_response = MF_V3_Tasks_Reboot.Response( - Index=0, - Type="Reboot" - ) - task = Task(Index=0, Type="Reboot", Input=reboot_request, Output=reboot_response) - self.SendTask(task) - return task - - -def shutdown(self) -> Task: - # Shutdown the scanner. - shutdown_request = MF_V3_Tasks_Shutdown.Request( - Index=0, - Type="Shutdown" - ) - shutdown_response = MF_V3_Tasks_Shutdown.Response( - Index=0, - Type="Shutdown" - ) - task = Task(Index=0, Type="Shutdown", Input=shutdown_request, Output=shutdown_response) - self.SendTask(task) - return task - - - - diff --git a/maf_three/MF/V3/__init__.py b/maf_three/MF/V3/__init__.py deleted file mode 100644 index 2bcc874..0000000 --- a/maf_three/MF/V3/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from MF.V3.Buffer import * -from MF.V3.Task import * -from MF.V3.Three import * From b6f6d802fceb7a78b49bf1bcec32afd793d0fd9c Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 21 Nov 2024 21:56:33 -0500 Subject: [PATCH 83/86] Changes to use non deprecated build. CI updates --- .github/workflows/CI.yml | 101 ++++++++++++++------------------ .vscode/launch.json | 10 ++++ pyproject.toml | 3 +- requirements.txt | 3 +- scripts/incrementVersion.sh | 22 +++++++ three/LICENSE | 21 +++++++ three/MANIFEST.in | 5 -- three/PYPI_README.md | 56 ++++++++++++++++++ three/__init__.py | 2 +- three/examples/__main__.py | 3 +- three/examples/simpleScanner.py | 15 ++++- three/requirements.txt | 3 + three/setup.py | 41 ------------- 13 files changed, 175 insertions(+), 110 deletions(-) create mode 100755 scripts/incrementVersion.sh create mode 100644 three/LICENSE delete mode 100644 three/MANIFEST.in create mode 100644 three/PYPI_README.md create mode 100644 three/requirements.txt delete mode 100644 three/setup.py diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 4862d44..fc26fff 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -1,71 +1,60 @@ -name: CI Pipeline +name: CI -# Triggers of the Action: Push or Pull Request on: - pull_request: - branches: [ develop ] - types: [opened, review_requested, ready_for_review, synchronize] - - # Allows you to run this workflow manually from the Actions tab (when this yml is in the main branch) + push: + branches: + - develop workflow_dispatch: jobs: build: - if: ${{ github.event_name == 'push' || !github.event.pull_request.draft }} - strategy: - fail-fast: false # allow other OS to keep running when one fails - matrix: # Linux ; MacOS ; Windows - sys: - - { os: ubuntu-latest, shell: bash} - #- { os: windows-latest, shell: 'msys2 {0}' } - #- { os: macos-latest, shell: bash} - - # Set the default shell - defaults: - run: - shell: ${{ matrix.sys.shell }} - - runs-on: ${{ matrix.sys.os }} - -#################################################################### + runs-on: ubuntu-latest + steps: - - # Checkout the source and the submodules - - name: Checkout repository and submodules - uses: actions/checkout@v3 + - name: Checkout code + uses: actions/checkout@v2 with: - submodules: recursive - token: ${{ secrets.API_TOKEN_GITHUB }} - persist-credentials: true + submodules: true + fetch-depth: 0 - # Install dependencies - - name: Install dependencies - run: pip3 install -r requirements.txt - - # Set version - - name: Set Version + - name: Update submodules + run: git submodule update --init --recursive + + - name: Increment Version run: | - VERSION=$(python3 setup.py --version) - echo "__version__ = \"$VERSION\"" > three/__init__.py - - # Build proto files - - name: Build proto files - run: python3 ./scripts/build_proto.py + ./scripts/incrementVersion.sh - # Build - - name: Build - run: python3 -m build - - # Install our package (required for the tests to find the namespace : MF.V3) - - name: Install - run: pip3 install ./dist/three-0.0.0-py3-none-any.whl + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' - # Run the tests - - name: Test - run: python3 -m pytest + - name: Install build dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Transpile Schema + run: | + python ./scripts/build_proto.py - # Build the documentation - - name: Documentation - run: python3 ./scripts/build-doc.py + - name: Build the package + run: python -m build + - name: Publish to TestPyPI + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }} + run: | + pip install twine + twine upload --verbose --repository testpypi dist/* + - name: Commit and push changes + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@matterandform.net' + git add . + git commit -m "CI: Version bump and transpiled code [skip ci]" + git push + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 160af0c..e70e581 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -36,6 +36,16 @@ "console": "integratedTerminal", "cwd": "${workspaceFolder}", "justMyCode": true + }, + { + "name": "Python: Setup Wheel", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/three/setup.py", + "args": ["sdist", "bdist_wheel"], + "console": "integratedTerminal", + "cwd": "${workspaceFolder}", + "justMyCode": true } ] } diff --git a/pyproject.toml b/pyproject.toml index 4f95b67..b4b71c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,6 +8,7 @@ build-backend = "setuptools.build_meta" [project] name = "three" description = "Matter and Form - THREE - Library" +readme = "./three/PYPI_README.md" dynamic = ["version"] classifiers = [ "Programming Language :: Python :: 3", @@ -22,7 +23,7 @@ dependencies = [ # URLs [project.urls] -Homepage = "https://matterandform.net" +Homepage = "https://github.com/Matter-and-Form/three-python-library" Documentation = "https://github.com/Matter-and-Form/three-python-library/wiki" # Package source diff --git a/requirements.txt b/requirements.txt index 5932c5a..7780874 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ protobuf==5.28.3 pycodestyle==2.12.1 pyflakes==3.2.0 websocket-client==1.8.0 -wheel \ No newline at end of file +wheel +build \ No newline at end of file diff --git a/scripts/incrementVersion.sh b/scripts/incrementVersion.sh new file mode 100755 index 0000000..61d9061 --- /dev/null +++ b/scripts/incrementVersion.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Path to the __init__.py file +INIT_FILE="./three/__init__.py" + +# Extract the current version +CURRENT_VERSION=$(grep -oP "(?<=__version__ = ')[^']*" "$INIT_FILE") +echo "Current version: $CURRENT_VERSION" + +# Split the version into its components +IFS='.' read -r -a VERSION_PARTS <<< "$CURRENT_VERSION" + +# Increment the build number +VERSION_PARTS[2]=$((VERSION_PARTS[2] + 1)) + +# Construct the new version +NEW_VERSION="${VERSION_PARTS[0]}.${VERSION_PARTS[1]}.${VERSION_PARTS[2]}" + +# Update the __init__.py file with the new version +sed -i "s/__version__ = '$CURRENT_VERSION'/__version__ = '$NEW_VERSION'/" "$INIT_FILE" + +echo "Version updated from $CURRENT_VERSION to $NEW_VERSION" \ No newline at end of file diff --git a/three/LICENSE b/three/LICENSE new file mode 100644 index 0000000..0cd4f3a --- /dev/null +++ b/three/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Matter and Form + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/three/MANIFEST.in b/three/MANIFEST.in deleted file mode 100644 index b9081f5..0000000 --- a/three/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include README.md -include LICENSE -include requirements.txt -recursive-include your_package_name *.py -recursive-include your_package_name *.pyi \ No newline at end of file diff --git a/three/PYPI_README.md b/three/PYPI_README.md new file mode 100644 index 0000000..bdfdf30 --- /dev/null +++ b/three/PYPI_README.md @@ -0,0 +1,56 @@ +# Matter and Form THREE Library + +## Overview +The Matter and Form THREE library provides a comprehensive API for controlling and interacting with the Matter and Form THREE scanner. This library allows developers to build custom integrations, automate tasks, and create new front-end systems for 3D scanning. + +## Project Home +[Github Project HERE](https://github.com/Matter-and-Form/three-python-library). + +## Examples + +### Using Premade Examples +To connect to the scanner, you can use the provided examples. For instance, to run the connection example, execute: + +```sh +python examples/connect.py +``` + +### Simple Example +Here is an example of how to use the library to connect to the scanner and control the projector: + +```python +from matter_and_form_three import Scanner + +# Create and connect to the scanner +scanner = Scanner(OnTask=None, OnMessage=None, OnBuffer=None) +# Use the Zeroconf address or replace with the ip +scanner.Connect("ws://matterandform.local:8081") + +# Simple request to list all projects +projectTask = scanner.list_projects() + +# Check the output from the task for errors +if projectTask.Error: + print('Error:', projectTask.Error) + return +# Do something with the output +for project_obj in projectTask.Output: + project = Project.Brief(**project_obj) + print('Project index:', project.index, ' - Name:', project.name) +``` + +### More Examples +The library comes with several pre-made examples. You can find them in the [examples directory](https://github.com/Matter-and-Form/three-python-library/tree/develop/three/examples). + +To run a specific example, use: + +```sh +python three/examples/.py +``` + +## Documentation +For detailed documentation, visit the TODO -> [official documentation](https://github.com/Matter-and-Form/three-python-library/wiki). + + +## License +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. \ No newline at end of file diff --git a/three/__init__.py b/three/__init__.py index 5400bb9..dc2a9e6 100644 --- a/three/__init__.py +++ b/three/__init__.py @@ -1 +1 @@ -__version__ = '8.20.0' \ No newline at end of file +__version__ = '8.20.6' \ No newline at end of file diff --git a/three/examples/__main__.py b/three/examples/__main__.py index fe1d98e..a3917d9 100644 --- a/three/examples/__main__.py +++ b/three/examples/__main__.py @@ -2,13 +2,12 @@ import sys -from three.examples import connection, projector, turntable, task, turntableCalibration, simpleScanner +from three.examples import connection, projector, task, turntableCalibration, simpleScanner # Available examples dictionary examples = { 'connection': connection, 'projector': projector, - 'turntable': turntable, 'task': task, 'turntableCalibration': turntableCalibration, 'simpleScanner': simpleScanner diff --git a/three/examples/simpleScanner.py b/three/examples/simpleScanner.py index e4917d5..4dbce83 100644 --- a/three/examples/simpleScanner.py +++ b/three/examples/simpleScanner.py @@ -6,9 +6,18 @@ # Three library from three.scanner import Scanner -from three.MF.V3.Settings import Capture, Camera, Projector, Turntable, ScanSelection, Export, Quality -from three.MF.V3.Descriptors import Project -from three.MF.V3.Descriptors.Settings import Scanner as ScannerDescriptor, Camera as CameraDescriptor, Projector as ProjectorDescriptor, Turntable as TurntableDescriptor, Capture as CaptureDescriptor +from three.MF.V3.Settings.Projector import Projector +from three.MF.V3.Settings.Capture import Capture +from three.MF.V3.Settings.Camera import Camera +from three.MF.V3.Settings.Turntable import Turntable +from three.MF.V3.Settings.ScanSelection import ScanSelection +from three.MF.V3.Settings.Export import Export +from three.MF.V3.Settings.Quality import Quality +from three.MF.V3.Descriptors.Project import Project +from three.MF.V3.Descriptors.Settings.Camera import Camera as CameraDescriptor +from three.MF.V3.Descriptors.Settings.Projector import Projector as ProjectorDescriptor +from three.MF.V3.Descriptors.Settings.Turntable import Turntable as TurntableDescriptor +from three.MF.V3.Descriptors.Settings.Capture import Capture as CaptureDescriptor from three.MF.V3 import Task, TaskState # Two frames for the video stream diff --git a/three/requirements.txt b/three/requirements.txt new file mode 100644 index 0000000..8c99434 --- /dev/null +++ b/three/requirements.txt @@ -0,0 +1,3 @@ +numpy==2.1.3 +protobuf==5.28.3 +websocket-client==1.8.0 \ No newline at end of file diff --git a/three/setup.py b/three/setup.py deleted file mode 100644 index bfb56cb..0000000 --- a/three/setup.py +++ /dev/null @@ -1,41 +0,0 @@ -from setuptools import setup, find_packages -import os - -# Function to read the version from three/__init__.py -def get_version(): - version_file = os.path.join('three', '__init__.py') - with open(version_file, 'r') as f: - exec(f.read(), globals()) - return __version__ - -# Read the requirements from requirements.txt -with open('requirements.txt', 'r') as f: - requirements = f.read().splitlines() - -# Read the long description from README.md -with open('README.md', 'r', encoding='utf-8') as f: - long_description = f.read() - -setup( - name='three', - version=get_version(), - description='Matter and Form - THREE - Library', - long_description=long_description, - long_description_content_type='text/markdown', - author='Matter and Form', - author_email='info@matterandform.net', - url='https://github.com/Matter-and-Form/three-python-library', - packages=find_packages(exclude=['tests', 'scripts', 'examples']), - include_package_data=True, - install_requires=requirements, - python_requires='>=3.10', - classifiers=[ - 'Programming Language :: Python :: 3', - 'Operating System :: OS Independent', - ], - entry_points={ - 'console_scripts': [ - 'examples=three.examples:main_cli', - ], - }, -) \ No newline at end of file From 9151365b2b7568a13333c88c75d6670354ce7f1e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 22 Nov 2024 02:57:09 +0000 Subject: [PATCH 84/86] CI: Version bump and transpiled code [skip ci] --- three/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/three/__init__.py b/three/__init__.py index dc2a9e6..80e22a4 100644 --- a/three/__init__.py +++ b/three/__init__.py @@ -1 +1 @@ -__version__ = '8.20.6' \ No newline at end of file +__version__ = '8.20.7' \ No newline at end of file From a53dbc38b06a0556d8fe9cb4218d5c5973ef6948 Mon Sep 17 00:00:00 2001 From: drewsipher Date: Thu, 21 Nov 2024 22:22:05 -0500 Subject: [PATCH 85/86] Changes to package name, and CI CD --- .github/workflows/CD.yml | 151 +++++++++++++-------------------------- .github/workflows/CI.yml | 18 ++++- pyproject.toml | 2 +- 3 files changed, 68 insertions(+), 103 deletions(-) diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 9cc556f..538a693 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -1,120 +1,69 @@ -name: CD Pipeline +name: CI -# The pipeline is triggered by tags being pushed. on: push: - tags: - - 'v*.*.*' # Library version - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: "pages" - cancel-in-progress: false + branches: + - release + workflow_dispatch: jobs: - Continuous_Deployment: + build: runs-on: ubuntu-latest - - # 1. Extract information from the tag (version number, channel). - # 2. Build the python package. - # 3. Update the package to the repo. - steps: - # Checkout the source and the submodules - - name: Checkout repository and submodules - uses: actions/checkout@v3 + steps: + - name: Checkout code + uses: actions/checkout@v2 with: - submodules: recursive - token: ${{ secrets.API_TOKEN_GITHUB }} - persist-credentials: true + submodules: true + fetch-depth: 0 - ############## 1. Extract information from the tag ############## + - name: Update submodules + run: git submodule update --init --recursive + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' - # Check tag - - name: Check tag + - name: Install build dependencies run: | - echo "Checking tag: ${GITHUB_REF_NAME}" - source ./scripts/github-tag - CheckTag ${GITHUB_REF_NAME} - - # Get version number - - name: Tag -> Version + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Transpile Schema run: | - source scripts/github-tag - echo "PACKAGE_VERSION=$(VersionFromTag ${GITHUB_REF_NAME})" >> $GITHUB_ENV + python ./scripts/build_proto.py - # Get the release channel: stable vs testing - - name: Tag -> Channel - run: | - source scripts/github-tag - echo "PACKAGE_CHANNEL=$(ChannelFromTag ${GITHUB_REF_NAME})" >> $GITHUB_ENV + - name: Build the package + run: python -m build - # Print out info - - name: Package Info + - name: Publish to PyPI + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} run: | - echo "Version: $PACKAGE_VERSION" - echo "Channel: $PACKAGE_CHANNEL" - - - ############## 2. Build the python package. ############## + pip install twine + twine upload --verbose --repository pypi dist/* - # Install dependencies - - name: Install dependencies + - name: Commit and push changes run: | - pip3 install -r requirements.txt - pip3 install twine - - # Set version - - name: Set Version - run: echo "__version__ = \"${{ env.PACKAGE_VERSION }}\"" > three/__init__.py - - # Build proto files - - name: Build proto files - run: python3 ./scripts/build_proto.py - - # Build - - name: Build - run: python3 -m build - - # Install our package (required for the tests to find the namespace : MF.V3) - - name: Install - run: pip3 install ./dist/three-${{ env.PACKAGE_VERSION }}-py3-none-any.whl - - # Run the tests - - name: Test - run: python3 -m pytest - - # Build the documentation - - name: Documentation - run: python3 ./scripts/build-doc.py - - - ############## 3. Upload the package and the documentation. ############## - - # Upload python package to testpypi - - name: Upload to TestPyPi - run: twine upload --repository testpypi dist/* -u__token__ -p${{ secrets.TESTPYPI_TOKEN }} - #run: twine upload dist/* -u__token__ -p${{ secrets.PYPI_TOKEN }} - - - # Upload the documentation - - name: Setup Pages - uses: actions/configure-pages@v5 + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@matterandform.net' + git add . + git commit -m "Publish new version to PyPi [skip ci]" + git push + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract version + id: extract_version + run: | + CURRENT_VERSION=$(grep -oP "(?<=__version__ = ')[^']*" ./three/__init__.py) + echo "TAG=$CURRENT_VERSION" >> $GITHUB_ENV - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 + - name: Create a Release + uses: softprops/action-gh-release@v1 with: - path: './doc/build/html' - - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 - - + files: dist/* + token: ${{ secrets.GITHUB_TOKEN }} + tag_name: ${{ env.TAG }} diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index fc26fff..49448cc 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -57,4 +57,20 @@ jobs: git commit -m "CI: Version bump and transpiled code [skip ci]" git push env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract version number + id: extract_version + run: | + CURRENT_VERSION=$(grep -oP "(?<=__version__ = ')[^']*" ./three/__init__.py) + echo "VERSION=$CURRENT_VERSION" >> $GITHUB_ENV + + - name: Create Pull Request to merge develop into release + uses: peter-evans/create-pull-request@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "CI: Merge develop into release" + base: "develop" + branch: "release" + title: "New Release Candidate v${{ env.VERSION }}" + body: "This is an new release candidate for three-python. Merging this will distribute the new version to pypi." diff --git a/pyproject.toml b/pyproject.toml index b4b71c9..a9d5e50 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" # Package info and dependencies [project] -name = "three" +name = "mfthree" description = "Matter and Form - THREE - Library" readme = "./three/PYPI_README.md" dynamic = ["version"] From e313050c72c1de4cc25404ac243b8517060e49ec Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 22 Nov 2024 03:22:41 +0000 Subject: [PATCH 86/86] CI: Version bump and transpiled code [skip ci] --- three/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/three/__init__.py b/three/__init__.py index 80e22a4..f9614df 100644 --- a/three/__init__.py +++ b/three/__init__.py @@ -1 +1 @@ -__version__ = '8.20.7' \ No newline at end of file +__version__ = '8.20.8' \ No newline at end of file