From 48deb5b51d5729e34c98fb86f03807cb47b71af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Br=C3=A9mond?= Date: Sun, 23 Jun 2019 23:02:29 -0700 Subject: [PATCH 1/2] [misc] Update Python bindings --- bindings/python/docs/Reference/Geometry.ipynb | 2 +- .../Geometry/2D/Objects/Polygon.ipynb | 162 ++++++++++++++++++ .../Geometry/2D/Objects/Point.cpp | 3 + tools/python/.env | 16 ++ tools/python/docker/Dockerfile | 12 +- tools/python/start.sh | 128 +++++++------- tutorials/python/notebooks/Polygon.ipynb | 62 +++++++ 7 files changed, 320 insertions(+), 65 deletions(-) create mode 100644 bindings/python/docs/Reference/Geometry/2D/Objects/Polygon.ipynb create mode 100644 tools/python/.env create mode 100644 tutorials/python/notebooks/Polygon.ipynb diff --git a/bindings/python/docs/Reference/Geometry.ipynb b/bindings/python/docs/Reference/Geometry.ipynb index f21c50f7..17efb36b 100644 --- a/bindings/python/docs/Reference/Geometry.ipynb +++ b/bindings/python/docs/Reference/Geometry.ipynb @@ -1888,7 +1888,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.7" + "version": "3.6.8" } }, "nbformat": 4, diff --git a/bindings/python/docs/Reference/Geometry/2D/Objects/Polygon.ipynb b/bindings/python/docs/Reference/Geometry/2D/Objects/Polygon.ipynb new file mode 100644 index 00000000..ea007ef0 --- /dev/null +++ b/bindings/python/docs/Reference/Geometry/2D/Objects/Polygon.ipynb @@ -0,0 +1,162 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Library ▸ Mathematics ▸ Geometry ▸ 2D ▸ Objects ▸ Polygon" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import Library.Mathematics as Mathematics" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "Point = Mathematics.Geometry.D2.Objects.Point\n", + "PointSet = Mathematics.Geometry.D2.Objects.PointSet\n", + "Polygon = Mathematics.Geometry.D2.Objects.Polygon\n", + "Transformation = Mathematics.Geometry.D2.Transformation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Polygon" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Constructors**" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "polygon = Polygon([Point(0.0, 0.0), Point(1.0, 0.0), Point(1.0, 1.0), Point(0.0, 1.0)])" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "polygon = Polygon([Point(0.0, 0.0), Point(1.0, 0.0), Point(1.0, 1.0), Point(0.0, 1.0)], [[Point(0.5, 0.5), Point(0.5, 0.6), Point(0.6, 0.5)]])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "Polygon.Undefined() ;" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Operators**" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "polygon == polygon ;\n", + "polygon != polygon ;" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Methods**" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "polygon.isDefined() ;\n", + "polygon.intersectsPolygon(polygon) ;\n", + "polygon.containsPoint(Point(0.0, 0.0)) ;\n", + "polygon.containsPointSet(PointSet([Point(0.0, 0.0)])) ;\n", + "polygon.getInnerRingCount() ;\n", + "polygon.getEdgeCount() ;\n", + "polygon.getVertexCount() ;\n", + "polygon.getOuterRing() ;\n", + "polygon.getInnerRingAt(0) ;\n", + "polygon.getEdgeAt(0) ;\n", + "polygon.getVertexAt(0) ;\n", + "# polygon.getEdges() ;\n", + "polygon.getVertices() ;\n", + "polygon.toString() ;\n", + "polygon.applyTransformation(Transformation.Identity()) ;" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.8" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/bindings/python/src/LibraryMathematicsPy/Geometry/2D/Objects/Point.cpp b/bindings/python/src/LibraryMathematicsPy/Geometry/2D/Objects/Point.cpp index 6ad99fdc..c0b49730 100755 --- a/bindings/python/src/LibraryMathematicsPy/Geometry/2D/Objects/Point.cpp +++ b/bindings/python/src/LibraryMathematicsPy/Geometry/2D/Objects/Point.cpp @@ -65,6 +65,9 @@ inline void LibraryMathematicsPy_Geometry_2D_Objects_Point ( .from_python>() .to_python>() + + .from_python>>() + .to_python>>() ; diff --git a/tools/python/.env b/tools/python/.env new file mode 100644 index 00000000..7bbac115 --- /dev/null +++ b/tools/python/.env @@ -0,0 +1,16 @@ +################################################################################################################################################################ + +# @project Library/Mathematics +# @file tools/python/.env +# @author Lucas Brémond +# @license Apache License 2.0 + +################################################################################################################################################################ + +JUPYTER_ENABLE_LAB=yes +# GRANT_SUDO=yes + +LD_LIBRARY_PATH=/usr/local/lib:/opt/conda/lib/python3.6/site-packages:/home/jovyan/lib +PYTHONPATH=/opt/conda/lib/python3.6/site-packages:/home/jovyan/lib + +################################################################################################################################################################ \ No newline at end of file diff --git a/tools/python/docker/Dockerfile b/tools/python/docker/Dockerfile index 798dd946..afcc329d 100644 --- a/tools/python/docker/Dockerfile +++ b/tools/python/docker/Dockerfile @@ -13,15 +13,23 @@ LABEL maintainer="lucas@loftorbital.com" USER root +RUN apt-get update \ + && apt-get install -y libssl1.0.0 libssl-dev \ + && rm -rf /var/lib/apt/lists/* + +COPY ./shortcuts-extension /home/jovyan/.jupyter/lab/user-settings/@jupyterlab/shortcuts-extension + RUN jupyter labextension install @jupyterlab/plotly-extension RUN python -m pip install --quiet numpy --upgrade \ && python -m pip install --quiet plotly -COPY ./shortcuts-extension /home/jovyan/.jupyter/lab/user-settings/@jupyterlab/shortcuts-extension - RUN chown -R ${NB_UID}:${NB_UID} /home/jovyan/.jupyter USER ${NB_UID} +RUN pip install LibraryMathematicsPy + +RUN mkdir -p /home/jovyan/.library + ################################################################################################################################################################ \ No newline at end of file diff --git a/tools/python/start.sh b/tools/python/start.sh index 187b44ad..ff34af92 100755 --- a/tools/python/start.sh +++ b/tools/python/start.sh @@ -13,7 +13,7 @@ script_directory="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" pushd "${script_directory}" > /dev/null -source ../.env +source "../.env" # Build Docker image if it does not exist already @@ -27,72 +27,76 @@ if [[ "$(docker images -q ${image_name}-python:${image_version} 2> /dev/null)" = fi +options="" +command="start-notebook.sh --NotebookApp.token=''" + if [[ ! -z $1 ]] && [[ $1 == "--link" ]]; then - docker run \ - --name="${container_name}-notebook" \ - -it \ - --rm \ - --publish="${python_port}:8888" \ - --user="" \ - --env="JUPYTER_ENABLE_LAB=yes" \ - --env="LD_LIBRARY_PATH=/usr/local/lib:/opt/conda/lib/python3.6/site-packages:/home/jovyan/lib" \ - --env="PYTHONPATH=/opt/conda/lib/python3.6/site-packages:/home/jovyan/lib" \ - --volume="${library_core_directory}/lib:/opt/library-core:ro" \ - --volume="${project_directory}/lib:/opt/lib:ro" \ - --volume="${project_directory}/bindings/python/docs:/home/jovyan/docs" \ - --volume="${project_directory}/tutorials/python/notebooks:/home/jovyan/tutorials" \ - --volume="${project_directory}/share/data:/app/share/data" \ - --workdir="/home/jovyan" \ - "${image_name}-python:${image_version}" \ - bash -c "mkdir -p /opt/conda/lib/python3.6/site-packages/Library/Core \ - && ln -s /opt/library-core/liblibrary-core.so.0 /opt/conda/lib/python3.6/site-packages/Library/Core/liblibrary-core.so.0 \ - && ln -s /opt/library-core/LibraryCorePy.so /opt/conda/lib/python3.6/site-packages/Library/Core/LibraryCorePy.so \ - && echo 'from .LibraryCorePy import *' > /opt/conda/lib/python3.6/site-packages/Library/Core/__init__.py \ - && mkdir -p /opt/conda/lib/python3.6/site-packages/Library/Mathematics \ - && ln -s /opt/lib/liblibrary-mathematics.so.0 /opt/conda/lib/python3.6/site-packages/Library/Mathematics/liblibrary-mathematics.so.0 \ - && ln -s /opt/lib/LibraryMathematicsPy.so /opt/conda/lib/python3.6/site-packages/Library/Mathematics/LibraryMathematicsPy.so \ - && echo 'from .LibraryMathematicsPy import *' > /opt/conda/lib/python3.6/site-packages/Library/Mathematics/__init__.py \ - && start-notebook.sh --NotebookApp.token=''" - - # docker run \ - # --name="${container_name}-notebook" \ - # -it \ - # --rm \ - # --publish="${python_port}:8888" \ - # --user="" \ - # --env="JUPYTER_ENABLE_LAB=yes" \ - # --env="LD_LIBRARY_PATH=/usr/local/lib:/opt/conda/lib/python3.6/site-packages:/home/jovyan/lib" \ - # --env="PYTHONPATH=/opt/conda/lib/python3.6/site-packages:/home/jovyan/lib" \ - # --volume="${library_core_directory}/lib:/opt/library-core:ro" \ - # --volume="${project_directory}/lib:/opt/lib:ro" \ - # --volume="${project_directory}/bindings/python/docs:/home/jovyan/docs" \ - # --volume="${project_directory}/tutorials/python/notebooks:/home/jovyan/tutorials" \ - # --volume="${project_directory}/share/data:/app/share/data" \ - # --workdir="/home/jovyan" \ - # "${image_name}-python:${image_version}" \ - # bash -c "mkdir -p /opt/conda/lib/python3.6/site-packages/Library/Mathematics \ - # && ln -s /opt/lib/liblibrary-mathematics.so.0 /opt/conda/lib/python3.6/site-packages/Library/Mathematics/liblibrary-mathematics.so.0 \ - # && ln -s /opt/lib/LibraryMathematicsPy.so /opt/conda/lib/python3.6/site-packages/Library/Mathematics/LibraryMathematicsPy.so \ - # && echo 'from .LibraryMathematicsPy import *' > /opt/conda/lib/python3.6/site-packages/Library/Mathematics/__init__.py \ - # && start-notebook.sh --NotebookApp.token=''" - -else - - docker run \ - --name="${container_name}-notebook" \ - -it \ - --rm \ - --publish="${python_port}:8888" \ - --env="JUPYTER_ENABLE_LAB=yes" \ - --volume="${project_directory}/bindings/python/docs:/home/jovyan/docs" \ - --volume="${project_directory}/tutorials/python/notebooks:/home/jovyan/tutorials" \ - --workdir="/home/jovyan" \ - "${image_name}-python:${image_version}" \ - start-notebook.sh --NotebookApp.token='' + command="" + + # # Library ▸ Core + + # options="${options} \ + # --volume=${library_core_directory}:/opt/library-core:ro" + + # command="${command} \ + # mkdir -p /opt/conda/lib/python3.6/site-packages/Library/Core; \ + # rm -rf /opt/conda/lib/python3.6/site-packages/Library/Core/liblibrary-core.so.0; \ + # rm -rf /opt/conda/lib/python3.6/site-packages/Library/Core/LibraryCorePy.so; \ + # rm -rf /opt/conda/lib/python3.6/site-packages/Library/Core/__init__.py; \ + # ln -s /opt/library-core/lib/liblibrary-core.so.0 /opt/conda/lib/python3.6/site-packages/Library/Core/liblibrary-core.so.0; \ + # ln -s /opt/library-core/lib/LibraryCorePy.so /opt/conda/lib/python3.6/site-packages/Library/Core/LibraryCorePy.so; \ + # ln -s /opt/library-core/bindings/python/tools/python/Library/Core/__init__.py /opt/conda/lib/python3.6/site-packages/Library/Core/__init__.py;" + + # # Library ▸ I/O + + # options="${options} \ + # --volume=${library_io_directory}:/opt/library-io:ro" + + # command="${command} \ + # mkdir -p /opt/conda/lib/python3.6/site-packages/Library/IO; \ + # rm -rf /opt/conda/lib/python3.6/site-packages/Library/IO/liblibrary-io.so.0; \ + # rm -rf /opt/conda/lib/python3.6/site-packages/Library/IO/LibraryIOPy.so; \ + # rm -rf /opt/conda/lib/python3.6/site-packages/Library/IO/__init__.py; \ + # ln -s /opt/library-io/lib/liblibrary-io.so.0 /opt/conda/lib/python3.6/site-packages/Library/IO/liblibrary-io.so.0; \ + # ln -s /opt/library-io/lib/LibraryIOPy.so /opt/conda/lib/python3.6/site-packages/Library/IO/LibraryIOPy.so; \ + # ln -s /opt/library-io/bindings/python/tools/python/Library/IO/__init__.py /opt/conda/lib/python3.6/site-packages/Library/IO/__init__.py;" + + # Library ▸ Mathematics + + options="${options} \ + --volume=${project_directory}:/opt/library-mathematics:ro" + + command="${command} \ + mkdir -p /opt/conda/lib/python3.6/site-packages/Library/Mathematics; \ + rm -rf /opt/conda/lib/python3.6/site-packages/Library/Mathematics/liblibrary-mathematics.so.0; \ + rm -rf /opt/conda/lib/python3.6/site-packages/Library/Mathematics/LibraryMathematicsPy.so; \ + rm -rf /opt/conda/lib/python3.6/site-packages/Library/Mathematics/__init__.py; \ + ln -s /opt/library-mathematics/lib/liblibrary-mathematics.so.0 /opt/conda/lib/python3.6/site-packages/Library/Mathematics/liblibrary-mathematics.so.0; \ + ln -s /opt/library-mathematics/lib/LibraryMathematicsPy.so /opt/conda/lib/python3.6/site-packages/Library/Mathematics/LibraryMathematicsPy.so; \ + ln -s /opt/library-mathematics/bindings/python/tools/python/Library/Mathematics/__init__.py /opt/conda/lib/python3.6/site-packages/Library/Mathematics/__init__.py;" + + command="${command} \ + start-notebook.sh --NotebookApp.token=''" fi +# Run Docker container + +docker run \ +--name="${container_name}-notebook" \ +-it \ +--rm \ +--publish="${python_port}:8888" \ +--env-file="${script_directory}/.env" \ +--volume="${project_directory}/bindings/python/docs:/home/jovyan/docs" \ +--volume="${project_directory}/tutorials/python/notebooks:/home/jovyan/tutorials" \ +--volume="${project_directory}/share:/home/jovyan/.library/mathematics" \ +--workdir="/home/jovyan" \ +${options} \ +"${image_name}-python:${image_version}" \ +/bin/bash -c "${command}" + popd > /dev/null ################################################################################################################################################################ \ No newline at end of file diff --git a/tutorials/python/notebooks/Polygon.ipynb b/tutorials/python/notebooks/Polygon.ipynb new file mode 100644 index 00000000..d9b2195d --- /dev/null +++ b/tutorials/python/notebooks/Polygon.ipynb @@ -0,0 +1,62 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import Library.Mathematics as Mathematics" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "Point = Mathematics.Geometry.D2.Objects.Point\n", + "PointSet = Mathematics.Geometry.D2.Objects.PointSet\n", + "Polygon = Mathematics.Geometry.D2.Objects.Polygon\n", + "Transformation = Mathematics.Geometry.D2.Transformation" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "polygon = Polygon([Point(0.0, 0.0), Point(1.0, 0.0), Point(1.0, 1.0), Point(0.0, 1.0)], [[Point(0.5, 0.5), Point(0.5, 0.6), Point(0.6, 0.5)]])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.8" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 167e98988f358372cac054b6bed98874a3931874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Br=C3=A9mond?= Date: Wed, 17 Jul 2019 16:11:02 -0700 Subject: [PATCH 2/2] [feature] Add Pyramid::contains(Point) and Ray::intersectionWith(Plane) --- .../Geometry/3D/Intersection.cpp | 13 +- .../Geometry/3D/Objects/Pyramid.cpp | 1 + .../Geometry/3D/Objects/Ray.cpp | 2 + .../Mathematics/Geometry/3D/Intersection.hpp | 30 +++++ .../Geometry/3D/Objects/Pyramid.hpp | 13 ++ .../Mathematics/Geometry/3D/Objects/Ray.hpp | 7 ++ .../Mathematics/Geometry/3D/Intersection.cpp | 39 ++++++ .../Geometry/3D/Objects/Pyramid.cpp | 66 +++++++++++ .../Mathematics/Geometry/3D/Objects/Ray.cpp | 46 ++++++- .../Geometry/3D/Objects/Pyramid.test.cpp | 112 ++++++++++++++++++ .../Geometry/3D/Objects/Ray.test.cpp | 20 ++++ 11 files changed, 343 insertions(+), 6 deletions(-) diff --git a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Intersection.cpp b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Intersection.cpp index 7261e7c8..cba61fae 100755 --- a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Intersection.cpp +++ b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Intersection.cpp @@ -80,18 +80,21 @@ inline void LibraryMathematicsPy_Geometry_3D_Intersection ( .def("accessComposite", &Intersection::accessComposite, return_value_policy()) .def("getType", &Intersection::getType) - + .def("Undefined", &Intersection::Undefined).staticmethod("Undefined") .def("Empty", &Intersection::Empty).staticmethod("Empty") .def("Point", &Intersection::Point).staticmethod("Point") .def("PointSet", &Intersection::PointSet).staticmethod("PointSet") - + .def("Line", &Intersection::Line).staticmethod("Line") + .def("Ray", &Intersection::Ray).staticmethod("Ray") + .def("Segment", &Intersection::Segment).staticmethod("Segment") + .def("StringFromType", &Intersection::StringFromType).staticmethod("StringFromType") ; enum_("Type") - + .value("Undefined", Intersection::Type::Undefined) .value("Empty", Intersection::Type::Empty) .value("Point", Intersection::Type::Point) @@ -103,9 +106,9 @@ inline void LibraryMathematicsPy_Geometry_3D_Intersection ( .value("Sphere", Intersection::Type::Sphere) .value("Ellipsoid", Intersection::Type::Ellipsoid) .value("Complex", Intersection::Type::Complex) - + ; } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Pyramid.cpp b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Pyramid.cpp index f1387800..5343c26e 100755 --- a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Pyramid.cpp +++ b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Pyramid.cpp @@ -45,6 +45,7 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Pyramid .def("isDefined", &Pyramid::isDefined) .def("intersectsEllipsoid", +[] (const Pyramid& aPyramid, const Ellipsoid& anEllipsoid) -> bool { return aPyramid.intersects(anEllipsoid) ; }) .def("intersectsEllipsoid", +[] (const Pyramid& aPyramid, const Ellipsoid& anEllipsoid, const Size aDiscretizationLevel) -> bool { return aPyramid.intersects(anEllipsoid, aDiscretizationLevel) ; }) + .def("containsPoint", +[] (const Pyramid& aPyramid, const Point& aPoint) -> bool { return aPyramid.contains(aPoint) ; }) .def("containsEllipsoid", +[] (const Pyramid& aPyramid, const Ellipsoid& anEllipsoid) -> bool { return aPyramid.contains(anEllipsoid) ; }) .def("getBase", &Pyramid::getBase) diff --git a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Ray.cpp b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Ray.cpp index b4ce0276..d0a652f4 100755 --- a/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Ray.cpp +++ b/bindings/python/src/LibraryMathematicsPy/Geometry/3D/Objects/Ray.cpp @@ -20,6 +20,7 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Ray ( ) using library::math::geom::d3::Object ; using library::math::geom::d3::objects::Point ; using library::math::geom::d3::objects::Ray ; + using library::math::geom::d3::objects::Plane ; using library::math::geom::d3::objects::Sphere ; using library::math::geom::d3::objects::Ellipsoid ; using library::math::geom::d3::Intersection ; @@ -40,6 +41,7 @@ inline void LibraryMathematicsPy_Geometry_3D_Objects_Ray ( ) .def("getOrigin", &Ray::getOrigin) .def("getDirection", &Ray::getDirection) + .def("intersectionWithPlane", +[] (const Ray& aRay, const Plane& aPlane) -> Intersection { return aRay.intersectionWith(aPlane) ; }) .def("intersectionWithEllipsoid", +[] (const Ray& aRay, const Ellipsoid& anEllipsoid) -> Intersection { return aRay.intersectionWith(anEllipsoid) ; }) .def("applyTransformation", &Ray::applyTransformation) diff --git a/include/Library/Mathematics/Geometry/3D/Intersection.hpp b/include/Library/Mathematics/Geometry/3D/Intersection.hpp index 17fe057e..6e1877de 100755 --- a/include/Library/Mathematics/Geometry/3D/Intersection.hpp +++ b/include/Library/Mathematics/Geometry/3D/Intersection.hpp @@ -272,6 +272,36 @@ class Intersection static Intersection LineString ( const objects::LineString& aLineString ) ; + /// @brief Constructs a line intersection + /// + /// @code + /// Intersection intersection = Intersection::Line(Line({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 })) ; + /// @endcode + /// + /// @return Line intersection + + static Intersection Line ( const objects::Line& aLine ) ; + + /// @brief Constructs a ray intersection + /// + /// @code + /// Intersection intersection = Intersection::Ray(Ray({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 })) ; + /// @endcode + /// + /// @return Ray intersection + + static Intersection Ray ( const objects::Ray& aRay ) ; + + /// @brief Constructs a segment intersection + /// + /// @code + /// Intersection intersection = Intersection::Segment(Segment({ 0.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 })) ; + /// @endcode + /// + /// @return Segment intersection + + static Intersection Segment ( const objects::Segment& aSegment ) ; + /// @brief Converts intersection type to string /// /// @return String diff --git a/include/Library/Mathematics/Geometry/3D/Objects/Pyramid.hpp b/include/Library/Mathematics/Geometry/3D/Objects/Pyramid.hpp index 7230e72f..4aeb290c 100755 --- a/include/Library/Mathematics/Geometry/3D/Objects/Pyramid.hpp +++ b/include/Library/Mathematics/Geometry/3D/Objects/Pyramid.hpp @@ -138,6 +138,19 @@ class Pyramid : public Object bool intersects ( const Ellipsoid& anEllipsoid, const Size aDiscretizationLevel = 40 ) const ; + /// @brief Check if pyramid contains point + /// + /// @code + /// Pyramid pyramid = ... ; + /// Point point = ... ; + /// pyramid.contains(point) ; + /// @endcode + /// + /// @param [in] aPoint A point + /// @return True if pyramid contains point + + bool contains ( const Point& aPoint ) const ; + /// @brief Check if pyramid contains ellipsoid /// /// @code diff --git a/include/Library/Mathematics/Geometry/3D/Objects/Ray.hpp b/include/Library/Mathematics/Geometry/3D/Objects/Ray.hpp index 1e29a129..37da50e6 100755 --- a/include/Library/Mathematics/Geometry/3D/Objects/Ray.hpp +++ b/include/Library/Mathematics/Geometry/3D/Objects/Ray.hpp @@ -179,6 +179,13 @@ class Ray : public Object Vector3d getDirection ( ) const ; + /// @brief Compute intersection of ray with plane + /// + /// @param [in] aPlane A plane + /// @return Intersection of ray with plane + + Intersection intersectionWith ( const Plane& aPlane ) const ; + /// @brief Compute intersection of ray with sphere /// /// @param [in] aSphere A sphere diff --git a/src/Library/Mathematics/Geometry/3D/Intersection.cpp b/src/Library/Mathematics/Geometry/3D/Intersection.cpp index 505879f7..94c71396 100644 --- a/src/Library/Mathematics/Geometry/3D/Intersection.cpp +++ b/src/Library/Mathematics/Geometry/3D/Intersection.cpp @@ -222,6 +222,45 @@ Intersection Intersection::LineString ( } +Intersection Intersection::Line ( const objects::Line& aLine ) +{ + + Intersection intersection ; + + intersection.type_ = Intersection::Type::Line ; + + intersection.composite_ = Composite { aLine } ; + + return intersection ; + +} + +Intersection Intersection::Ray ( const objects::Ray& aRay ) +{ + + Intersection intersection ; + + intersection.type_ = Intersection::Type::Ray ; + + intersection.composite_ = Composite { aRay } ; + + return intersection ; + +} + +Intersection Intersection::Segment ( const objects::Segment& aSegment ) +{ + + Intersection intersection ; + + intersection.type_ = Intersection::Type::Segment ; + + intersection.composite_ = Composite { aSegment } ; + + return intersection ; + +} + String Intersection::StringFromType ( const Intersection::Type& aType ) { diff --git a/src/Library/Mathematics/Geometry/3D/Objects/Pyramid.cpp b/src/Library/Mathematics/Geometry/3D/Objects/Pyramid.cpp index 089d7561..1ac585bc 100644 --- a/src/Library/Mathematics/Geometry/3D/Objects/Pyramid.cpp +++ b/src/Library/Mathematics/Geometry/3D/Objects/Pyramid.cpp @@ -7,6 +7,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -129,6 +131,70 @@ bool Pyramid::intersects ( } +bool Pyramid::contains ( const Point& aPoint ) const +{ + + using Point2d = library::math::geom::d2::objects::Point ; + + if (!aPoint.isDefined()) + { + throw library::core::error::runtime::Undefined("Ellipsoid") ; + } + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Pyramid") ; + } + + if (aPoint == apex_) + { + return true ; + } + + // Projection of the point onto the pyramid base plane, along the apex to point ray + + const Ray apexToPointRay = { apex_, aPoint - apex_ } ; + + const Plane basePlane = { base_.getOrigin(), base_.getNormalVector() } ; + + const Intersection rayPlaneIntersection = apexToPointRay.intersectionWith(basePlane) ; + + if (rayPlaneIntersection.isEmpty()) + { + return false ; + } + + if (!rayPlaneIntersection.is()) + { + throw library::core::error::RuntimeError("Pyramid is degenerate.") ; + } + + const Point intersectionPoint = rayPlaneIntersection.as() ; + + // Convert intersection point into pyramid base frame + + const Transformation translation = Transformation::Translation(-base_.getOrigin().asVector()) ; + + const Vector3d baseXAxis = base_.getXAxis() ; + const Vector3d baseYAxis = base_.getYAxis() ; + const Vector3d baseZAxis = base_.getNormalVector() ; + + const RotationMatrix rotationMatrix = RotationMatrix::Columns(baseXAxis, baseYAxis, baseZAxis) ; + + const Transformation rotation = Transformation::Rotation(rotationMatrix) ; + + const Transformation combinedTransformation = rotation * translation ; + + const Point transformedPoint = combinedTransformation.applyTo(intersectionPoint) ; + + const Point2d projectedPoint = { transformedPoint.x(), transformedPoint.y() } ; + + // Query if projected point is within polygonal base + + return base_.getPolygon2d().contains(projectedPoint) ; + +} + bool Pyramid::contains ( const Ellipsoid& anEllipsoid ) const { diff --git a/src/Library/Mathematics/Geometry/3D/Objects/Ray.cpp b/src/Library/Mathematics/Geometry/3D/Objects/Ray.cpp index 083fb336..7e7cd445 100644 --- a/src/Library/Mathematics/Geometry/3D/Objects/Ray.cpp +++ b/src/Library/Mathematics/Geometry/3D/Objects/Ray.cpp @@ -89,7 +89,7 @@ bool Ray::intersects ( // } -bool Ray::intersects ( const Sphere& aSphere ) const +bool Ray::intersects ( const Sphere& aSphere ) const { return aSphere.intersects(*this) ; } @@ -147,6 +147,50 @@ Vector3d Ray::getDirection ( ) } +Intersection Ray::intersectionWith ( const Plane& aPlane ) const +{ + + if (!this->isDefined()) + { + throw library::core::error::runtime::Undefined("Ray") ; + } + + if (!aPlane.isDefined()) + { + throw library::core::error::runtime::Undefined("Plane") ; + } + + const Vector3d n = aPlane.getNormalVector() ; + const Vector3d v = direction_ ; + + const Vector3d Q_0 = aPlane.getPoint().asVector() ; + const Vector3d P_0 = origin_.asVector() ; + + const double nDotV = n.dot(v) ; + + if (nDotV == 0.0) // Ray and plane are parallel + { + + if (n.dot(Q_0 - P_0) == 0.0) // Ray is in plane + { + return Intersection::Ray(*this) ; + } + + return Intersection::Empty() ; + + } + + const double t = n.dot(Q_0 - P_0) / nDotV ; + + if (t < 0.0) + { + return Intersection::Empty() ; + } + + return Intersection::Point(Point::Vector(P_0 + t * v)) ; + +} + Intersection Ray::intersectionWith ( const Sphere& aSphere, const bool onlyInSight ) const { diff --git a/test/Library/Mathematics/Geometry/3D/Objects/Pyramid.test.cpp b/test/Library/Mathematics/Geometry/3D/Objects/Pyramid.test.cpp index 305a881f..b5abe317 100644 --- a/test/Library/Mathematics/Geometry/3D/Objects/Pyramid.test.cpp +++ b/test/Library/Mathematics/Geometry/3D/Objects/Pyramid.test.cpp @@ -205,6 +205,118 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Pyramid, Intersects_Ellipsoid) } +TEST (Library_Mathematics_Geometry_3D_Objects_Pyramid, Contains_Point) +{ + + using library::math::obj::Vector3d ; + using library::math::geom::d3::objects::Point ; + using library::math::geom::d3::objects::Polygon ; + using library::math::geom::d3::objects::Pyramid ; + + { + + const Polygon base = { { { { -0.1, -0.1 }, { +0.1, -0.1 }, { +0.1, +0.1 }, { -0.1, +0.1 } } }, { 0.0, 0.0, 1.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 } } ; + const Point apex = { 0.0, 0.0, 0.0 } ; + + const Pyramid pyramid = { base, apex } ; + + EXPECT_TRUE(pyramid.contains(Point { 0.0, 0.0, 0.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 0.0, 0.0, 1.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 0.0, 0.0, 2.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 0.0, 0.0, 3.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { 0.0, 0.0, -1.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { 0.0, 0.0, -2.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { 0.0, 0.0, -3.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { +1.0, 0.0, 0.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { -1.0, 0.0, 0.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { 0.0, +1.0, 0.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { 0.0, -1.0, 0.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { 2.0, 2.0, 1.0 })) ; + + } + + { + + const Polygon base = { { { { -0.1, -0.1 }, { +0.1, -0.1 }, { +0.1, +0.1 }, { -0.1, +0.1 } } }, { 0.0, 0.0, -1.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 } } ; + const Point apex = { 0.0, 0.0, 0.0 } ; + + const Pyramid pyramid = { base, apex } ; + + EXPECT_TRUE(pyramid.contains(Point { 0.0, 0.0, 0.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 0.0, 0.0, -1.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 0.0, 0.0, -2.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 0.0, 0.0, -3.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { 0.0, 0.0, 1.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { 0.0, 0.0, 2.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { 0.0, 0.0, 3.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { +1.0, 0.0, 0.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { -1.0, 0.0, 0.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { 0.0, +1.0, 0.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { 0.0, -1.0, 0.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { 2.0, 2.0, -1.0 })) ; + + } + + { + + const Polygon base = { { { { -0.1, -0.1 }, { +0.1, -0.1 }, { +0.1, +0.1 }, { -0.1, +0.1 } } }, { 0.0, 2.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 0.0, -1.0 } } ; + const Point apex = { 0.0, 1.0, 0.0 } ; + + const Pyramid pyramid = { base, apex } ; + + EXPECT_TRUE(pyramid.contains(Point { 0.0, 1.0, 0.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 0.0, 2.0, 0.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 0.0, 3.0, 0.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 0.0, 4.0, 0.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { 0.0, 0.0, 0.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { 0.0, -1.0, 0.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { 0.0, -2.0, 0.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { 0.0, -2.0, 0.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { +1.0, 0.0, 0.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { -1.0, 0.0, 0.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { 0.0, 0.0, +1.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { 0.0, 0.0, -1.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { 1.0, 1.0, 1.0 })) ; + + } + + { + + const Polygon base = { { { { -1.0, -1.0 }, { +1.0, -1.0 }, { +1.0, +1.0 }, { -1.0, +1.0 } } }, { 2.0, 2.0, 0.0 }, { 0.0, 0.0, -1.0 }, { 0.0, 1.0, 0.0 } } ; + const Point apex = { 0.0, 0.0, 0.0 } ; + + const Pyramid pyramid = { base, apex } ; + + EXPECT_TRUE(pyramid.contains(Point { 0.0, 0.0, 0.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 2.0, 2.0, 0.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 2.0, 1.0, 0.0 })) ; + EXPECT_TRUE(pyramid.contains(Point { 2.0, 3.0, 0.0 })) ; + + EXPECT_FALSE(pyramid.contains(Point { 2.0, 0.5, 0.0 })) ; + EXPECT_FALSE(pyramid.contains(Point { 1.0, 2.0, 0.0 })) ; + + } + + { + + EXPECT_ANY_THROW(Pyramid::Undefined().contains(Point::Undefined())) ; + + } + +} + TEST (Library_Mathematics_Geometry_3D_Objects_Pyramid, GetBase) { diff --git a/test/Library/Mathematics/Geometry/3D/Objects/Ray.test.cpp b/test/Library/Mathematics/Geometry/3D/Objects/Ray.test.cpp index 259caed0..60f2fc58 100644 --- a/test/Library/Mathematics/Geometry/3D/Objects/Ray.test.cpp +++ b/test/Library/Mathematics/Geometry/3D/Objects/Ray.test.cpp @@ -309,6 +309,26 @@ TEST (Library_Mathematics_Geometry_3D_Objects_Ray, GetDirection) } +TEST (Library_Mathematics_Geometry_3D_Objects_Ray, IntersectionWith_Plane) +{ + + using library::math::geom::d3::objects::Ray ; + using library::math::geom::d3::objects::Plane ; + + { + + // [TBI] + + } + + { + + EXPECT_ANY_THROW(Ray::Undefined().intersectionWith(Plane::Undefined())) ; + + } + +} + TEST (Library_Mathematics_Geometry_3D_Objects_Ray, IntersectionWith_Ellipsoid) {