Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions docs/api/newton.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ newton

* - Name
- Value
* - JOINT_LIMIT_UNLIMITED
- 10000000000.0
* - MAXVAL
- 1e10
* - __version__
- 0.2.0
4 changes: 2 additions & 2 deletions newton/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
# core
# ==================================================================================
from ._src.core import (
MAXVAL,
Axis,
AxisType,
)
from ._version import __version__

__all__ = [
"MAXVAL",
"Axis",
"AxisType",
"__version__",
Expand Down Expand Up @@ -53,7 +55,6 @@
# sim
# ==================================================================================
from ._src.sim import ( # noqa: E402
JOINT_LIMIT_UNLIMITED,
BroadPhaseMode,
CollisionPipeline,
CollisionPipelineUnified,
Expand All @@ -73,7 +74,6 @@
)

__all__ += [
"JOINT_LIMIT_UNLIMITED",
"BroadPhaseMode",
"CollisionPipeline",
"CollisionPipelineUnified",
Expand Down
2 changes: 2 additions & 0 deletions newton/_src/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@
velocity_at_point,
)
from .types import (
MAXVAL,
Axis,
AxisType,
)

__all__ = [
"MAXVAL",
"Axis",
"AxisType",
"quat_between_axes",
Expand Down
10 changes: 10 additions & 0 deletions newton/_src/core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ def flag_to_int(flag):
# Warp vector types
vec5 = wp.types.vector(length=5, dtype=wp.float32)

# Large finite value used as sentinel (matches MuJoCo's mjMAXVAL)
MAXVAL = 1e10
"""Large finite sentinel value for 'no limit' / 'no hit' / 'invalid' markers.

Use this instead of infinity to avoid verify_fp false positives.
For comparisons with volume-sampled data, use `>= wp.static(MAXVAL * 0.99)` to handle
interpolation-induced floating-point errors.
"""


class Axis(IntEnum):
"""Enumeration of axes in 3D space."""
Expand Down Expand Up @@ -181,6 +190,7 @@ def axis_to_vec3(axis: AxisType | Vec3) -> wp.vec3:


__all__ = [
"MAXVAL",
"Axis",
"AxisType",
"Devicelike",
Expand Down
24 changes: 13 additions & 11 deletions newton/_src/geometry/collision_primitive.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@

Returns (single contact): (distance: float, position: vec3, normal: vec3)
Returns (multi contact): (distances: vecN, positions: matNx3, normals: vecN or matNx3)
Use wp.inf for unpopulated contact slots.
Use MAXVAL for unpopulated contact slots.
"""

from typing import Any

import warp as wp

from newton._src.core.types import MAXVAL

# Local type definitions for use within kernels
_vec8f = wp.types.vector(8, wp.float32)
_mat23f = wp.types.matrix((2, 3), wp.float32)
Expand Down Expand Up @@ -221,11 +223,11 @@ def collide_capsule_capsule(

Returns:
Tuple containing:
contact_dist: Vector of contact distances (wp.inf for invalid contacts)
contact_dist: Vector of contact distances (MAXVAL for invalid contacts)
contact_pos: Matrix of contact positions (one per row)
contact_normal: Shared contact normal vector (from capsule 1 toward capsule 2)
"""
contact_dist = wp.vec2(wp.inf, wp.inf)
contact_dist = wp.vec2(MAXVAL, MAXVAL)
contact_pos = _mat23f()
contact_normal = wp.vec3()

Expand Down Expand Up @@ -400,15 +402,15 @@ def collide_plane_box(

Returns:
Tuple containing:
contact_dist: Vector of contact distances (wp.inf for unpopulated contacts)
contact_dist: Vector of contact distances (MAXVAL for unpopulated contacts)
contact_pos: Matrix of contact positions (one per row)
contact_normal: contact normal vector
"""

corner = wp.vec3()
center_dist = wp.dot(box_pos - plane_pos, plane_normal)

dist = wp.vec4(wp.inf)
dist = wp.vec4(MAXVAL)
pos = _mat43f()

# test all corners, pick bottom 4
Expand Down Expand Up @@ -540,7 +542,7 @@ def collide_plane_cylinder(
"""

# Initialize output matrices
contact_dist = wp.vec4(wp.inf)
contact_dist = wp.vec4(MAXVAL)
contact_pos = _mat43f()
contact_count = 0

Expand Down Expand Up @@ -668,15 +670,15 @@ def collide_box_box(

Returns:
Tuple containing:
contact_dist: Vector of contact distances (wp.inf for unpopulated contacts)
contact_dist: Vector of contact distances (MAXVAL for unpopulated contacts)
contact_pos: Matrix of contact positions (one per row)
contact_normals: Matrix of contact normal vectors (one per row)
"""

# Initialize output matrices
contact_dist = _vec8f()
for i in range(8):
contact_dist[i] = wp.inf
contact_dist[i] = MAXVAL
contact_pos = _mat83f()
contact_normals = _mat83f()
contact_count = 0
Expand Down Expand Up @@ -1182,7 +1184,7 @@ def collide_capsule_box(

Returns:
Tuple containing:
contact_dist: Vector of contact distances (wp.inf for unpopulated contacts)
contact_dist: Vector of contact distances (MAXVAL for unpopulated contacts)
contact_pos: Matrix of contact positions (one per row)
contact_normals: Matrix of contact normal vectors (one per row)
"""
Expand Down Expand Up @@ -1357,7 +1359,7 @@ def collide_capsule_box(
c1 = wp.where((ee2 > 0) == w_neg, 1, 2)

if cltype == -4: # invalid type
return wp.vec2(wp.inf), _mat23f(), _mat23f()
return wp.vec2(MAXVAL), _mat23f(), _mat23f()

if cltype >= 0 and cltype // 3 != 1: # closest to a corner of the box
c1 = axisdir ^ clcorner
Expand Down Expand Up @@ -1488,7 +1490,7 @@ def collide_capsule_box(
# collide with sphere using core function
dist2, pos2, normal2 = collide_sphere_box(s2_pos_g, capsule_radius, box_pos, box_rot, box_size)
else:
dist2 = wp.inf
dist2 = MAXVAL
pos2 = wp.vec3()
normal2 = wp.vec3()

Expand Down
6 changes: 4 additions & 2 deletions newton/_src/geometry/kernels.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

import warp as wp

from newton._src.core.types import MAXVAL

from . import collision_primitive as primitive
from .broad_phase_common import binary_search
from .flags import ParticleFlags, ShapeFlags
Expand Down Expand Up @@ -2112,8 +2114,8 @@ def handle_contact_pairs(
# Flip the normal since we flipped the arguments
normal = -neg_normal

# Check if this contact point is valid (primitive function returns wp.inf for invalid contacts)
if distance >= 1.0e5: # Use a reasonable threshold instead of exact wp.inf comparison
# Check if this contact point is valid (primitive function returns MAXVAL for invalid contacts)
if distance >= MAXVAL:
return

elif (
Expand Down
4 changes: 3 additions & 1 deletion newton/_src/geometry/narrow_phase.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import warp as wp

from newton._src.core.types import MAXVAL

from ..geometry.collision_core import (
ENABLE_TILE_BVH_QUERY,
check_infinite_plane_bsphere_overlap,
Expand Down Expand Up @@ -375,7 +377,7 @@ def narrow_phase_primitive_kernel(
contact_pos_0 = wp.vec3(positions[0, 0], positions[0, 1], positions[0, 2])

# Check if second contact is valid (parallel axes case)
if dists[1] < wp.inf:
if dists[1] < MAXVAL:
contact_dist_1 = dists[1]
contact_pos_1 = wp.vec3(positions[1, 0], positions[1, 1], positions[1, 2])
num_contacts = 2
Expand Down
8 changes: 5 additions & 3 deletions newton/_src/geometry/sdf_contact.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import warp as wp

from newton._src.core.types import MAXVAL

from ..geometry.contact_data import ContactData
from ..geometry.sdf_utils import SDFData

Expand Down Expand Up @@ -200,15 +202,15 @@ def sample_sdf_extrapolated(
sparse_idx = wp.volume_world_to_index(sdf_data.sparse_sdf_ptr, sdf_pos)
sparse_dist = wp.volume_sample_f(sdf_data.sparse_sdf_ptr, sparse_idx, wp.Volume.LINEAR)

if sparse_dist >= wp.inf or wp.isnan(sparse_dist):
if sparse_dist >= wp.static(MAXVAL * 0.99) or wp.isnan(sparse_dist):
# Fallback to coarse grid when sparse sample is diluted by background
coarse_idx = wp.volume_world_to_index(sdf_data.coarse_sdf_ptr, sdf_pos)
return wp.volume_sample_f(sdf_data.coarse_sdf_ptr, coarse_idx, wp.Volume.LINEAR)
else:
return sparse_dist
else:
# Point is outside extent - project to boundary
eps = 1e-2 * sdf_data.sparse_voxel_size # slightly shrink to avoid sampling NaN
eps = 1e-2 * sdf_data.sparse_voxel_size # slightly shrink to avoid sampling background
clamped_pos = wp.min(wp.max(sdf_pos, lower + eps), upper - eps)
dist_to_boundary = wp.length(sdf_pos - clamped_pos)

Expand Down Expand Up @@ -260,7 +262,7 @@ def sample_sdf_grad_extrapolated(
sparse_idx = wp.volume_world_to_index(sdf_data.sparse_sdf_ptr, sdf_pos)
sparse_dist = wp.volume_sample_grad_f(sdf_data.sparse_sdf_ptr, sparse_idx, wp.Volume.LINEAR, gradient)

if sparse_dist >= wp.inf or wp.isnan(sparse_dist):
if sparse_dist >= wp.static(MAXVAL * 0.99) or wp.isnan(sparse_dist):
# Fallback to coarse grid when sparse sample is diluted by background
coarse_idx = wp.volume_world_to_index(sdf_data.coarse_sdf_ptr, sdf_pos)
coarse_dist = wp.volume_sample_grad_f(sdf_data.coarse_sdf_ptr, coarse_idx, wp.Volume.LINEAR, gradient)
Expand Down
10 changes: 8 additions & 2 deletions newton/_src/geometry/sdf_hydroelastic.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import warp as wp

from newton._src.core.types import MAXVAL

from ..sim.model import Model
from .collision_core import sat_box_intersection
from .contact_data import ContactData
Expand Down Expand Up @@ -963,7 +965,9 @@ def sdf_diff_sdf(

valB = sample_sdf_extrapolated(sdfB_data, pointB)

is_valid = not (valA >= wp.inf or wp.isnan(valA) or valB >= wp.inf or wp.isnan(valB))
is_valid = not (
valA >= wp.static(MAXVAL * 0.99) or wp.isnan(valA) or valB >= wp.static(MAXVAL * 0.99) or wp.isnan(valB)
)

if valA < 0 and valB < 0:
diff = k_eff_a * valA - k_eff_b * valB
Expand Down Expand Up @@ -995,7 +999,9 @@ def sdf_diff_sdf(

valB = sample_sdf_extrapolated(sdfB_data, pointB)

is_valid = not (valA >= wp.inf or wp.isnan(valA) or valB >= wp.inf or wp.isnan(valB))
is_valid = not (
valA >= wp.static(MAXVAL * 0.99) or wp.isnan(valA) or valB >= wp.static(MAXVAL * 0.99) or wp.isnan(valB)
)

if valA < 0 and valB < 0:
diff = k_eff_a * valA - k_eff_b * valB
Expand Down
4 changes: 3 additions & 1 deletion newton/_src/geometry/sdf_mc.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import numpy as np
import warp as wp

from newton._src.core.types import MAXVAL

#: Corner values for a single voxel (8 corners)
vec8f = wp.types.vector(length=8, dtype=wp.float32)

Expand Down Expand Up @@ -183,7 +185,7 @@ def mc_calc_face(
p_scaled = wp.volume_index_to_world(sdf_a, vol_idx)
face_verts[vi] = p_scaled
depth = wp.volume_sample_f(sdf_a, vol_idx, wp.Volume.LINEAR)
if depth >= wp.inf or wp.isnan(depth):
if depth >= wp.static(MAXVAL * 0.99) or wp.isnan(depth):
depth = 0.0
vert_depths[vi] = -depth
if depth < 0.0:
Expand Down
7 changes: 4 additions & 3 deletions newton/_src/geometry/sdf_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import numpy as np
import warp as wp

from ..core.types import MAXVAL
from ..geometry.kernels import box_sdf, capsule_sdf, cone_sdf, cylinder_sdf, ellipsoid_sdf, sphere_sdf
from .sdf_mc import get_mc_tables, int_to_vec3f, mc_calc_face, vec8f
from .types import GeoType, Mesh
Expand Down Expand Up @@ -52,9 +53,9 @@ class SDFData:


# Default background value for unallocated voxels in sparse SDF.
# Using inf ensures any trilinear interpolation with unallocated voxels produces inf or NaN,
# allowing detection of unallocated voxels.
SDF_BACKGROUND_VALUE = wp.inf
# Using a large finite value ensures any trilinear interpolation with unallocated voxels
# produces a large value, allowing detection of unallocated voxels.
SDF_BACKGROUND_VALUE = MAXVAL


def create_empty_sdf_data() -> SDFData:
Expand Down
5 changes: 3 additions & 2 deletions newton/_src/sensors/sensor_tiled_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import numpy as np
import warp as wp

from ..core.types import MAXVAL
from ..geometry import ShapeFlags
from ..sim import Model, State
from .warp_raytrace import ClearData, RenderContext, RenderLightType, RenderShapeType
Expand Down Expand Up @@ -52,8 +53,8 @@ def convert_newton_transform(
def compute_mesh_bounds(in_meshes: wp.array(dtype=wp.uint64), out_bounds: wp.array2d(dtype=wp.vec3f)):
tid = wp.tid()

min_point = wp.vec3(wp.inf)
max_point = wp.vec3(-wp.inf)
min_point = wp.vec3(MAXVAL)
max_point = wp.vec3(-MAXVAL)

if in_meshes[tid] != 0:
mesh = wp.mesh_get(in_meshes[tid])
Expand Down
14 changes: 8 additions & 6 deletions newton/_src/sensors/warp_raytrace/bvh.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

import warp as wp

from newton._src.core.types import MAXVAL

from .types import RenderShapeType


Expand All @@ -25,8 +27,8 @@ def compute_mesh_bounds(
mesh_min_bounds = wp.cw_mul(mesh_min_bounds, scale)
mesh_max_bounds = wp.cw_mul(mesh_max_bounds, scale)

min_bound = wp.vec3f(wp.inf)
max_bound = wp.vec3f(-wp.inf)
min_bound = wp.vec3f(MAXVAL)
max_bound = wp.vec3f(-MAXVAL)

corner_1 = wp.transform_point(transform, wp.vec3f(mesh_min_bounds[0], mesh_min_bounds[1], mesh_min_bounds[2]))
min_bound = wp.min(min_bound, corner_1)
Expand Down Expand Up @@ -65,8 +67,8 @@ def compute_mesh_bounds(

@wp.func
def compute_box_bounds(transform: wp.transformf, size: wp.vec3f) -> tuple[wp.vec3f, wp.vec3f]:
min_bound = wp.vec3f(wp.inf)
max_bound = wp.vec3f(-wp.inf)
min_bound = wp.vec3f(MAXVAL)
max_bound = wp.vec3f(-MAXVAL)

for x in range(2):
for y in range(2):
Expand Down Expand Up @@ -117,8 +119,8 @@ def compute_plane_bounds(transform: wp.transformf, size: wp.vec3f) -> tuple[wp.v
if size[0] <= 0.0 or size[1] <= 0.0:
size_scale = 1000.0

min_bound = wp.vec3f(wp.inf)
max_bound = wp.vec3f(-wp.inf)
min_bound = wp.vec3f(MAXVAL)
max_bound = wp.vec3f(-MAXVAL)

for x in range(2):
for y in range(2):
Expand Down
Loading
Loading