Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pruning Improvements and Voxel Regions + Bugfix & Cleanup #175

Merged
merged 28 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
44d1770
Added object inradius test + bugfix.
Eric-Vin Sep 7, 2023
3bad697
Added planarInradius functionality and tests for proper 2D pruning.
Eric-Vin Sep 8, 2023
682154c
Improved pruning for 2d regions.
Eric-Vin Sep 8, 2023
627893c
Rudimentary VoxelRegion implementation.
Eric-Vin Sep 11, 2023
e6f6922
Added volume and dimensionality to VoxelRegion.
Eric-Vin Sep 11, 2023
c539dd4
Pruning cleanup.
Eric-Vin Sep 11, 2023
5ddfab3
Progress on mesh voxelization pruning.
Eric-Vin Sep 12, 2023
de2bf66
More cleanup and fixes for voxelization.
Eric-Vin Sep 13, 2023
6bb59ab
Pared back voxel region constructor.
Eric-Vin Sep 13, 2023
3230375
Fixed scipy interpreting 0 as reach fixpoint.
Eric-Vin Sep 13, 2023
9d6a8c3
Remove lazy return.
Eric-Vin Sep 13, 2023
855e976
Tighter bound on erosion.
Eric-Vin Sep 13, 2023
a6ac69f
In pruning, ensure vozelization overapproximates mesh.
Eric-Vin Sep 13, 2023
7c32bc9
Ensure planarInradius is only used when there is no pitch or roll.
Eric-Vin Sep 14, 2023
a32a598
More pruning work.
Eric-Vin Sep 18, 2023
98a3d4d
Visibiliy pruning work.
Eric-Vin Oct 4, 2023
4174128
Use conditioned value when pruning visibility.
Eric-Vin Oct 4, 2023
6993f02
Only prune fixed view regions now.
Eric-Vin Oct 4, 2023
dec858b
Updated inradius and planarInradius to have proper return types.
Eric-Vin Oct 5, 2023
dbb149a
Fully implemented visibility pruning.
Eric-Vin Oct 5, 2023
9110b25
Add proper dependency check.
Eric-Vin Oct 9, 2023
b790262
More work on visibility pruning.
Eric-Vin Oct 10, 2023
88d2ac2
Visibility pruning tests.
Eric-Vin Oct 11, 2023
2a117c9
Couldn't get hack to work for vector norm.
Eric-Vin Oct 12, 2023
c45b4df
Pruning tweaks and VoxelRegion optimizations.
Eric-Vin Oct 13, 2023
84071ae
Slight pruning module re-org.
Eric-Vin Nov 9, 2023
7738224
PR fixes.
Eric-Vin Jan 11, 2024
0a75bfc
3DPruningImprovements PR Fixes
Eric-Vin Jan 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 120 additions & 48 deletions src/scenic/core/object_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import trimesh

