Skip to content
Open
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
2 changes: 2 additions & 0 deletions doc/manual/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ User manual
* Geometric contractors
* :ref:`sec-ctc-geom-ctcdist`
* :ref:`sec-ctc-geom-ctcpolar`
* :ref:`sec-ctc-geom-ctcvisible`
* CtcSegment
* CtcPolygon
* CtcPointCloud
Expand Down Expand Up @@ -284,6 +285,7 @@ User manual
* SepInverse
* SepTransform
* Geometrical separators
* SepVisible
* SepPolarCart or SepCartPolar
* SepPolygon
* SepEllipse
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
113 changes: 113 additions & 0 deletions doc/manual/manual/contractors/geometric/ctcvisible.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
.. _sec-ctc-geom-ctcvisible:

The CtcVisible and CtcNoVisible contractors
===========================================

Main authors: `Quentin Brateau <https://teusner.github.io/>`_

The visibility constraint characterizes the set of points :math:`\mathbf{x} \in \mathbb{R}^2` that are visible from an observation point :math:`\mathbf{a}` given an obstacle segment :math:`[\mathbf{e}_1, \mathbf{e}_2]`.

This constraint is based on the work of **Rémy Guyonneau** (see [Guyonneau2013]_). A point :math:`\mathbf{x}` is considered visible if the segment :math:`[\mathbf{a}, \mathbf{x}]` does not intersect the obstacle segment :math:`[\mathbf{e}_1, \mathbf{e}_2]`. This creates a "shadow cone" originating from :math:`\mathbf{a}`.

.. image:: visibility.png
:alt: Illustration of the visibility constraint from an observation point [Guyonneau2013]_
:width: 250px

.. image:: novisibility.png
:alt: Illustration of the non-visibility constraint from an observation point [Guyonneau2013]_
:width: 250px

.. doxygenclass:: codac2::CtcVisible
:project: codac

.. doxygenclass:: codac2::CtcNoVisible
:project: codac

.. note::
Current implementations assume a thin (degenerated) observation point :math:`\mathbf{a}`. Future versions will support visibility from **observation lines**, set defined by **convex polygons**, and from any **set** defined by a Separator.

Methods
-------

.. doxygenfunction:: codac2::CtcVisible::contract(IntervalVector&) const
:project: codac

.. doxygenfunction:: codac2::CtcNoVisible::contract(IntervalVector&) const
:project: codac



Example of use: Characterizing the set of visible and non-visible points from an observation point
--------------------------------------------------------------------------------------------------

In this example, we characterize the visible and hidden areas from an observer at the origin :math:`\mathbf{a}=(0,0)^\intercal` facing a wall represented by a segment from :math:`(2, -1)` to :math:`(2, 1)`.

.. tabs::

.. group-tab:: Python

.. literalinclude:: src.py
:language: py
:start-after: [ctcvisible-beg]
:end-before: [ctcvisible-end]
:dedent: 4

.. group-tab:: C++

.. literalinclude:: src.cpp
:language: c++
:start-after: [ctcvisible-beg]
:end-before: [ctcvisible-end]
:dedent: 4

.. figure:: ctcvisible.png
:width: 400px

.. tabs::

.. group-tab:: Python

.. literalinclude:: src.py
:language: py
:start-after: [ctcnovisible-beg]
:end-before: [ctcnovisible-end]
:dedent: 4

.. group-tab:: C++

.. literalinclude:: src.cpp
:language: c++
:start-after: [ctcnovisible-beg]
:end-before: [ctcnovisible-end]
:dedent: 4

Characterization of the visibility area. The points that are not visible are out of the visibility region and belongs to the blue area. The uncertain region is represented in yellow.

.. figure:: ctcnovisible.png
:width: 400px

Characterization of the non-visibility area. The points that are visible are out of the non-visibility region and belongs to the blue area. The uncertain region is represented in yellow.

Fake Boundaries
---------------

