Project Point Cloud to Plane
SUMMARY
Project Point Cloud to Plane orthogonally projects every point of a 3D point cloud onto a plane, flattening the cloud onto that surface.
Each point is moved to its closest point on the plane ax + by + cz + d = 0, defined by the coefficients [a, b, c, d] you supply ([a, b, c] is the plane normal and d is the signed distance from the origin — often obtained from a plane-fitting skill such as segment_point_cloud_using_plane). This is the same operation as project_point_cloud_to_plane_defined_by_point_normal, just parameterized differently — use this variant when you already have [a, b, c, d] coefficients rather than a point-and-normal pair.
Use this Skill when you want to flatten a 3D point cloud onto a known plane for ground-plane removal, planar feature extraction, or preparing data for 2D-style analysis.
The Skill
from telekinesis import vitreous
projected_point_cloud = vitreous.project_point_cloud_to_plane(
point_cloud=point_cloud,
plane_coefficients=[0.0, 0.0, 1.0, 0.0],
add_white_noise=False,
white_noise_standard_deviation=0.0,
)Data Transfer Notice
There is no longer a fixed limit of 1 million points per request. However, very large datasets may result in slower data transfer and processing times. We are continuously optimizing performance as part of our beta program, with ongoing improvements to enhance speed and reliability.
Example
Raw Pointcloud
Unprocessed point cloud. Plane for projection visualized in green.
Projected Pointcloud
Flattened pointcloud.
The Code
"""
Demonstrates projecting a point cloud orthogonally onto a plane.
"""
from loguru import logger
import rerun as rr
from telekinesis import vitreous, datatypes
def project_point_cloud_to_plane_example():
"""
Projects all points orthogonally onto a plane.
Moves each point to its closest point on the specified plane. Flattens
the cloud onto a 2D surface in 3D space.
"""
# ===================== Load Data ==========================================
point_cloud_url = (
"https://assets.telekinesis.ai/examples/v1/point_clouds/engine_parts_0.ply"
)
point_cloud = datatypes.PointCloud.from_url(url=point_cloud_url, use_cache=True)
# ===================== Run Skill ==========================================
projected_point_cloud = vitreous.project_point_cloud_to_plane(
add_white_noise=False,
white_noise_standard_deviation=1e-6,
point_cloud=point_cloud,
plane_coefficients=[0.0, 0.0, 1.0, 0.0],
)
# ===================== Log ================================================
logger.success(f"Projected {point_cloud} to plane")
logger.success(f"Results: {projected_point_cloud}")
logger.info(
f"Projected point cloud positions shape: {projected_point_cloud.positions.shape}"
)
logger.info(
f"Projected point cloud has normals shape: "
f"{projected_point_cloud.normals.shape if projected_point_cloud.has_normals else None}"
)
logger.info(
f"Projected point cloud has colors shape: "
f"{projected_point_cloud.colors.shape if projected_point_cloud.has_colors else None}"
)
# ===================== Visualization (Optional) ===========================
rr.init("project_point_cloud_to_plane_example", spawn=True)
datatypes.visualize(point_cloud, entity_path="/1-input_point_cloud")
datatypes.visualize(projected_point_cloud, entity_path="/2-filtered_point_cloud")
if __name__ == "__main__":
project_point_cloud_to_plane_example()Runnable examples are available in the Telekinesis examples repository.
Follow the README in that repository to set up the environment, run this specific example with:
cd telekinesis-examples
python examples/point_cloud/project_point_cloud_to_plane.pyParameter Configuration
These parameters are passed directly to the plane-projection service and control which plane the cloud is projected onto, and whether synthetic noise is added to the result.
| Key | Type | Default | Description |
|---|---|---|---|
point_cloud | datatypes.PointCloud | required | The point cloud to project |
plane_coefficients | datatypes.Vector4D | np.ndarray | list[float] | required | The plane equation coefficients [a, b, c, d] where ax + by + cz + d = 0. [a, b, c] is the plane normal (should be normalized) and d is the signed distance from the origin. Often obtained from a plane-fitting skill such as segment_point_cloud_using_plane |
add_white_noise | datatypes.Bool | bool | False | Whether to add random Gaussian noise to the projected points, e.g. to simulate measurement uncertainty when generating synthetic test data |
white_noise_standard_deviation | datatypes.Float | float | int | 0.0 | Standard deviation, in meters, of the Gaussian noise added when add_white_noise is True; ignored otherwise |
Returns
| Type | Description |
|---|---|
datatypes.PointCloud | A point cloud with every point moved onto the plane. Use .positions for the projected (N, 3) position array. |
Raises
| Exception | Condition |
|---|---|
TypeError | A parameter's value does not match its expected type (see the Parameter Configuration table above) |
ValueError | plane_coefficients does not have exactly 4 elements |
ConfigurationError | The TELEKINESIS_API_KEY environment variable is not set |
SerializationError | The request input failed to serialize, or the response failed to deserialize |
RequestTimeoutError | The request to the Vitreous service timed out |
TransportError | A network failure occurred before a response was received |
ClientError | The Vitreous service rejected the request due to invalid input, invalid data, or another unexpected 4xx response |
AuthenticationError | The API key was rejected as invalid or expired |
AuthenticationServiceError | The authentication service was unavailable |
ServerError | The Vitreous service returned a 5xx or otherwise unexpected error response |
How to Tune the Parameters
plane_coefficients
- Controls: Which plane, in the general form
ax + by + cz + d = 0, the point cloud is projected onto. - Units:
[a, b, c]dimensionless (unit normal);din meters - Default: required, no default
- Normalize
[a, b, c]to unit length before passing it in — an un-normalized normal still describes the same plane geometrically, butdthen loses its meaning as a distance in meters - Obtain these directly from a plane-fitting skill such as
segment_point_cloud_using_planerather than hand-deriving them
add_white_noise
- Controls: Whether Gaussian noise is added to the projected points after they are moved onto the plane.
- Units: Boolean
- Default:
False - Keep
Falsefor exact, deterministic projection - Set
Trueonly to synthesize noisy test data, e.g. to simulate sensor measurement uncertainty
white_noise_standard_deviation
- Controls: The spread of the Gaussian noise added when
add_white_noise=True. Ignored whenadd_white_noise=False. - Units: Meters
- Default:
0.0 - Increase → more variation around the projected plane position
- Decrease → projected points stay closer to the exact plane
- Typical range: 0.0–0.01 meters — use 0.001–0.005 for small variation, 0.005–0.01 for larger variation
TIP
Keep add_white_noise=False for exact projection; only enable noise for simulation/testing. If you don't already have plane coefficients, run segment_point_cloud_using_plane first to obtain them.
Where to Use the Skill
Common pipelines include:
- Ground plane removal – flattening a floor/table scan onto its best-fit plane before filtering out ground points
- Planar feature extraction – reducing a near-planar surface to a true 2D-in-3D representation for shape or area analysis
- Conveyor/inspection alignment – projecting scanned parts onto a known reference plane (e.g. a conveyor belt) before measurement
- Registration preparation – standardizing point clouds onto a common plane before running registration or segmentation
Alternative Skills
| Skill | vs. Project Point Cloud to Plane |
|---|---|
| project_point_cloud_to_plane_defined_by_point_normal | Projects onto the exact same kind of plane, just specified by a point + normal instead of [a, b, c, d] coefficients. Use whichever parameterization you already have on hand — the two are otherwise equivalent. |
When Not to Use the Skill
Do not use Project Point Cloud to Plane when:
- You have a point and normal vector instead of
[a, b, c, d]coefficients — useproject_point_cloud_to_plane_defined_by_point_normaldirectly rather than converting - You need to preserve full 3D structure — projection flattens the cloud onto the plane, discarding out-of-plane detail
- You need a non-orthogonal projection — this Skill only performs orthogonal (closest-point) projection
plane_coefficientsisn't normalized or well-formed — a non-unit[a, b, c]still defines a valid plane geometrically, butdwill no longer read as a distance in meters
TIP
If you don't have plane coefficients yet, run segment_point_cloud_using_plane first — its output can be fed directly into plane_coefficients here.