from scenic.core.distributions import (
FunctionDistribution,
MultiplexerDistribution,
RandomControlFlowError,
Samplable,
Expand Down Expand Up @@ -1255,67 +1256,138 @@ def boundingBox(self):
@cached_property
def inradius(self):
"""A lower bound on the inradius of this object"""
# First check if all needed variables are defined. If so, we can
# compute the inradius exactly.
width, length, height = self.width, self.length, self.height
shape = self.shape
if not any(needsSampling(val) for val in (width, length, height, shape)):
shapeRegion = MeshVolumeRegion(

# Define a helper function that computes the actual inradius
def inradiusActual(width, length, height, shape):
return MeshVolumeRegion(
mesh=shape.mesh, dimensions=(width, length, height)
)
return shapeRegion.inradius
).inradius

# Define a helper function that computes the support of the inradius,
# given the sub supports.
def inradiusSupport(width_s, length_s, height_s, shape_s):
# Unpack the dimension supports (and ignore the shape support)
min_width, max_width = width_s
min_length, max_length = length_s
min_height, max_height = height_s

if None in [
min_width,
max_width,
min_length,
max_length,
min_height,
max_height,
]:
# Can't get a bound on one or more dimensions, abort
return None, None

min_bounds = np.array([min_width, min_length, min_height])
max_bounds = np.array([max_width, max_length, max_height])

# Extract a list of possible shapes
if isinstance(self.shape, Shape):
shapes = [self.shape]
elif isinstance(self.shape, MultiplexerDistribution) and all(
isinstance(opt, Shape) for opt in self.shape.options
):
shapes = self.shape.options
else:
# Something we don't recognize, abort
return None, None

# If we havea uniform distribution over shapes and a supportInterval for each dimension,
# we can compute a supportInterval for this object's inradius
# Get the inradius for each shape with the min and max bounds
min_distances = [
MeshVolumeRegion(mesh=shape.mesh, dimensions=min_bounds).inradius
for shape in shapes
]
max_distances = [
MeshVolumeRegion(mesh=shape.mesh, dimensions=max_bounds).inradius
for shape in shapes
]

# Define helper class
class InradiusHelper:
def __init__(self, support):
self.support = support
distance_range = (min(min_distances), max(max_distances))

def supportInterval(self):
return self.support
return distance_range

# Extract bounds on all dimensions
min_width, max_width = supportInterval(width)
min_length, max_length = supportInterval(length)
min_height, max_height = supportInterval(height)
# Return either the inradius or a FunctionDistribution using the above helpers
args = toDistribution((self.width, self.length, self.height, self.shape))
if not isLazy(args):
return inradiusActual(*args)
else:
return FunctionDistribution(
args=args, kwargs={}, func=inradiusActual, support=inradiusSupport
)

if None in [min_width, max_width, min_length, max_length, min_height, max_height]:
# Can't get a bound on one or more dimensions, abort
return 0
@cached_property
def planarInradius(self):
"""A lower bound on the planar inradius of this object.

min_bounds = np.array([min_width, min_length, min_height])
max_bounds = np.array([max_width, max_length, max_height])
This is defined as the inradius of the polygon of the occupiedSpace
of this object projected into the XY plane, assuming that pitch and
roll are both 0.
"""

# Extract a list of possible shapes
if isinstance(shape, Shape):
shapes = [shape]
elif isinstance(shape, MultiplexerDistribution):
if all(isinstance(opt, Shape) for opt in shape.options):
shapes = shape.options
# Define a helper function that computes the actual planarInradius
def planarInradiusActual(width, length, shape):
return MeshVolumeRegion(
mesh=shape.mesh, dimensions=(width, length, 1)
).boundingPolygon.inradius

# Define a helper function that computes the support of the inradius,
# given the sub supports.
def planarInradiusSupport(width_s, length_s, shape_s):
# Unpack the dimension supports (and ignore the shape support)
min_width, max_width = width_s
min_length, max_length = length_s

if None in [min_width, max_width, min_length, max_length]:
# Can't get a bound on one or more dimensions, abort
return None, None

min_bounds = np.array([min_width, min_length, 1])
max_bounds = np.array([max_width, max_length, 1])

# Extract a list of possible shapes
if isinstance(self.shape, Shape):
shapes = [self.shape]
elif isinstance(self.shape, MultiplexerDistribution) and all(
isinstance(opt, Shape) for opt in self.shape.options
):
shapes = self.shape.options
else:
# Something we don't recognize, abort
return 0

# Check that all possible shapes contain the origin
if not all(shape.containsCenter for shape in shapes):
# One or more shapes has inradius 0
return 0
return None, None

# Get the inradius of the projected for each shape with the min and max bounds
min_distances = [
MeshVolumeRegion(
mesh=shape.mesh, dimensions=min_bounds
).boundingPolygon.inradius
for shape in shapes
]
max_distances = [
MeshVolumeRegion(
mesh=shape.mesh, dimensions=max_bounds
).boundingPolygon.inradius
for shape in shapes
]

# Get the inradius for each shape with the min and max bounds
min_distances = [
MeshVolumeRegion(mesh=shape.mesh, dimensions=min_bounds).inradius
for shape in shapes
]
max_distances = [
MeshVolumeRegion(mesh=shape.mesh, dimensions=max_bounds).inradius
for shape in shapes
]
distance_range = (min(min_distances), max(max_distances))

distance_range = (min(min_distances), max(max_distances))
return distance_range

return InradiusHelper(support=distance_range)
# Return either the inradius or a FunctionDistribution using the above helpers
args = toDistribution((self.width, self.length, self.shape))
if not isLazy(args):
return planarInradiusActual(*args)
else:
return FunctionDistribution(
args=args,
kwargs={},
func=planarInradiusActual,
support=planarInradiusSupport,
)

@cached_property
def surface(self):
Expand Down
Loading