When implementing visibility over a union of segments (e.g., a non-convex polygon), one must be careful of **fake boundaries**. These occur when the intersection of several visibility contractors creates "uncertain" regions that do not correspond to actual physical visibility limits. For a detailed discussion on handling these in interval analysis, see [Brateau2025]_.

Related content
---------------

.. |visibility-pdf| replace:: **Download the manuscript**
.. _visibility-pdf: https://theses.hal.science/tel-00961501/file/these_remy_guyonneau.pdf

.. |fake_boundaries-pdf| replace:: **Download the paper**
.. _fake_boundaries-pdf: https://cyber.bibl.u-szeged.hu/index.php/actcybern/article/view/4560

.. admonition:: References

.. [Guyonneau2013] \ R. Guyonneau. *Modélisation et exploitation d'incertitudes pour la robotique mobile à l'aide de l'analyse par intervalles*. PhD Thesis, 2013. |visibility-pdf|_

.. [Brateau2025] \ Q. Brateau, et al. *Considering Adjacent Sets for Computing the Visibility Region*. Acta Cybernetica, 2025. |fake_boundaries-pdf|_

.. admonition:: Technical documentation

See the `C++ API documentation of CtcVisible <../../api/html/classcodac2_1_1_ctc_visible.html>`_.
1 change: 1 addition & 0 deletions doc/manual/manual/contractors/geometric/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Geometric contractors

ctcdist.rst
ctcpolar.rst
ctcvisible.rst
CtcSegment <http://codac.io>
CtcPolygon <http://codac.io>
CtcEllipse <http://codac.io>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions doc/manual/manual/contractors/geometric/src.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <codac2_CtcDist.h>
#include <codac2_CtcPolar.h>
#include <codac2_CtcProj.h>
#include <codac2_CtcVisible.h>
#include <codac2_Approx.h>
#include <codac2_cart_prod.h>
#include <codac2_CtcInter.h>
Expand Down Expand Up @@ -86,4 +87,33 @@ TEST_CASE("CtcPolar - manual")
// x = [1.5, 2.5] ; y = [6.53834, 7.85812] ; rho = [7, 8] ; theta = [1.20558, 1.38218]
// [ctcpolar-2-end]
}
}

TEST_CASE("CtcVisible - manual")
{
{
// [ctcvisible-beg]
Vector a({1, 1});
Segment s({{1, 1}, {4, 4}}, {{3, 3}, {2, 2}});
CtcVisible ctc(Vector({0.0, 0.0}), Segment({2.0, -1.0}, {2.0, 1.0}));
DefaultFigure::pave(
{{-1,6},{-1,6}},
CtcNoVisible(a, s),
1e-1
);
// [ctcvisible-end]
}

{
// [ctcnovisible-beg]
Vector a({1, 1});
Segment s({{1, 1}, {4, 4}}, {{3, 3}, {2, 2}});
CtcNoVisible sep(a, s);
DefaultFigure::pave(
{{-1,6},{-1,6}},
CtcNoVisible(a, s),
1e-1
);
// [ctcnovisible-end]
}
}
24 changes: 24 additions & 0 deletions doc/manual/manual/contractors/geometric/src.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,29 @@ def tests_CtcPolar_manual(test):
test.assertTrue(Approx(rho,1e-5) == Interval([7,8]))
test.assertTrue(Approx(theta,1e-5) == Interval([1.20558,1.38218]))

def test_CtcVisible(test):
# [ctcvisible-beg]
a = [1, 1]
s = Segment([1, 4], [3, 2])
ctc = CtcVisible(a, s)
DefaultFigure.pave(
[[-1,6],[-1,6]],
ctc,
0.1
)
# [ctcvisible-end]

# [ctcnovisible-beg]
a = [1, 1]
s = Segment([1, 4], [3, 2])
ctc = CtcNoVisible(a, s)
DefaultFigure.pave(
[[-1,6],[-1,6]],
ctc,
0.1
)
# [ctcnovisible-end]


