-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16 from cemsbv/15-add-method-to-project-point3d-o…
…nto-polygon3d Add method to project point3d onto polygon3d.
- Loading branch information
Showing
7 changed files
with
156 additions
and
16 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
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,67 @@ | ||
from __future__ import annotations | ||
|
||
import numpy as np | ||
from skspatial.objects import Plane as ScikitSpatialPlane | ||
|
||
from plxcontroller.geometry_3d.point_3d import Point3D | ||
from plxcontroller.geometry_3d.polygon_3d import Polygon3D | ||
|
||
|
||
def project_vertically_point_onto_polygon_3d( | ||
point: Point3D, polygon: Polygon3D | ||
) -> Point3D | None: | ||
"""Returns the vertical projection of the Point3D onto Polygon3D. | ||
If the point is not within the boundaries of the projection of the polygon | ||
in the xy plane, then None is returned. | ||
Parameters | ||
---------- | ||
point : Point3D | ||
the point to project. | ||
polygon : Polygon3D | ||
the polygon to project onto. | ||
Raises | ||
------ | ||
TypeError | ||
if any parameter is not of the expected type. | ||
Returns | ||
------- | ||
Point3D | None | ||
the projected point onto the polygon. | ||
""" | ||
# Validate input | ||
if not isinstance(point, Point3D): | ||
raise TypeError( | ||
f"Unexpected type for point. Expected Point3D, but got {type(point)}." | ||
) | ||
|
||
if not isinstance(polygon, Polygon3D): | ||
raise TypeError( | ||
f"Unexpected type for polygon. Expected Polygon3D, but got {type(point)}." | ||
) | ||
|
||
# Check whether the point is inside the projection of the polygon in the xy plane | ||
if not polygon.shapely_polygon_xy_plane.contains(point.shapely_point_xy_plane): | ||
return None | ||
|
||
# Make plane using first three points of the polygon. | ||
# Note that all points in Polygon3D are coplanar, so it does not matter which | ||
# poitns are taken. | ||
plane = ScikitSpatialPlane.from_points( | ||
*[coord for coord in polygon.coordinates[:3]] | ||
) | ||
|
||
# Calculate the z-coordinate using the equation of the plane with the | ||
# point x and y coordinates input | ||
a, b, c, d = plane.cartesian() | ||
if not np.isclose(c, 0.0): | ||
z = (d - a * point.x - b * point.y) / c | ||
else: | ||
# if the coefficient c is close to zero, it means that | ||
# the plane is parallel to the z-axis, so the z-coordinate | ||
# is the same as the point itself. | ||
z = point.z | ||
|
||
return Point3D(x=point.x, y=point.y, z=z) |
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,47 @@ | ||
import pytest | ||
|
||
from plxcontroller.geometry_3d.operations_3d import ( | ||
project_vertically_point_onto_polygon_3d, | ||
) | ||
from plxcontroller.geometry_3d.point_3d import Point3D | ||
from plxcontroller.geometry_3d.polygon_3d import Polygon3D | ||
|
||
|
||
def test_project_vertically_point_onto_polygon_3d() -> None: | ||
""" | ||
Tests the method project_vertically_point_onto_polygon_3d. | ||
""" | ||
|
||
# Assert invalid input (types) | ||
with pytest.raises(TypeError, match="Expected Point3D"): | ||
project_vertically_point_onto_polygon_3d( | ||
point="invalid input", | ||
polygon=Polygon3D(coordinates=[(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0)]), | ||
) | ||
|
||
with pytest.raises(TypeError, match="Expected Polygon3D"): | ||
project_vertically_point_onto_polygon_3d( | ||
point=Point3D(x=0.5, y=0.5, z=5.0), | ||
polygon="invalid input", | ||
) | ||
|
||
# Assert it returns None if projection falls out the boundaries of the polygon | ||
assert ( | ||
project_vertically_point_onto_polygon_3d( | ||
point=Point3D(x=-0.5, y=-0.5, z=5.0), | ||
polygon=Polygon3D(coordinates=[(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0)]), | ||
) | ||
is None | ||
) | ||
|
||
# Assert it returns the expected point (polygon3d parallel to xy plane) | ||
assert project_vertically_point_onto_polygon_3d( | ||
point=Point3D(x=0.5, y=0.5, z=5.0), | ||
polygon=Polygon3D(coordinates=[(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0)]), | ||
).coordinates == (0.5, 0.5, 0) | ||
|
||
# Assert it returns the expected point (inclined polygon3d) | ||
assert project_vertically_point_onto_polygon_3d( | ||
point=Point3D(x=0.5, y=0.5, z=5.0), | ||
polygon=Polygon3D(coordinates=[(0, 0, 0), (1, 0, 1), (1, 1, 1), (0, 1, 0)]), | ||
).coordinates == (0.5, 0.5, 0.5) |