-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Squashed commit of the following: commit 4acc015 Author: JoeBell <joe@onmyhonor.com> Date: Sun Mar 9 18:00:03 2025 -0400 Added normalize function Added function to normalize the scale of meshes commit e685ab2 Merge: 968cbac cc38025 Author: JoeBell <joe@onmyhonor.com> Date: Tue Mar 4 21:28:20 2025 -0500 Merge branch 'main' into shipgen-integration commit 968cbac Author: JoeBell <joe@onmyhonor.com> Date: Tue Mar 4 20:58:29 2025 -0500 Added conversion Added helper functions to convert stl.Mesh's to triangle arrays commit 13a589f Author: JoeBell <joe@onmyhonor.com> Date: Tue Mar 4 20:47:02 2025 -0500 Cleaned up Generate commit 22876e9 Merge: f92334b adb4ab8 Author: JoeBell <joe@onmyhonor.com> Date: Tue Mar 4 20:08:58 2025 -0500 Merge branch 'main' into shipgen-integration commit f92334b Author: JoeBell <joe@onmyhonor.com> Date: Tue Mar 4 19:39:31 2025 -0500 Renamed parameters commit f261895 Author: JoeBell <joe@onmyhonor.com> Date: Tue Mar 4 19:37:13 2025 -0500 Stopped warning message commit bf90105 Author: JoeBell <joe@onmyhonor.com> Date: Tue Mar 4 19:26:12 2025 -0500 Fixed unused parameter commit f79dbc1 Author: JoeBell <joe@onmyhonor.com> Date: Tue Mar 4 19:14:46 2025 -0500 Removed need to save stl's commit c640f6c Author: JoeBell <joe@onmyhonor.com> Date: Tue Mar 4 19:05:02 2025 -0500 Improved typing commit 19cf09b Author: JoeBell <joe@onmyhonor.com> Date: Tue Mar 4 18:48:43 2025 -0500 Added hull generator commit e8845c8 Author: JoeBell <joe@onmyhonor.com> Date: Tue Mar 4 16:18:36 2025 -0500 Uploaded streamlined ShipGen Uploaded a version of ShipGen modified from https://www.dropbox.com/sh/jg98r425v7ly89l/AAA49uMr7_mhaVmRDrPq0NU_a?dl=0 with all non-essential files removed * Added Custom Types Everything runs abut half as fast but it is much less error prone and more readable * Changed Raytrace Imports Change the Raytrace library so that mesh classes can be imported directly * Restructured Raytrace Library Moved the mesh classes into their own folder * Fixed Typo Related Bug Passing a Vector3 to the Vector3 constructor no longer causes an error * Redid Custom Types Custom types are now better integrated with numpy to get speed back to around where they were (well, 2/3rds the speed but whos counting) * Added Triangle output to Raytrace Raytracing functions now return a distance and a triangle. Subclasses now overwrite the raytrace_as_tri method * Added Explicate Reexports Added reexports to AUVSim * Created Generate Folder * Created Scan Utilities Added functions to help position AUVs and scan paths * Made CompositeMesh.triangles getter Modified CompositeMesh to make instantiating large quantities less intensive * Renamed AUV Utilities * Added Parallelism to AUV Utilities Made functions in the AUV utilities that take arrays in addition to their single value counter-parts * Added Hull Utilities Added utilities for generating hulls and placing anomalies * Created Outline Added an outline notebook that walks through how to create items for the dataset * Fixed Point Randomizer Fixed bug where random point had a 50% chance of not being on the triangle * Fixed Surface Normal * Fixed Outline
- Loading branch information
Showing
40 changed files
with
4,994 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
# Created by venv; see https://docs.python.org/3/library/venv.html | ||
ShipD/ | ||
ShipGen/ | ||
Scripts/ | ||
Lib/ | ||
Include/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
from .auv import ( | ||
AUV, | ||
AUVPath, | ||
AUVPathGen | ||
AUV as AUV, | ||
AUVPath as AUVPath, | ||
AUVPathGen as AUVPathGen, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
__pycache__/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from .auv import( | ||
place_auvs_over_points as place_auvs_over_points, | ||
generate_paths as generate_paths, | ||
scan_paths as scan_paths, | ||
) | ||
from .hull import ( | ||
generate_hulls as generate_hulls, | ||
generate_points_on_hull as generate_points_on_hull, | ||
generate_vertical_bounds as generate_vertical_bounds, | ||
load_anomalies as load_anomalies, | ||
pick_anomalies as pick_anomalies, | ||
place_anomalies_at_points as place_anomalies_at_points, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
from typing import Callable | ||
|
||
from CustomTypes import Vector3, Vector3Array | ||
from Raytrace import TriangleMesh | ||
from AUVSim import AUV, AUVPathGen, AUVPath | ||
from Raytrace.SideScan import SideScan, ScanReading, RawScanReading | ||
|
||
from .helper import get_surface_normal, normalize | ||
|
||
def place_auv_over_point( | ||
point:Vector3, | ||
mesh:TriangleMesh, | ||
distance: float, | ||
align_start_facing = True, | ||
use_cw_normal:None|bool = None, | ||
) -> AUV: | ||
normal = get_surface_normal(mesh, point, use_cw_normal) | ||
position = point + normal * distance | ||
facing = Vector3(1, 0, 0) | ||
if align_start_facing: | ||
facing = normalize(Vector3(-normal[1], normal[0], 0)) # tangent w/ no z | ||
|
||
return AUV(position, facing, distance) | ||
|
||
def place_auvs_over_points( | ||
points:Vector3Array, | ||
meshs:TriangleMesh|list[TriangleMesh], | ||
distance: float, | ||
align_start_facing = True, | ||
use_cw_normal:None|bool = None, | ||
) -> list[AUV]: | ||
if not isinstance(meshs, list): | ||
meshs = [meshs] * len(points) | ||
return [ | ||
place_auv_over_point(point, mesh, distance, align_start_facing, use_cw_normal) | ||
for point, mesh in zip(points, meshs) | ||
] | ||
|
||
def generate_path( | ||
mesh:TriangleMesh, | ||
auv:AUV, | ||
travel_distance:float, | ||
samples:int, | ||
back_steps:int|None = None, | ||
) -> AUVPath: | ||
# Step 1: Backstep | ||
if not (back_steps is None): | ||
auv_copy = AUV(auv.start_pos, auv.start_facing) | ||
auv_copy.ideal_distance = auv.ideal_distance | ||
back_dist = travel_distance / (samples - 1) * back_steps | ||
auv = step_back_auv(mesh, auv_copy, back_dist, back_steps) | ||
# Step 2: Get path | ||
return AUVPathGen(mesh, auv).get_path(travel_distance, samples) | ||
|
||
def generate_paths( | ||
meshs:TriangleMesh|list[TriangleMesh], | ||
auvs:list[AUV], | ||
travel_distance:float, | ||
samples:int, | ||
back_steps:int|None|list[int|None] = None, | ||
) -> list[AUVPath]: | ||
if not isinstance(meshs, list): | ||
meshs = [meshs] * len(auvs) | ||
if not isinstance(back_steps, list): | ||
back_steps = [back_steps] * len(auvs) | ||
return [ | ||
generate_path(mesh, auv, travel_distance, samples, bs) | ||
for mesh, auv, bs in zip(meshs, auvs, back_steps) | ||
] | ||
|
||
def step_back_auv( | ||
mesh:TriangleMesh, | ||
auv:AUV, | ||
travel_distance:float, | ||
steps:int, | ||
) -> AUV: | ||
auv.start_facing = auv.start_facing * -1 | ||
path_gen = AUVPathGen(mesh, auv) | ||
back_start = path_gen.get_path(travel_distance, steps + 1).rays[-1] | ||
auv.start_facing = auv.start_facing * -1 # undo changes | ||
|
||
return AUV(back_start.origin, back_start.direction * -1, auv.ideal_distance) | ||
|
||
def scan_path( | ||
scanner:SideScan, | ||
path: AUVPath, | ||
min_angle:float, | ||
max_angle:float, | ||
angle_reselution:int, | ||
silent:bool = False, | ||
process:Callable[[RawScanReading], ScanReading] = ScanReading | ||
) -> list[ScanReading]: | ||
readings:list[ScanReading] = [] | ||
for n, orientation in enumerate(path.rays): | ||
rays = SideScan.generate_rays(orientation, min_angle, max_angle, angle_reselution) | ||
if not silent: | ||
print(n + 1, len(path.rays), sep='/', end=' \r') | ||
readings.append(process(scanner.scan_rays(rays))) | ||
return readings | ||
def scan_paths( | ||
scanners:SideScan|list[SideScan], | ||
paths: list[AUVPath], | ||
min_angle:float, | ||
max_angle:float, | ||
angle_reselution:int, | ||
silent:bool = False, | ||
process:Callable[[RawScanReading], ScanReading] = ScanReading | ||
) -> list[list[ScanReading]]: | ||
if not isinstance(scanners, list): | ||
scanners = [scanners] * len(paths) | ||
return [ | ||
scan_path(scanner, path, min_angle, max_angle, angle_reselution, silent, process) | ||
for scanner, path in zip(scanners, paths) | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import numpy as np | ||
|
||
from CustomTypes import Ray, Vector3 | ||
from Raytrace import TriangleMesh | ||
|
||
|
||
def normalize(v:Vector3) -> Vector3: | ||
return v / float(np.sqrt(v.dot(v))) | ||
|
||
def get_surface_normal( | ||
mesh:TriangleMesh, | ||
point:Vector3, | ||
use_cw_normal:None|bool = None, | ||
): | ||
# Step 1: Find the triangle at the point | ||
# NOTE: Using the closest centroid is not necesarily correct | ||
# But its a decent aproximation in most cases | ||
min_ind = find_closest_centroid_ind(mesh, point) | ||
tri = mesh.triangles[min_ind] | ||
if tri is None: raise ValueError(f"sample_ray could not find surface at point {point}") | ||
# Step 2: Find the normal at the triangle | ||
normal = np.cross(tri[1] - tri[0], tri[2] - tri[0]).view(Vector3) | ||
normal = normalize(normal) | ||
if use_cw_normal: | ||
normal = normal * -1 | ||
if use_cw_normal is None: # Guess at correct normal direction | ||
if (normal[1] < 0) != (point[1] < 0): | ||
normal = normal * -1 # Point normal away from xz plane | ||
return normal | ||
|
||
def find_closest_centroid_ind( | ||
mesh:TriangleMesh, | ||
point:Vector3, | ||
) -> int: | ||
# NOTE: Could (probably) be sped up with scipy.spatial.KDTree | ||
rel_pos = mesh.centroids - point | ||
sqr_dist = np.sum(rel_pos*rel_pos, axis=-1) | ||
return int(np.argmin(sqr_dist)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
from copy import deepcopy | ||
from typing import overload | ||
|
||
import numpy as np | ||
from CustomTypes import Vector3, TriangleArray, Vector3Array | ||
from Raytrace import TriangleMesh, CompositeMesh, BVHMesh | ||
import ShipGen as SG | ||
import random | ||
|
||
def generate_hulls( | ||
find_best:int, | ||
out_of:int, | ||
x_length:float|None = None, | ||
characteristics:SG.ShipCharacteristics|None = None, | ||
silent:bool = False, | ||
) -> list[BVHMesh]: | ||
# Step 1: Generate the hulls | ||
raw_hulls = SG.generate_hulls(find_best, out_of, characteristics) | ||
# Step 2: Apply scale | ||
if not (x_length is None): | ||
for hull in raw_hulls: | ||
SG.normalize_x(hull, x_length) | ||
# Step 3: Convert them to BVHs | ||
triangles_list = SG.mesh_list_to_triangles(raw_hulls) | ||
hulls:list[BVHMesh] = [] | ||
for n, triangles in enumerate(triangles_list): | ||
if not silent: | ||
print(f'Building BVH {n} / {len(triangles_list)}') | ||
hulls.append(BVHMesh(triangles, min_node_size = 100)) | ||
return hulls | ||
|
||
def place_anomaly_at_point( | ||
hull:TriangleMesh, | ||
anomaly:TriangleMesh, | ||
point:Vector3, | ||
) -> CompositeMesh: | ||
anomaly = deepcopy(anomaly) | ||
# TODO: A proper addition method should be implemented | ||
# HACK: Will only work fully for regular TriangleMesh | ||
if type(anomaly) != TriangleMesh: | ||
raise NotImplementedError('place_anomaly_at_point only works for anomalies of type TriangleMesh (no subclasses)') | ||
anomaly.triangles = TriangleArray(anomaly.triangles + point) | ||
|
||
return CompositeMesh([hull, anomaly]) | ||
def place_anomalies_at_points( | ||
hull:TriangleMesh, | ||
anomalies:list[TriangleMesh], | ||
points:Vector3Array, | ||
) -> list[CompositeMesh]: | ||
return [ | ||
place_anomaly_at_point(hull, anomaly, point) | ||
for anomaly, point in zip(anomalies, points) | ||
] | ||
|
||
def generate_point_on_hull_anywhere( | ||
hull:TriangleMesh, | ||
) -> Vector3: | ||
# NOTE: not a perfectly even distribution | ||
triangle_ind = random.randint(0, len(hull.triangles)) | ||
triangle = hull.triangles[triangle_ind] | ||
rand_x = random.random() | ||
rand_y = random.random() | ||
if rand_y > 1 - rand_x: # outside triangle | ||
rand_x = 1 - rand_x | ||
rand_y = 1 - rand_y | ||
off_x = (triangle[1] - triangle[0]) * rand_x | ||
off_y = (triangle[2] - triangle[0]) * rand_y | ||
return triangle[0] + off_x + off_y | ||
def generate_point_on_hull_in( | ||
hull:TriangleMesh, | ||
min_bound:Vector3, | ||
max_bound:Vector3, | ||
attempts:int = 1000 | ||
) -> Vector3: | ||
for _ in range(attempts): | ||
point = generate_point_on_hull_anywhere(hull) | ||
if np.all(min_bound <= point) and np.all(point <= max_bound): | ||
return point | ||
raise RuntimeError(f'Was not able to generate valid point within {attempts} attempts') | ||
|
||
def generate_point_on_hull( | ||
hull:TriangleMesh, | ||
min_bound:Vector3|None = None, | ||
max_bound:Vector3|None = None, | ||
attempts:int = 1000 | ||
) -> Vector3: | ||
if min_bound is None or max_bound is None: | ||
return generate_point_on_hull_anywhere(hull) | ||
else: | ||
return generate_point_on_hull_in(hull, min_bound, max_bound, attempts) | ||
def generate_points_on_hull( | ||
count:int, | ||
hull:TriangleMesh, | ||
min_bound:Vector3|None = None, | ||
max_bound:Vector3|None = None, | ||
attempts:int = 1000 | ||
) -> Vector3Array: | ||
return Vector3Array([ | ||
generate_point_on_hull(hull, min_bound, max_bound, attempts) | ||
for _ in range(count)]) | ||
|
||
def generate_vertical_bounds( | ||
hull:TriangleMesh, | ||
cut_percentage:float, | ||
) -> tuple[Vector3, Vector3]: | ||
min_z = np.min(hull.triangles.nd[:,2]) | ||
max_z = np.max(hull.triangles.nd[:,2]) | ||
height = max_z - min_z | ||
min_bound = Vector3(-np.inf, -np.inf, min_z + height * cut_percentage) | ||
max_bound = Vector3( np.inf, np.inf, max_z - height * cut_percentage) | ||
return min_bound, max_bound | ||
|
||
def load_anomalies(paths:str|list[str]) -> list[TriangleMesh]: | ||
if isinstance(paths, str): return load_anomalies([paths]) | ||
return [TriangleMesh(stl_path = path) for path in paths] | ||
def pick_anomalies( | ||
count:int, | ||
anomalies:list[TriangleMesh], | ||
weights:list[float], | ||
) -> list[TriangleMesh]: | ||
#TODO: Implement weights | ||
return [random.choice(anomalies) for _ in range(count)] |
Oops, something went wrong.