if __name__ == '__main__':
unittest.main()
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions doc/manual/manual/contractors/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Contractors, separators
CtcInverse <analytic/ctcinverse>
CtcDist <geometric/ctcdist>
CtcPolar <geometric/ctcpolar>
CtcVisible <geometric/ctcvisible>

.. What are contractors? <http://codac.io>
.. The Ctc class <http://codac.io>
Expand Down
34 changes: 34 additions & 0 deletions examples/14_visibility/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# ==================================================================
# codac / basics example - cmake configuration file
# ==================================================================

cmake_minimum_required(VERSION 3.5)
project(codac_example LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Adding Codac

# In case you installed Codac in a local directory, you need
# to specify its path with the CMAKE_PREFIX_PATH option.
# set(CMAKE_PREFIX_PATH "~/codac/build_install")

find_package(CODAC REQUIRED)
message(STATUS "Found Codac version ${CODAC_VERSION}")

# Initializating Ibex

ibex_init_common()

# Compilation

if(FAST_RELEASE)
add_compile_definitions(FAST_RELEASE)
message(STATUS "You are running Codac in fast release mode. (option -DCMAKE_BUILD_TYPE=Release is required)")
endif()

add_executable(${PROJECT_NAME} main.cpp)
target_compile_options(${PROJECT_NAME} PUBLIC ${CODAC_CXX_FLAGS})
target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC ${CODAC_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} PUBLIC ${CODAC_LIBRARIES})
23 changes: 23 additions & 0 deletions examples/14_visibility/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <codac>
using namespace codac2;

int main()
{
// Observation Point and Obstacle Segment
Vector a({1, 1});
Segment s({{1,1}, {4,4}}, {{3,3}, {2,2}});

// Set up the figure
DefaultFigure::set_axes(axis(0,{-1,6}), axis(1,{-1,6}));

// Show the observation point and the segment
DefaultFigure::draw_circle(a, 0.05, StyleProperties({Color::dark_green(), Color::green()}, "w:0.025", "z:5"));
DefaultFigure::draw_line(s[0].mid(), s[1].mid(), StyleProperties(Color::red(), "w:0.05", "z:5"));

// Paving of the visibility separator
DefaultFigure::pave(
{{-1,6},{-1,6}},
CtcVisible(a, s),
1e-1
);
}
4 changes: 3 additions & 1 deletion python/src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
contractors/codac2_py_CtcQInter.cpp
contractors/codac2_py_CtcSegment.cpp
contractors/codac2_py_CtcUnion.cpp
contractors/codac2_py_CtcWrapper.cpp
contractors/codac2_py_CtcUnion.cpp
contractors/codac2_py_CtcVisible.cpp
contractors/codac2_py_linear_ctc.cpp

domains/ellipsoid/codac2_py_Ellipsoid.cpp
Expand Down Expand Up @@ -113,6 +114,7 @@
separators/codac2_py_SepQInter.cpp
separators/codac2_py_SepTransform.cpp
separators/codac2_py_SepUnion.cpp
separators/codac2_py_SepVisible.cpp
separators/codac2_py_SepWrapper.cpp

tools/codac2_py_Approx.cpp
Expand Down
42 changes: 42 additions & 0 deletions python/src/core/contractors/codac2_py_CtcVisible.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/** * Codac binding (core)
* ----------------------------------------------------------------------------
* \date 2026
* \author Quentin Brateau
* \copyright Copyright 2026 Codac Team
* \license GNU Lesser General Public License (LGPL)
*/
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <codac2_CtcVisible.h>
#include "codac2_py_Ctc.h"
#include "codac2_py_CtcWrapper_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py):

#define CTCVISIBLE_MAIN "Contractor for visibility from a point relative to a segment."
#define CTCVISIBLE_INIT "Initialize CtcVisible with an observation point and an obstacle segment."
#define CTCVISIBLE_CONTRACT "Contract the box x based on visibility criteria."

#define CTCNOVISIBLE_MAIN "Contractor for the hidden zone (shadow) behind a segment."
#define CTCNOVISIBLE_INIT "Initialize CtcNoVisible with an observation point and an obstacle segment."
#define CTCNOVISIBLE_CONTRACT "Contract the box x to the hidden area."

using namespace std;
using namespace codac2;
namespace py = pybind11;
using namespace pybind11::literals;

void export_CtcVisibility(py::module& m, py::class_<CtcBase<IntervalVector>, pyCtcIntervalVector>& pyctc)
{
// --- CtcVisible ---
py::class_<CtcVisible> vis(m, "CtcVisible", pyctc, CTCVISIBLE_MAIN);
vis
.def(py::init<const Vector&, const Segment&>(),
CTCVISIBLE_INIT, "a"_a, "s"_a)
.def(CONTRACT_BOX_METHOD(CtcVisible, CTCVISIBLE_CONTRACT));

// --- CtcNoVisible ---
py::class_<CtcNoVisible> nvis(m, "CtcNoVisible", pyctc, CTCNOVISIBLE_MAIN);
nvis
.def(py::init<const Vector&, const Segment&>(),
CTCNOVISIBLE_INIT, "a"_a, "s"_a)
.def(CONTRACT_BOX_METHOD(CtcNoVisible, CTCNOVISIBLE_CONTRACT));
}
36 changes: 36 additions & 0 deletions python/src/core/separators/codac2_py_SepVisible.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/** * Codac binding (core)
* ----------------------------------------------------------------------------
* \date 2026
* \author Quentin Brateau
* \copyright Copyright 2026 Codac Team
* \license GNU Lesser General Public License (LGPL)
*/

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <codac2_SepVisible.h>
#include "codac2_py_Sep.h"
#include "codac2_py_SepUnion_docs.h" // Generated file from Doxygen XML (doxygen2docstring.py):

#define SEPVISIBILITY_MAIN "Separator for visibility characterization (Inside=Hidden, Outside=Visible)."
#define SEPVISIBILITY_INIT "Initialize SepVisible with an observation point 'a' and an obstacle segment 's'."
#define SEPVISIBILITY_SEPARATE "Separate the box into hidden and visible parts, returning a tuple (x_in, x_out)."

using namespace std;
using namespace codac2;
namespace py = pybind11;
using namespace pybind11::literals;

void export_SepVisible(py::module& m, py::class_<SepBase, pySep>& pysep)
{
py::class_<SepVisible> exported(m, "SepVisible", pysep, SEPVISIBILITY_MAIN);
exported
.def(py::init<const Vector&, const Segment&>(),
"a"_a, "s"_a,
SEPVISIBILITY_INIT)

.def("separate", &SepVisible::separate,
"x"_a,
SEPVISIBILITY_SEPARATE)
;
}
3 changes: 3 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcLazy.h
${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcNot.h
${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcUnion.h
${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcVisible.cpp
${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcVisible.h
${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcPointCloud.cpp
${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcPointCloud.h
${CMAKE_CURRENT_SOURCE_DIR}/contractors/codac2_CtcPolar.cpp
Expand Down Expand Up @@ -244,6 +246,7 @@
${CMAKE_CURRENT_SOURCE_DIR}/separators/codac2_SepTransform.h
${CMAKE_CURRENT_SOURCE_DIR}/separators/codac2_SepUnion.cpp
${CMAKE_CURRENT_SOURCE_DIR}/separators/codac2_SepUnion.h
${CMAKE_CURRENT_SOURCE_DIR}/separators/codac2_SepVisible.h
${CMAKE_CURRENT_SOURCE_DIR}/separators/codac2_SepWrapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/separators/codac2_SepWrapper.h

Expand Down
Loading
Loading