From 91a656c3b1d8a3cb3c97dd8e66acd4d3b755a97a Mon Sep 17 00:00:00 2001 From: godardma Date: Fri, 3 Jul 2026 11:44:52 +0200 Subject: [PATCH 01/13] [graphics] solving IPE figure not clearing ( closes #383 ) --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 38c465bbf..140e1a4b3 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -190,6 +190,7 @@ void Figure2D_IPE::clear() // clear _color map and layers _colors.clear(); _layers.clear(); + _items.clear(); init_figure(); } From ec5e3d23bc4942c254e2d2bc1ce08aecd7a1006c Mon Sep 17 00:00:00 2001 From: godardma Date: Fri, 3 Jul 2026 14:31:01 +0200 Subject: [PATCH 02/13] [graphics] save function for Figure2D ( closes #377 ) --- doc/manual/manual/visualization/figures.rst | 3 ++- examples/00_graphics/graphic_animation.cpp | 21 ++++++++++++++++++ examples/00_graphics/graphic_animation.py | 22 ++++++++++++++++++- .../graphics/figures/codac2_py_Figure2D.cpp | 4 ++++ src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 3 +++ src/graphics/3rd/ipe/codac2_Figure2D_IPE.h | 7 ++++++ .../3rd/vibes/codac2_Figure2D_VIBes.cpp | 5 +++++ .../3rd/vibes/codac2_Figure2D_VIBes.h | 7 ++++++ src/graphics/figures/codac2_Figure2D.cpp | 6 +++++ src/graphics/figures/codac2_Figure2D.h | 18 +++++++++++++++ src/graphics/figures/codac2_OutputFigure2D.h | 7 ++++++ 11 files changed, 101 insertions(+), 2 deletions(-) diff --git a/doc/manual/manual/visualization/figures.rst b/doc/manual/manual/visualization/figures.rst index f146017eb..95a525a95 100644 --- a/doc/manual/manual/visualization/figures.rst +++ b/doc/manual/manual/visualization/figures.rst @@ -156,4 +156,5 @@ VIBes only Some methods are exclusive to the real-time display with VIBes : - center_viewbox : takes two Vector as arguments, the center and radius of each axis -- auto_scale : takes no argument, the figure will be automatically scaled to fit the window \ No newline at end of file +- auto_scale : takes no argument, the figure will be automatically scaled to fit the window +- save : takes the name of the file as argument and saves the current state of the VIBes window to the file. Allowed formats are png, jpg, bmp and svg. \ No newline at end of file diff --git a/examples/00_graphics/graphic_animation.cpp b/examples/00_graphics/graphic_animation.cpp index 1b567d086..6f357e68c 100644 --- a/examples/00_graphics/graphic_animation.cpp +++ b/examples/00_graphics/graphic_animation.cpp @@ -21,4 +21,25 @@ int main() theta += 2.0 * M_PI / (double) steps; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } + + Figure2D fig_save ("Animation with exports",GraphicOutput::VIBES|GraphicOutput::IPE); + fig_save.set_window_properties({600,50},{500,500}); // position, window size + fig_save.set_axes(axis(0,{-0.5,4}), axis(1,{-0.5,1.5})); + + Vector X({0,0,0}); + + ColorMap cmap = ColorMap::rainbow(); + for (double t = 0; t < 2.*PI; t+=PI/20.) + { + fig_save.draw_tank(X, 0.05, cmap.color(t/(2.*PI))); + X+=Vector({0.1*cos(X[2]),0.1*sin(X[2]),0.1*cos(t)}); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + if (Interval(PI).inflate(0.1).contains(t)) + { + fig_save.save("animation_tank.png"); + fig_save.save("animation_tank.jpg"); + fig_save.save("animation_tank.bmp"); + fig_save.save("animation_tank.svg"); + } + } } \ No newline at end of file diff --git a/examples/00_graphics/graphic_animation.py b/examples/00_graphics/graphic_animation.py index 69955e528..24dfff9e7 100644 --- a/examples/00_graphics/graphic_animation.py +++ b/examples/00_graphics/graphic_animation.py @@ -1,4 +1,5 @@ from codac import * +import math import time fig = Figure2D("Animation", GraphicOutput.VIBES | GraphicOutput.IPE) @@ -11,4 +12,23 @@ fig.clear() fig.draw_point([5*cos(theta).mid(), 5*sin(theta).mid()], Color.red()) theta += 2*PI / steps - time.sleep(0.1) \ No newline at end of file + time.sleep(0.1) + +fig_save = Figure2D("Animation with exports", GraphicOutput.VIBES | GraphicOutput.IPE) +fig_save.set_window_properties([600,50],[500,500]) # position, window size +fig_save.set_axes(axis(0,[-0.5,4]), axis(1,[-0.5,1.5])) + +X = Vector([0,0,0]) +t = 0 +cmap = ColorMap.rainbow() + +while t <2*PI: + fig_save.draw_tank(X, 0.05, cmap.color(t/(2*PI))) + X+=Vector([0.1*math.cos(X[2]),0.1*math.sin(X[2]),0.1*math.cos(t)]) + time.sleep(0.1) + if (Interval(PI).inflate(0.1).contains(t)): + fig_save.save("animation_tank.png") + fig_save.save("animation_tank.jpg") + fig_save.save("animation_tank.bmp") + fig_save.save("animation_tank.svg") + t += PI/20 \ No newline at end of file diff --git a/python/src/graphics/figures/codac2_py_Figure2D.cpp b/python/src/graphics/figures/codac2_py_Figure2D.cpp index 41b26324c..e78d90819 100644 --- a/python/src/graphics/figures/codac2_py_Figure2D.cpp +++ b/python/src/graphics/figures/codac2_py_Figure2D.cpp @@ -109,6 +109,10 @@ void export_Figure2D(py::module& m) .def("clear", &Figure2D::clear, VOID_FIGURE2D_CLEAR) + + .def("save", &Figure2D::save, + VOID_FIGURE2D_SAVE_CONST_STRING_REF, + "filename"_a) .def("scaled_unit", &Figure2D::scaled_unit, DOUBLE_FIGURE2D_SCALED_UNIT_CONST) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 140e1a4b3..62a6a94cd 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -195,6 +195,9 @@ void Figure2D_IPE::clear() init_figure(); } +void Figure2D_IPE::save(const std::string& filename) +{} + std::string ipe_str(const Color& c) { return c.hex_str().substr(1); diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h index 23d0e15f6..ddfeba394 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.h @@ -72,6 +72,13 @@ namespace codac2 */ void clear(); + /** + * \brief Saves the figure to a file + * + * \param filename Name of the file to save the figure to + */ + void save(const std::string& filename); + /** * \brief Begins a new path in the IPE file * diff --git a/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.cpp b/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.cpp index eb3e40059..aeb59a32b 100644 --- a/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.cpp +++ b/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.cpp @@ -93,6 +93,11 @@ void Figure2D_VIBes::clear() _layers.clear(); } +void Figure2D_VIBes::save(const std::string& filename) +{ + vibes::saveImage(filename, _fig.name()); +} + void Figure2D_VIBes::draw_point(const Vector& c, const StyleProperties& style) { assert(_fig.size() <= c.size()); diff --git a/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.h b/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.h index 04572df9c..f780f544a 100644 --- a/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.h +++ b/src/graphics/3rd/vibes/codac2_Figure2D_VIBes.h @@ -65,6 +65,13 @@ namespace codac2 * \brief Clears the figure */ void clear(); + + /** + * \brief Saves the figure to a file + * + * \param filename Name of the file to save the figure to + */ + void save(const std::string& filename); // Geometric shapes diff --git a/src/graphics/figures/codac2_Figure2D.cpp b/src/graphics/figures/codac2_Figure2D.cpp index 15c9503c8..2658e715b 100644 --- a/src/graphics/figures/codac2_Figure2D.cpp +++ b/src/graphics/figures/codac2_Figure2D.cpp @@ -111,6 +111,12 @@ void Figure2D::clear() output_fig->clear(); } +void Figure2D::save(const std::string& filename) +{ + for(const auto& output_fig : _output_figures) + output_fig->save(filename); +} + double Figure2D::scaled_unit() const { return std::max(_axes[0].limits.diam(),_axes[1].limits.diam()) / _window_size.max_coeff(); diff --git a/src/graphics/figures/codac2_Figure2D.h b/src/graphics/figures/codac2_Figure2D.h index 3b920c734..ec637baa8 100644 --- a/src/graphics/figures/codac2_Figure2D.h +++ b/src/graphics/figures/codac2_Figure2D.h @@ -182,6 +182,13 @@ namespace codac2 */ void clear(); + /** + * \brief Saves the figure to a file + * + * \param filename Name of the file to save the figure to + */ + void save(const std::string& filename); + /** * \brief Getter for the scaling factor of the figure * @@ -715,6 +722,17 @@ namespace codac2 selected_fig()->clear(); } + /** + * \brief Saves the figure to a file + * + * \param filename Name of the file to save the figure to + */ + static void save(const std::string& filename) + { + auto_init(); + selected_fig()->save(filename); + } + // Geometric shapes /** diff --git a/src/graphics/figures/codac2_OutputFigure2D.h b/src/graphics/figures/codac2_OutputFigure2D.h index a83ba57e4..a4157949c 100644 --- a/src/graphics/figures/codac2_OutputFigure2D.h +++ b/src/graphics/figures/codac2_OutputFigure2D.h @@ -73,6 +73,13 @@ namespace codac2 * \brief Clears the figure */ virtual void clear() = 0; + + /** + * \brief Saves the figure to a file + * + * \param filename Name of the file to save the figure to + */ + virtual void save(const std::string& filename) = 0; protected: From 3212d3ad38e8488b41f9aad9d01398b8500f77b0 Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 7 Jul 2026 16:52:45 +0200 Subject: [PATCH 03/13] [graphics] dot detection for IPE file save --- src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 39 ++++++++++---------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 62a6a94cd..86313cdf2 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -12,11 +12,14 @@ #include "codac2_Figure2D_IPE.h" #include "codac2_math.h" +// TO DELETE +#include + using namespace std; using namespace codac2; Figure2D_IPE::Figure2D_IPE(const Figure2D& fig) - : OutputFigure2D(fig), _f(fig.name() + ".xml"), + : OutputFigure2D(fig), _x_offset(0.03*_fig.axes()[0].limits.diam()), _y_offset(0.03*_fig.axes()[1].limits.diam()) { @@ -25,23 +28,7 @@ Figure2D_IPE::Figure2D_IPE(const Figure2D& fig) Figure2D_IPE::~Figure2D_IPE() { - draw_axes(); - print_header_page(); - _f.close(); - - _f = std::ofstream(_fig.name() + ".xml", std::ofstream::binary | std::ofstream::app); - std::ifstream f_temp_content(_fig.name() + "_tmp.xml", std::ofstream::binary); - - for (const auto& item : _items) - _f << item.second; - - f_temp_content.close(); - std::remove((_fig.name() + "_tmp.xml").c_str()); - _f.close(); - - _f = std::ofstream(_fig.name() + ".xml", std::ofstream::app); - _f << "\n\n"; - _f.close(); + save(_fig.name()+"."); } void Figure2D_IPE::init_figure() @@ -172,6 +159,8 @@ void Figure2D_IPE::update_axes() _ipe_grid_size/(_fig.axes()[0].limits.diam()+_x_offset), _ipe_grid_size/(_fig.axes()[1].limits.diam()+_y_offset) }; + + draw_axes(); } void Figure2D_IPE::update_window_properties() @@ -196,7 +185,19 @@ void Figure2D_IPE::clear() } void Figure2D_IPE::save(const std::string& filename) -{} +{ + std::size_t dot_position = filename.find_last_of('.'); + std::string file_name = filename.substr(0, dot_position); + _f = std::ofstream(file_name + ".xml", std::ofstream::binary | std::ofstream::app); + + print_header_page(); + + for (const auto& item : _items) + _f << item.second; + + _f << "\n\n"; + _f.close(); +} std::string ipe_str(const Color& c) { From a190b9eb380612981a17e6b59b336b6840365a92 Mon Sep 17 00:00:00 2001 From: godardma Date: Thu, 16 Jul 2026 18:23:26 +0200 Subject: [PATCH 04/13] [doc] adding PavingStyle doc --- doc/manual/manual/visualization/colors.rst | 41 ++++++++++++++++++++++ src/core/domains/paving/codac2_Subpaving.h | 1 + 2 files changed, 42 insertions(+) diff --git a/doc/manual/manual/visualization/colors.rst b/doc/manual/manual/visualization/colors.rst index 4a44c86c7..adb740814 100644 --- a/doc/manual/manual/visualization/colors.rst +++ b/doc/manual/manual/visualization/colors.rst @@ -208,6 +208,47 @@ For more information, see :ref:`subsec-graphics-colors-optional-arguments`. fig.draw_box(IntervalVector({{2,5},{2,5}}), StyleProperties(Color().red(), "..", "layer1", "w:0.1", "z:1.5")); % Red edge, dotted line, line width of 0.1, z-value of 1.5 and on layer1 +Paving style +------------ + +To change the color used to draw a paving, the ``draw_paving`` functions can take an optional argument which is the ``PavingStyle``. +Predefined styles are + +- blue_green (default_style) +- blue_white +- blue_pink +- black_white + +A custom ``PavingStyle`` can also be created from three ``StyleProperties`` : the boundary, the outside and the inside. +Below is an example of the different possibilities. + +.. tabs:: + + .. code-tab:: py + + DefaultFigure.draw_paving(p) # default style, blue_green + DefaultFigure.draw_paving(p,PavingStyle.blue_pink()) #blue_pink style + # orange boundary, purple outside and blue inside + paving_style = PavingStyle([Color.dark_orange(),Color.orange()],[Color.dark_purple(),Color.purple()],[Color.dark_blue(),Color.blue()]) + DefaultFigure.draw_paving(p,paving_style) + + + + .. code-tab:: c++ + + DefaultFigure::draw_paving(p); + DefaultFigure::draw_paving(p,PavingStyle::blue_pink()); + // orange boundary, purple outside and blue inside + PavingStyle paving_style ({Color::dark_orange(),Color::orange()},{Color::dark_purple(),Color::purple()},{Color::dark_blue(),Color::blue()}); + DefaultFigure::draw_paving(p,paving_style); + + .. code-tab:: matlab + + DefaultFigure().draw_paving(p); + DefaultFigure().draw_paving(p,PavingStyle().blue_pink()); + % orange boundary, purple outside and blue inside + paving_style = PavingStyle(StyleProperties({Color().dark_orange(),Color().orange()}),StyleProperties({Color().dark_purple(),Color().purple()}),StyleProperties({Color().dark_blue(),Color().blue()})); + DefaultFigure().draw_paving(p,paving_style); Color maps ---------- diff --git a/src/core/domains/paving/codac2_Subpaving.h b/src/core/domains/paving/codac2_Subpaving.h index e9f934b28..3ef8e2cd0 100644 --- a/src/core/domains/paving/codac2_Subpaving.h +++ b/src/core/domains/paving/codac2_Subpaving.h @@ -77,6 +77,7 @@ namespace codac2 { auto x_boxes = _node_value(xi); auto neighb_nodes = this->front()->paving().neighbours(xi, _node_value, node_complementary_value); + std::list neighb_boxes; for(const auto& neighb_ni : neighb_nodes) From f97d189bdd0406bcf792b4ab290dabdcb6225b8f Mon Sep 17 00:00:00 2001 From: godardma Date: Thu, 16 Jul 2026 18:24:33 +0200 Subject: [PATCH 05/13] minor modification --- src/core/domains/paving/codac2_Subpaving.h | 1 - src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/core/domains/paving/codac2_Subpaving.h b/src/core/domains/paving/codac2_Subpaving.h index 3ef8e2cd0..e9f934b28 100644 --- a/src/core/domains/paving/codac2_Subpaving.h +++ b/src/core/domains/paving/codac2_Subpaving.h @@ -77,7 +77,6 @@ namespace codac2 { auto x_boxes = _node_value(xi); auto neighb_nodes = this->front()->paving().neighbours(xi, _node_value, node_complementary_value); - std::list neighb_boxes; for(const auto& neighb_ni : neighb_nodes) diff --git a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp index 86313cdf2..3b5da24b3 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -12,9 +12,6 @@ #include "codac2_Figure2D_IPE.h" #include "codac2_math.h" -// TO DELETE -#include - using namespace std; using namespace codac2; From 07bc9192ff9d32e1ab062b01e8469d88db0a4d10 Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 20 Jul 2026 18:51:26 +0200 Subject: [PATCH 06/13] [doc] cleaner doc for drawing functinos --- doc/manual/manual/visualization/colors.rst | 3 +- doc/manual/manual/visualization/functions.rst | 160 ++++++++++++------ 2 files changed, 109 insertions(+), 54 deletions(-) diff --git a/doc/manual/manual/visualization/colors.rst b/doc/manual/manual/visualization/colors.rst index 4a44c86c7..ba1766398 100644 --- a/doc/manual/manual/visualization/colors.rst +++ b/doc/manual/manual/visualization/colors.rst @@ -128,7 +128,7 @@ Additionnal methods are available for any useful purpose: fig.draw_box(IntervalVector({{2.6,3.1},{2.6,3.1}}),StyleProperties({Color({108,90,78},Model().HSV),Color({108,90,78,20},Model().HSV)})); - +.. _subsec-graphics-colors-styleproperties: StyleProperties --------------- @@ -299,6 +299,7 @@ You can also create your own color map : Note that you can add RGB and HSV colors to the same color map. The model of the color map will define the interpolation space. +.. _subsec-graphics-colors-stylegradientproperties: StyleGradientProperties ----------------------- diff --git a/doc/manual/manual/visualization/functions.rst b/doc/manual/manual/visualization/functions.rst index b3efcc917..3e5d5a45c 100644 --- a/doc/manual/manual/visualization/functions.rst +++ b/doc/manual/manual/visualization/functions.rst @@ -101,91 +101,145 @@ Paving Geometric shapes ---------------- -.. doxygenfunction:: codac2::Figure2D::draw_point(const Vector&, const StyleProperties&) - :project: codac +All the drawable geometric objects can take a last optionnal argument to set up their stroke color, fill color, line style etc. +For further details, refer to :ref:`subsec-graphics-colors-styleproperties`. -.. doxygenfunction:: codac2::Figure2D::draw_box(const IntervalVector&, const StyleProperties&) - :project: codac +The geometric shapes that can be drawn and their arguments are listed below : -.. doxygenfunction:: codac2::Figure2D::draw_circle(const Vector&, double, const StyleProperties&) - :project: codac +- draw_point -.. doxygenfunction:: codac2::Figure2D::draw_ring(const Vector&, const Interval&, const StyleProperties&) - :project: codac + - Vector : 2D coordinate of the point to draw -.. doxygenfunction:: codac2::Figure2D::draw_line(const Vector&, const Vector&, const StyleProperties&) - :project: codac +- draw_box -.. doxygenfunction:: codac2::Figure2D::draw_line(const Segment&, const StyleProperties&) - :project: codac + - IntervalVector : the 2D box to draw -.. doxygenfunction:: codac2::Figure2D::draw_arrow(const Vector&, const Vector&, float, const StyleProperties&) - :project: codac +- draw_circle -.. doxygenfunction:: codac2::Figure2D::draw_polyline(const std::vector&, const StyleProperties&) - :project: codac + - Vector : the center of the circle + - double : the radius of the circle + +- draw_ring -.. doxygenfunction:: codac2::Figure2D::draw_polyline(const std::vector&, float, const StyleProperties&) - :project: codac + - Vector : the center of the ring + - Interval : the ring range : inner and outer radius -.. doxygenfunction:: codac2::Figure2D::draw_polygon(const Polygon&, const StyleProperties&) - :project: codac +- draw_pie -.. doxygenfunction:: codac2::Figure2D::draw_parallelepiped(const Parallelepiped&, const StyleProperties&) - :project: codac + - Vector : the center of the pie + - Interval : the pie range : inner and outer radius + - Interval : the pie angle : begin and end angle (in radian) -.. doxygenfunction:: codac2::Figure2D::draw_zonotope(const Zonotope&, const StyleProperties&) - :project: codac +- draw_line -.. doxygenfunction:: codac2::Figure2D::draw_pie(const Vector&, const Interval&, const Interval&, const StyleProperties&) - :project: codac + - Vector : the first point of the line + - vector : the second point of the line -.. doxygenfunction:: codac2::Figure2D::draw_ellipse(const Vector&, const Vector&, double, const StyleProperties&) - :project: codac +- draw_line -.. doxygenfunction:: codac2::Figure2D::draw_ellipsoid(const Ellipsoid&, const StyleProperties&) - :project: codac + - Segment : the segment to draw + +- draw_arrow + + - Vector : the first point of the line + - vector : the second point of the line + - float : the length of the tip of the arrow + +- draw_polyline + + - vector : vector where each element is a point of the polyline to draw + +- draw_polyline + + - vector : vector where each element is a point of the polyline to draw + - float : the length of the tip of the arrow + +- draw_polygone + + - Polygon : the polygon to draw + +- draw_parallelepiped + + - Parallelepiped : the parallelepiped to draw + +- draw_zonotope + + - Zonotope : the zonotope to draw + +- draw_ellipse + + - Vector : center of the ellipse + - Vector : Half-lengths of the ellipse + - double : rotation angle of the ellipse (in radian) + +- draw_ellipsoid + + - Ellipsoid : the ellipsoid to draw Trajectories and tubes ---------------------- -.. doxygenfunction:: codac2::Figure2D::draw_trajectory(const SampledTraj&, const StyleProperties&) - :project: codac -.. doxygenfunction:: codac2::Figure2D::draw_trajectory(const AnalyticTraj&, const StyleProperties&) - :project: codac +All the drawable trajectories and tubes can take a last optionnal argument to set up their stroke color, fill color, line style etc. +For further details, refer to :ref:`subsec-graphics-colors-styleproperties` for constant fill and edge color, +and :ref:`subsec-graphics-colors-stylegradientproperties` for the use of a colormap. -Trajectories can be drawn with a ColorMap instead of the classic StyleProperties. This can be done by passing a ColorMap object as the second argument. +The trajectories and tubes that can be drawn are listed below: -.. doxygenfunction:: codac2::Figure2D::draw_trajectory(const SampledTraj&, const StyleGradientProperties&) - :project: codac +- plot_trajectory -.. doxygenfunction:: codac2::Figure2D::draw_trajectory(const AnalyticTraj&, const StyleGradientProperties&) - :project: codac + - SampledTraj | AnalyticTraj : the 1D trajectory to draw (x-axis is the time) -.. doxygenfunction:: codac2::Figure2D::draw_tube(const SlicedTube&, const StyleProperties&, int) - :project: codac +- plot_trajectories -.. doxygenfunction:: codac2::Figure2D::draw_tube(const SlicedTube&, const StyleGradientProperties&, int) - :project: codac + - SampledTraj | AnalyticTraj : the nD trajectory to draw component by component (x-axis is the time) -.. doxygenfunction:: codac2::Figure2D::plot_tube(const SlicedTube&, const StyleProperties&) - :project: codac +- plot_tube -.. doxygenfunction:: codac2::Figure2D::plot_tube(const SlicedTube&, const SlicedTube&, const StyleProperties&) - :project: codac + - SlicedTube : the 1D tube to draw (x-axis is the time) + +- plot_tube + + - SlicedTube : the 1D tube to draw (x-axis is the time) + - SlicedTube : the derivative of the tube to draw + +- draw_trajectory + + - SampledTraj | AnalyticTraj : the 2D trajectory to draw + +- draw_tube + + - SlicedTube : the 2D tube to draw Vehicles -------- -.. doxygenfunction:: codac2::Figure2D::draw_tank(const Vector&, float, const StyleProperties&) - :project: codac +All the drawable vehicles can take a last optionnal argument to set up their stroke color, fill color, line style etc. +For further details, refer to :ref:`subsec-graphics-colors-styleproperties`. -.. doxygenfunction:: codac2::Figure2D::draw_AUV(const Vector&, float, const StyleProperties&) - :project: codac +The vehicles that can be drawn and their arguments are listed below : + +- draw_tank + + - Vector : the 3D state of the tank to draw (x,y,theta in radian) + - float : the size of the tank + +- draw_AUV + + - Vector : the 3D state of the AUV to draw (x,y,theta in radian) + - float : the size of the AUV + +- draw_motor_boat + + - Vector : the 3D state of the motor boat to draw (x,y,theta in radian) + - float : the size of the motor boat + +Paving +------ + +All the drawable pavings can take a last optionnal argument to set up their style for the insider, boundary and outside boxes. +For further details, refer to :ref:`subsec-graphics-colors-styleproperties`. -.. doxygenfunction:: codac2::Figure2D::draw_motor_boat(const Vector&, float, const StyleProperties&) - :project: codac Miscellaneous ------------- From 1f548701bd45c4dcc4823f21625657fb2fbf6298 Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 20 Jul 2026 19:00:03 +0200 Subject: [PATCH 07/13] [doc] cleaner doc for drawing functions --- doc/manual/manual/visualization/colors.rst | 1 + doc/manual/manual/visualization/functions.rst | 46 +++++++++++-------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/doc/manual/manual/visualization/colors.rst b/doc/manual/manual/visualization/colors.rst index 3766dcad3..a728c1b35 100644 --- a/doc/manual/manual/visualization/colors.rst +++ b/doc/manual/manual/visualization/colors.rst @@ -208,6 +208,7 @@ For more information, see :ref:`subsec-graphics-colors-optional-arguments`. fig.draw_box(IntervalVector({{2,5},{2,5}}), StyleProperties(Color().red(), "..", "layer1", "w:0.1", "z:1.5")); % Red edge, dotted line, line width of 0.1, z-value of 1.5 and on layer1 +.. _subsec-graphics-colors-pavingstyle: Paving style ------------ diff --git a/doc/manual/manual/visualization/functions.rst b/doc/manual/manual/visualization/functions.rst index 3e5d5a45c..38c1475ff 100644 --- a/doc/manual/manual/visualization/functions.rst +++ b/doc/manual/manual/visualization/functions.rst @@ -237,33 +237,39 @@ The vehicles that can be drawn and their arguments are listed below : Paving ------ -All the drawable pavings can take a last optionnal argument to set up their style for the insider, boundary and outside boxes. -For further details, refer to :ref:`subsec-graphics-colors-styleproperties`. +All the drawable pavings can take a last optionnal argument to set up their style for the inside, boundary and outside boxes. +For further details, refer to :ref:`subsec-graphics-colors-pavingstyle`. +The paving that can be drawn and their arguments are listed below : -Miscellaneous -------------- +- draw_paving -.. doxygenfunction:: codac2::Figure2D::draw_text(const std::string&, const Vector&, double, const StyleProperties&) - :project: codac + - PavingOut | PavingInOut : the paving to draw -.. doxygenfunction:: codac2::Figure2D::draw_raster(const std::string&, const IntervalVector&, const StyleProperties&) - :project: codac +- draw_paving -Paving ------- + - PavingOut | PavingInOut : the paving to draw + - function(Figure2D,IntervalVector,StyleProperties) : Custom drawing function (for instance, if one wants to draw in polar coordinates) + +- draw_subpaving + + - Subpaving : the subpaving to draw + +Miscellaneous +------------- + +Other objects can be drawn and can take a last optionnal argument to set up their stroke color, fill color, line style etc. +For further details, refer to :ref:`subsec-graphics-colors-styleproperties`. -.. doxygenfunction:: codac2::Figure2D::draw_paving(const PavingOut&, const PavingStyle&) - :project: codac +These objects are : -.. doxygenfunction:: codac2::Figure2D::draw_paving(const PavingOut&, const std::function&, const PavingStyle&) - :project: codac +- draw_text -.. doxygenfunction:: codac2::Figure2D::draw_paving(const PavingInOut&, const PavingStyle&) - :project: codac + - string : the text to draw + - Vector : the 2D Vector for the position of the top-left corner of the text + - float : the scale of the text (VIBes only) -.. doxygenfunction:: codac2::Figure2D::draw_paving(const PavingInOut&, const std::function&, const PavingStyle&) - :project: codac +- draw_raster -.. doxygenfunction:: codac2::Figure2D::draw_subpaving(const Subpaving

&, const StyleProperties&) - :project: codac + - string : The name of the file (the path is relative to the VIBes' server folder) + - IntervalVector : The bounding box of the raster From a242393e8b89b15f3cad325232841752a603ee55 Mon Sep 17 00:00:00 2001 From: godardma Date: Mon, 20 Jul 2026 19:29:48 +0200 Subject: [PATCH 08/13] [doc] adding graphical examples --- doc/manual/manual/extensions/capd/capd.rst | 1 + .../manual/extensions/capd/peibos_capd.rst | 2 +- doc/manual/manual/functions/peibos/peibos.rst | 3 +- .../manual/visualization/2d_example.rst | 26 ++++ .../visualization/2d_example_src/src.cpp | 124 ++++++++++++++++++ .../manual/visualization/2d_example_src/src.m | 112 ++++++++++++++++ .../visualization/2d_example_src/src.py | 115 ++++++++++++++++ .../manual/visualization/3d_example.rst | 20 +++ .../visualization/3d_example_src/src.cpp | 80 +++++++++++ .../visualization/3d_example_src/src.py | 63 +++++++++ doc/manual/manual/visualization/colors.rst | 6 +- doc/manual/manual/visualization/functions.rst | 12 +- doc/manual/manual/visualization/index.rst | 4 +- 13 files changed, 556 insertions(+), 12 deletions(-) create mode 100644 doc/manual/manual/visualization/2d_example.rst create mode 100644 doc/manual/manual/visualization/2d_example_src/src.cpp create mode 100644 doc/manual/manual/visualization/2d_example_src/src.m create mode 100644 doc/manual/manual/visualization/2d_example_src/src.py create mode 100644 doc/manual/manual/visualization/3d_example.rst create mode 100644 doc/manual/manual/visualization/3d_example_src/src.cpp create mode 100644 doc/manual/manual/visualization/3d_example_src/src.py diff --git a/doc/manual/manual/extensions/capd/capd.rst b/doc/manual/manual/extensions/capd/capd.rst index 40c23731e..590fe4c98 100644 --- a/doc/manual/manual/extensions/capd/capd.rst +++ b/doc/manual/manual/extensions/capd/capd.rst @@ -11,6 +11,7 @@ To use CAPD with Codac, you first need to install the CAPD library. You can find Note that as CAPD is a C++ only library, the content present in this page is **only available in C++**. +.. _subsec-extensions-capd-capd-install: Installing the ``codac-capd`` extension --------------------------------------- diff --git a/doc/manual/manual/extensions/capd/peibos_capd.rst b/doc/manual/manual/extensions/capd/peibos_capd.rst index fb80ca017..3fae692b3 100644 --- a/doc/manual/manual/extensions/capd/peibos_capd.rst +++ b/doc/manual/manual/extensions/capd/peibos_capd.rst @@ -31,7 +31,7 @@ The PEIBOS function takes at least six arguments : - The final time for the integration of the ODE. - A timestep to get intermediate states. - The inverse chart for the gnomonic atlas (an analytic function). -- The list of symmetries for the gnomonic atlas. Note that each symmetry is represented as a hyperoctahedral symmetry, see :ref:`sec-actions-octasym`. +- The list of symmetries for the gnomonic atlas. Note that each symmetry is represented as a hyperoctahedral symmetry, see :ref:`sec-tools-octasym`. - A resolution :math:`\epsilon`. The initial box :math:`\left[-1,1\right]^m` will initiallly be splitted in boxes with a diameter smaller than :math:`\epsilon`. - Eventually an offset vector can be specified if the initial set is not centered around the origin. - Eventually a flag can be set to True to get the verbose. diff --git a/doc/manual/manual/functions/peibos/peibos.rst b/doc/manual/manual/functions/peibos/peibos.rst index f2afcf83f..aaa1bcdd0 100644 --- a/doc/manual/manual/functions/peibos/peibos.rst +++ b/doc/manual/manual/functions/peibos/peibos.rst @@ -13,6 +13,7 @@ Let us consider an initial set :math:`\mathbb{X}_0 \subset \mathbb{R}^n` with it Considering a function :math:`\mathbf{f}:\mathbb{R}^n \to \mathbb{R}^p`, :math:`n \leq p`, the PEIBOS tool allows to compute the set :math:`\mathbf{Y}=\left\{ \mathbf{f}(\mathbf{x}) \mid \mathbf{x} \in \partial \mathbb{X}_0 \right\}`. .. _subsec-functions-peibos-gnomonic-atals: + Gnomonic atlas -------------- @@ -60,7 +61,7 @@ The PEIBOS function takes at least four arguments : - The studied analytic function. - The inverse chart for the gnomonic atlas (an analytic function). -- The list of symmetries for the gnomonic atlas. Note that each symmetry is represented as a hyperoctahedral symmetry, see :ref:`sec-actions-octasym`. +- The list of symmetries for the gnomonic atlas. Note that each symmetry is represented as a hyperoctahedral symmetry, see :ref:`sec-tools-octasym`. - A resolution :math:`\epsilon`. The initial box :math:`\left[-1,1\right]^m` will initiallly be splitted in boxes with a diameter smaller than :math:`\epsilon`. - Eventually an offset vector can be specified if the initial set is not centered around the origin. - Eventually a flag can be set to True to get the verbose. diff --git a/doc/manual/manual/visualization/2d_example.rst b/doc/manual/manual/visualization/2d_example.rst new file mode 100644 index 000000000..2b4b003e1 --- /dev/null +++ b/doc/manual/manual/visualization/2d_example.rst @@ -0,0 +1,26 @@ +.. _sec-graphics-2d-example: + +2D graphical example +==================== + +Below is an example covering a wide variety of drawing functions, colors, styles etc. + +.. tabs:: + + .. group-tab:: Python + + .. literalinclude:: 2d_example_src/src.py + :language: py + :dedent: 0 + + .. group-tab:: C++ + + .. literalinclude:: 2d_example_src/src.cpp + :language: c++ + :dedent: 0 + + .. group-tab:: Matlab + + .. literalinclude:: 2d_example_src/src.m + :language: matlab + :dedent: 0 \ No newline at end of file diff --git a/doc/manual/manual/visualization/2d_example_src/src.cpp b/doc/manual/manual/visualization/2d_example_src/src.cpp new file mode 100644 index 000000000..f10e08181 --- /dev/null +++ b/doc/manual/manual/visualization/2d_example_src/src.cpp @@ -0,0 +1,124 @@ +#include +#include +#include + +using namespace std; +using namespace codac2; + +int main(){ + + // Graphics can be directly called without a Figure2D instanciation, using "DefaultFigure" + + DefaultFigure::set_window_properties({600,600},{300,300}); + DefaultFigure::draw_box({{2.2,2.5},{2.2,2.5}},{Color::black(),Color::yellow(0.5)}); + DefaultFigure::draw_AUV({1,1,3.14/2},1.,{{Color::black(),Color::yellow()}, "-.."}); + DefaultFigure::draw_motor_boat({0,0,0}, 1., {Color::black(),Color::yellow()}); + DefaultFigure::draw_tank({2,1,3.14/2},1.,{{Color::black(),Color::yellow()},"vehicles","-."}); + DefaultFigure::draw_pie({2,2},{1.5,2.5},{(3*3.14/4)-0.5,(3*3.14/4)+0.5},{Color::blue(),Color::cyan()}); + DefaultFigure::draw_polyline({{2,-0.5},{4,0.5},{3,1.5},{4,2.5},{3,3}}, Color::red()); + DefaultFigure::draw_polygon({{2,4.5},{4,4.5},{4.2,3.5},{3.5,3}}, {Color::none(),Color::green(0.5)}); + DefaultFigure::draw_polyline({{-0.8,0},{0,1.5}}, 0.2, {Color::red(),Color::black(0.3)}); + + // Last argument corresponds to "StyleProperties" with one or two colors: edge color + (optional) fill color + // Predefined Color objects can be configured with a float parameter for opacity (1=opaque, 0=transparent) + + // Custom figures can also be created: + std::shared_ptr fig1 = std::make_shared("My Figure 1",GraphicOutput::VIBES|GraphicOutput::IPE); + + // Here, graphics will be rendered by two tools: both VIBES and IPE + // For VIBES, it requires the VIBes viewer to be launched prior to the execution + // For IPE, it generates a file named "My figure 1.xml" that can be edited with IPE, and converted to PDF + + fig1->set_window_properties({50,50},{500,500}); // position, window size + fig1->set_axes(IntervalVector::constant(2,{-10,10})); // bounding box + fig1->draw_box({{-1,1},{-1,1}},{Color::green(),Color::red(0.2)}); // drawing a green box with red opacity values inside + fig1->draw_circle({1,1},0.5,Color({255,155,5})); // drawing a circle at (1,1) of radius 0.5 with a custom RGB color + fig1->draw_ring({1,1},{4,6},Color::red()); // drawing a ring at (1,1) of radius {4,6} with a predefined red color + + std::shared_ptr fig2 = std::make_shared("My Figure 2",GraphicOutput::VIBES|GraphicOutput::IPE); + fig2->set_axes(axis(0,{-1,5}), axis(1,{-1,5})); // (axis_id,{range_of_values_on_this_axis}) + fig2->set_window_properties({250,250},{500,500}); + + // The previously declared figure "fig2" can now be used as a DefaultFigure + DefaultFigure::set(fig2); + DefaultFigure::draw_box({{2.2,2.5},{2.2,2.5}},{Color::black(),Color::green(0.8)}); + + DefaultFigure::set(fig1); + DefaultFigure::draw_box({{2.2,2.5},{2.2,2.5}},{Color::blue(),Color::cyan(0.8)}); + + fig2->draw_circle({2.,2.},0.5,{{Color::red(),Color::red(0.2)}, "z:1."}); // will alway be on top despite being "drawn" first + + fig2->draw_AUV({1,1,3.14/2},2.,{{Color::black(),Color::yellow()}, "w:0.1", "vehicles"}); + fig2->draw_tank({2,1,3.14/2},1.5,{{Color::black(),Color::yellow()},"vehicles","w:0.1"}); + fig2->draw_motor_boat({0,0,0}, 1., {{Color::black(),Color::yellow()},"vehicles"}); + fig2->draw_pie({2,2},{1.5,2.5},{(3*3.14/4)-0.5,(3*3.14/4)+0.5},{Color::blue(),Color::cyan()}); + fig2->draw_polyline({{2,-0.5},{4,0.5},{3,1.5},{4,2.5},{3,3}}, {Color::red(),".."}); + fig2->draw_polygon({{2,4.5},{4,4.5},{4.2,3.5},{3.5,3}}, {Color::none(),Color::green(0.5)}); + fig2->draw_polyline({{-0.8,0},{0,1.5}}, 0.2, {Color::red(),Color::black(0.3)}); + fig2->draw_ellipse({1,1},{0.5,2}, 0.2, {Color::blue(),Color::blue(0.3)}); + fig2->draw_line({1,1},{3,3}, Color::blue()); + fig2->draw_arrow({3,1},{2.2,2}, 0.2, {Color::red(),Color::black(0.3)}); + fig2->draw_parallelepiped({{1.5,2.8},Matrix({{0.5,0.4},{0,0.2}})}, {{Color::red(),Color::green(0.5)}, "parallelepiped", "w:0.1"}); + + fig2->draw_zonotope({{4,1.5}, + {{-0.2,-0.06,0.2,0.06,0.01,0.08,0}, + {0.1,0.04,0.04,-0.04,-0.03,0.18,0}}}, + {{Color::red(),Color::yellow(0.4)},"zonotope", "w:0.05"}); + + Parallelepiped p_3d ({1.2,3.5,2.2},Matrix({{0.5,0.4,0},{0,0.2,0.1},{0,0,0.3}})); + fig2->draw_zonotope(p_3d.proj({0,1}), {{Color::green(),Color::yellow(0.4)}, "zonotope"}); + + fig2->draw_text("Hello, World!",{-0.5,4.5},0.2, Color::blue()); + + std::filesystem::path p = __FILE__; + fig2->draw_raster(p.parent_path().string()+"/logo_codac.png", IntervalVector({{2.5,5},{-1,-0.4}}), StyleProperties("raster")); + + fig2->draw_circle({0.5,0.5},0.5,{{Color::orange(),Color::orange(0.2)}, "z:-1."}); // will alway be in the bottom despite being "drawn" last + + // Colors + // predefined colors without and with opacity + fig2->draw_point({2,2}, {Color::red(),Color::yellow(0.5)}); + // HTML color without and with opacity + fig2->draw_box({{2.4,2.9},{2.4,2.9}},{Color("#da3907"),Color("#da390755")}); + // HSV color without and with opacity + fig2->draw_box({{2.6,3.1},{2.6,3.1}},{Color({108,90,78},Model::HSV),Color({108,90,78,20},Model::HSV)}); + + Figure2D fig3 ("ColorMap figure",GraphicOutput::VIBES|GraphicOutput::IPE); + fig3.set_window_properties({800,250},{500,500}); + + ColorMap cmap_haxby = ColorMap::haxby(); + ColorMap cmap_default = ColorMap::basic(); + ColorMap cmap_blue_tube = ColorMap::blue_tube(); + ColorMap cmap_red_tube = ColorMap::red_tube(); + ColorMap cmap_rainbow = ColorMap::rainbow(); + + ColorMap custom_map; + custom_map[0] = Color({255,0,0}); + custom_map[0.5] = Color({0,255,0}); + custom_map[1] = Color({0,0,255}); + + double subdivisions = 40.; + fig3.set_axes(axis(0,{-1,subdivisions+1}), axis(1,{-1.25,0.05})); + for (double i=0.; i<=subdivisions; i+=1.0) + { + double ratio = i/subdivisions; + fig3.draw_box({{i,i+1},{-1./5.,0}},{Color::black(),cmap_default.color(ratio)}); + fig3.draw_box({{i,i+1},{-2./5.,-1./5.}},{Color::black(),cmap_haxby.color(ratio)}); + fig3.draw_box({{i,i+1},{-3./5.,-2./5.}},{Color::black(),cmap_rainbow.color(ratio)}); + fig3.draw_box({{i,i+1},{-4./5.,-3./5.}},{Color::black(),cmap_blue_tube.color(ratio)}); + fig3.draw_box({{i,i+1},{-5/5.,-4./5.}},{Color::black(),cmap_red_tube.color(ratio)}); + fig3.draw_box({{i,i+1},{-6./5.,-5./5.}},{Color::black(),custom_map.color(ratio)}); + } + + Figure2D fig4 ("My Figure 4",GraphicOutput::VIBES); + + fig4.set_window_properties({500,50},{500,500}); + fig4.set_axes(axis(0,{-10,10}), axis(1,{-10,10})); + + double a=0.8; + ScalarVar t; + // Fermat's spiral + AnalyticFunction f1 ({t},{a*sqrt(t)*cos(t),a*sqrt(t)*sin(t)}); + AnalyticTraj traj4 ({0,100},f1); + fig4.draw_trajectory(traj4,{ColorMap::rainbow(), ".."}); +} diff --git a/doc/manual/manual/visualization/2d_example_src/src.m b/doc/manual/manual/visualization/2d_example_src/src.m new file mode 100644 index 000000000..1420da740 --- /dev/null +++ b/doc/manual/manual/visualization/2d_example_src/src.m @@ -0,0 +1,112 @@ +import py.codac4matlab.* + +% Graphics can be directly called without a Figure2D instanciation, using "DefaultFigure": + +DefaultFigure().set_window_properties(Vector({600,600}),Vector({300,300})); +DefaultFigure().draw_box(IntervalVector({{2.2,2.5},{2.2,2.5}}),StyleProperties({Color().black(),Color().yellow(0.5)})); +DefaultFigure().draw_AUV(Vector({1,1,3.14/2}),1.,StyleProperties({Color().black(),Color().yellow()},"-..")); +DefaultFigure().draw_motor_boat(Vector({0,0,0}),1.,StyleProperties({Color().black(),Color().yellow()})); +DefaultFigure().draw_tank(Vector({2,1,3.14/2}),1.,StyleProperties({Color().black(),Color().yellow()},"vehicles","-.")); +DefaultFigure().draw_pie(Vector({2,2}),Interval(1.5,2.5),Interval((3*3.14/4)-0.5,(3*3.14/4)+0.5),StyleProperties({Color().blue(),Color().cyan()})); +DefaultFigure().draw_polyline({Vector({2,-0.5}),Vector({4,0.5}),Vector({3,1.5}),Vector({4,2.5}),Vector({3,3})},Color().red()); +DefaultFigure().draw_polygon(Polygon({Vector({2,4.5}),Vector({4,4.5}),Vector({4.2,3.5}),Vector({3.5,3})}),StyleProperties({Color().none(),Color().green(0.5)})); +DefaultFigure().draw_polyline({Vector({-0.8,0}),Vector({0,1.5})},0.2,StyleProperties({Color().red(),Color().black(0.3)})); + +% Last argument corresponds to "StyleProperties" with one or two colors: edge color + (optional) fill color +% Predefined Color objects can be configured with a float parameter for opacity (1=opaque, 0=transparent) + +% Custom figures can also be created: + +fig1 = Figure2D("My figure 1", GraphicOutput().VIBES.union(GraphicOutput().IPE)); +% Here, graphics will be rendered by two tools: both VIBES and IPE +% For VIBES, it requires the VIBes viewer to be launched prior to the execution +% For IPE, it generates a file named "My figure 1.xml" that can be edited with IPE, and converted to PDF + +fig1.set_window_properties(Vector({50,50}),Vector({500,500})); % position, window size +fig1.set_axes(IntervalVector().constant(2,Interval(-10,10))); % bounding box +fig1.draw_box(IntervalVector({{-1,1},{-1,1}}),StyleProperties({Color().green(),Color().red(0.2)})); % drawing a green box with red opacity values inside +fig1.draw_circle(Vector({1,1}),0.5,Color({255,155,5})); % drawing a circle at (1,1) of radius 0.5 with a custom RGB color +fig1.draw_ring(Vector({1,1}),Interval(4,6),Color().red()); % drawing a ring at (1,1) of radius [4,6] with a predefined red color + +fig2 = Figure2D("My figure 2", GraphicOutput().VIBES.union(GraphicOutput().IPE)); +fig2.set_axes(axis(1,Interval(-1,5)), axis(2,Interval(-1,5))); % (axis_id,[range_of_values_on_this_axis]) +fig2.set_window_properties(Vector({250,250}),Vector({500,500})); + +% The previously declared figure "fig2" can now be used as a DefaultFigure +DefaultFigure().set(fig2); +DefaultFigure().draw_box(IntervalVector({{2.2,2.5},{2.2,2.5}}),StyleProperties({Color().black(),Color().green(0.8)})); + +DefaultFigure().set(fig1); +DefaultFigure().draw_box(IntervalVector({{2.2,2.5},{2.2,2.5}}),StyleProperties({Color().blue(),Color().cyan(0.8)})); + +fig2.draw_circle(Vector({2,2}),0.5,StyleProperties({Color().red(),Color().red(0.2)},"z:1.")); % will alway be on top despite being "drawn" first + +fig2.draw_AUV(Vector({1,1,3.14/2}),2.,StyleProperties({Color().black(),Color().yellow()},"w:0.1","vehicles")); +fig2.draw_tank(Vector({2,1,3.14/2}),1.5,StyleProperties({Color().black(),Color().yellow()},"vehicles","w:0.1")); +fig2.draw_motor_boat(Vector({0,0,0}),1.,StyleProperties({Color().black(),Color().yellow()},"vehicles")); +fig2.draw_pie(Vector({2,2}),Interval(1.5,2.5),Interval((3*3.14/4)-0.5,(3*3.14/4)+0.5),StyleProperties({Color().blue(),Color().cyan()})); +fig2.draw_polyline({Vector({2,-0.5}),Vector({4,0.5}),Vector({3,1.5}),Vector({4,2.5}),Vector({3,3})},StyleProperties(Color().red(),"..")); +fig2.draw_polygon(Polygon({Vector({2,4.5}),Vector({4,4.5}),Vector({4.2,3.5}),Vector({3.5,3})}),StyleProperties({Color().none(),Color().green(0.5)})); +fig2.draw_polyline({Vector({-0.8,0}),Vector({0,1.5})},0.2,StyleProperties({Color().red(),Color().black(0.3)})); +fig2.draw_ellipse(Vector({1,1}),Vector({0.5,2.}),0.2,StyleProperties({Color().blue(),Color().blue(0.3)})); +fig2.draw_line(Vector({1,1}),Vector({3,3}),Color().blue()); +fig2.draw_arrow(Vector({3,1}),Vector({2.2,2}),0.2,StyleProperties({Color().red(),Color().black(0.3)})); +fig2.draw_parallelepiped(Parallelepiped(Vector({1.5,2.8}),Matrix({{0.5,0.4},{0,0.2}})),StyleProperties({Color().red(),Color().green(0.5)},"parallelepiped","w:0.1")); + +fig2.draw_zonotope(Zonotope(Vector({4,1.5}),Matrix({{-0.2,-0.06,0.2,0.06,0.01,0.08,0}, ... + {0.1,0.04,0.04,-0.04,-0.03,0.18,0}})),StyleProperties({Color().red(),Color().yellow(0.4)},"zonotope","w:0.05")); + +p_3d = Parallelepiped(Vector({1.2,3.5,2.2}),Matrix({{0.5,0.4,0},{0,0.2,0.1},{0,0,0.3}})); +fig2.draw_zonotope(p_3d.proj({1,2}),StyleProperties({Color().green(),Color().yellow(0.4)},"zonotope")); + +fig2.draw_text("Hello, World!",Vector({-0.5,4.5}),0.2, Color().blue()); + +fig2.draw_raster("logo_codac.png", IntervalVector({{2.5,5},{-1,-0.4}}),StyleProperties("raster")); + +fig2.draw_circle(Vector({0.5,0.5}),0.5,StyleProperties({Color().orange(),Color().orange(0.2)},"z:-1.")); % will alway be in the bottom despite being "drawn" last + +% Colors +% predefined colors without and with opacity +fig2.draw_point(Vector({2,2}), StyleProperties({Color().red(),Color().yellow(0.5)})); +% HTML color without and with opacity +fig2.draw_box(IntervalVector({{2.4,2.9},{2.4,2.9}}),StyleProperties({Color("#da3907"),Color("#da390755")})); +% HSV color without and with opacity +fig2.draw_box(IntervalVector({{2.6,3.1},{2.6,3.1}}),StyleProperties({Color({108,90,78},Model().HSV),Color({108,90,78,20},Model().HSV)})); + +fig3 = Figure2D("ColorMap figure", GraphicOutput().VIBES.union(GraphicOutput().IPE)); +fig3.set_window_properties(Vector({800,250}),Vector({500,500})); + +cmap_haxby = ColorMap().haxby(); +cmap_default = ColorMap().basic(); +cmap_blue_tube = ColorMap().blue_tube(); +cmap_red_tube = ColorMap().red_tube(); +cmap_rainbow = ColorMap().rainbow(); + +custom_map = ColorMap(Model().RGB); +custom_map.set_item(0,Color({255,0,0})); +custom_map.set_item(0.5,Color({0,255,0})); +custom_map.set_item(1,Color({0,0,255})); + +subdivisions = 40; +fig3.set_axes(axis(1,Interval(-1,subdivisions+1)), axis(2,Interval(-1.25,0.05))); + +for i = 0:(subdivisions) + ratio = i / subdivisions; + fig3.draw_box(IntervalVector({{i,i+1},{-1./5.,0}}),StyleProperties({Color().black(),cmap_default.color(ratio)})); + fig3.draw_box(IntervalVector({{i,i+1},{-2./5.,-1./5.}}),StyleProperties({Color().black(),cmap_haxby.color(ratio)})); + fig3.draw_box(IntervalVector({{i,i+1},{-3./5.,-2./5.}}),StyleProperties({Color().black(),cmap_rainbow.color(ratio)})); + fig3.draw_box(IntervalVector({{i,i+1},{-4./5.,-3./5.}}),StyleProperties({Color().black(),cmap_blue_tube.color(ratio)})); + fig3.draw_box(IntervalVector({{i,i+1},{-5./5.,-4./5.}}),StyleProperties({Color().black(),cmap_red_tube.color(ratio)})); + fig3.draw_box(IntervalVector({{i,i+1},{-6./5.,-5./5.}}),StyleProperties({Color().black(),custom_map.color(ratio)})); +end + +fig4 = Figure2D("My Figure 4", GraphicOutput().VIBES); +fig4.set_window_properties(Vector({500,50}),Vector({500,500})); +fig4.set_axes(axis(1,Interval(-10,10)), axis(2,Interval(-10,10))); + +a= 0.8; +t = ScalarVar(); +% Fermat's spiral +f1 = AnalyticFunction({t},vec(a*sqrt(t)*cos(t),a*sqrt(t)*sin(t))); +traj4 = AnalyticTraj(Interval(0,100),f1); +fig4.draw_trajectory(traj4, StyleGradientProperties(ColorMap().rainbow(), "..")); \ No newline at end of file diff --git a/doc/manual/manual/visualization/2d_example_src/src.py b/doc/manual/manual/visualization/2d_example_src/src.py new file mode 100644 index 000000000..a7477e114 --- /dev/null +++ b/doc/manual/manual/visualization/2d_example_src/src.py @@ -0,0 +1,115 @@ +from codac import * +import os + +# Graphics can be directly called without a Figure2D instanciation, using "DefaultFigure": + +DefaultFigure.set_window_properties([600,600],[300,300]) +DefaultFigure.draw_box([[2.2,2.5],[2.2,2.5]],[Color.black(),Color.yellow(0.5)]) +DefaultFigure.draw_AUV([1,1,3.14/2],1.,StyleProperties([Color.black(),Color.yellow()],"-..")) +DefaultFigure.draw_motor_boat([0,0,0], 1., [Color.black(),Color.yellow()]) +DefaultFigure.draw_tank([2,1,3.14/2],1.,StyleProperties([Color.black(),Color.yellow()],"vehicles","-.")) +DefaultFigure.draw_pie([2,2],[1.5,2.5],[(3*3.14/4)-0.5,(3*3.14/4)+0.5],[Color.blue(),Color.cyan()]) +DefaultFigure.draw_polyline([[2,-0.5],[4,0.5],[3,1.5],[4,2.5],[3,3]], Color.red()) +DefaultFigure.draw_polygon([[2,4.5],[4,4.5],[4.2,3.5],[3.5,3]], [Color.none(),Color.green(0.5)]) +DefaultFigure.draw_polyline([[-0.8,0],[0,1.5]], 0.2, [Color.red(),Color.black(0.3)]) + +# Last argument corresponds to "StyleProperties" with one or two colors: edge color + (optional) fill color +# Predefined Color objects can be configured with a float parameter for opacity (1=opaque, 0=transparent) + +# Custom figures can also be created: +fig1 = Figure2D("My figure 1", GraphicOutput.VIBES | GraphicOutput.IPE) +# Here, graphics will be rendered by two tools: both VIBES and IPE +# For VIBES, it requires the VIBes viewer to be launched prior to the execution +# For IPE, it generates a file named "My figure 1.xml" that can be edited with IPE, and converted to PDF + +fig1.set_window_properties([50,50],[500,500]) # position, window size +fig1.set_axes(IntervalVector.constant(2,[-10,10])) # bounding box +fig1.draw_box([[-1,1],[-1,1]],[Color.green(),Color.red(0.2)]) # drawing a green box with red opacity values inside +fig1.draw_circle([1,1],0.5,Color([255,155,5])) # drawing a circle at (1,1) of radius 0.5 with a custom RGB color +fig1.draw_ring([1,1],[4,6],Color.red()) # drawing a ring at (1,1) of radius [4,6] with a predefined red color + +fig2 = Figure2D("My figure 2", GraphicOutput.VIBES | GraphicOutput.IPE) +fig2.set_axes(axis(0,[-1,5]), axis(1,[-1,5])) # (axis_id,[range_of_values_on_this_axis]) +fig2.set_window_properties([250,250],[500,500]) + +# The previously declared figure "fig2" can now be used as a DefaultFigure +DefaultFigure.set(fig2) +DefaultFigure.draw_box([[2.2,2.5],[2.2,2.5]],[Color.black(),Color.green(0.8)]) + +DefaultFigure.set(fig1) +DefaultFigure.draw_box([[2.2,2.5],[2.2,2.5]],[Color.blue(),Color.cyan(0.8)]) + +fig2.draw_circle([2,2],0.5,StyleProperties([Color.red(),Color.red(0.2)], "z:1.")) # will alway be on top despite being "drawn" first + +fig2.draw_AUV([1,1,3.14/2],2.,StyleProperties([Color.black(),Color.yellow()], "w:0.1", "vehicles")) +fig2.draw_tank([2,1,3.14/2],1.5,StyleProperties([Color.black(),Color.yellow()],"vehicles","w:0.1")) +fig2.draw_motor_boat([0,0,0], 1.,StyleProperties([Color.black(),Color.yellow()],"vehicles")) +fig2.draw_pie([2,2],[1.5,2.5],[(3*3.14/4)-0.5,(3*3.14/4)+0.5],[Color.blue(),Color.cyan()]) +fig2.draw_polyline([[2,-0.5],[4,0.5],[3,1.5],[4,2.5],[3,3]], StyleProperties(Color.red(),"..")) +fig2.draw_polygon([[2,4.5],[4,4.5],[4.2,3.5],[3.5,3]], [Color.none(),Color.green(0.5)]) +fig2.draw_polyline([[-0.8,0],[0,1.5]], 0.2, [Color.red(),Color.black(0.3)]) +fig2.draw_ellipse([1,1],[0.5,2], 0.2, [Color.blue(),Color.blue(0.3)]) +fig2.draw_line([1,1],[3,3], Color.blue()) +fig2.draw_arrow([3,1],[2.2,2], 0.2, [Color.red(),Color.black(0.3)]) +fig2.draw_parallelepiped(Parallelepiped([1.5,2.8],Matrix([[0.5,0.4],[0,0.2]])), StyleProperties([Color.red(),Color.green(0.5)],"parallelepiped","w:0.1")) + +fig2.draw_zonotope(Zonotope([4,1.5],Matrix([[-0.2,-0.06,0.2,0.06,0.01,0.08,0], + [0.1,0.04,0.04,-0.04,-0.03,0.18,0]])),StyleProperties([Color.red(),Color.yellow(0.4)],"zonotope","w:0.05")) + +p_3d = Parallelepiped([1.2,3.5,2.2],Matrix([[0.5,0.4,0],[0,0.2,0.1],[0,0,0.3]])) +fig2.draw_zonotope(p_3d.proj([0,1]), StyleProperties([Color.green(),Color.yellow(0.4)],"zonotope")) + +fig2.draw_text("Hello, World!",[-0.5,4.5],0.2, Color.blue()) + +current_folder = os.path.dirname(os.path.abspath(__file__)) +fig2.draw_raster(current_folder+"/logo_codac.png", IntervalVector([[2.5,5],[-1,-0.4]]),StyleProperties("raster")) + +fig2.draw_circle([0.5,0.5],0.5,StyleProperties([Color.orange(),Color.orange(0.2)], "z:-1.")) # will alway be in the bottom despite being "drawn" last + +# Colors +# predefined colors without and with opacity +fig2.draw_point([2,2], [Color.red(),Color.yellow(0.5)]) +# HTML color without and with opacity +fig2.draw_box([[2.4,2.9],[2.4,2.9]],[Color("#da3907"),Color("#da390755")]) +# HSV color without and with opacity +fig2.draw_box([[2.6,3.1],[2.6,3.1]],[Color([108,90,78],Model.HSV),Color([108,90,78,20],Model.HSV)]) +# RGB color auto cast from list without and with opacity +fig2.draw_box([[2.,2.3],[2.6,2.9]],[[255,0,255],[255,0,255,100]]) + +fig3 = Figure2D("ColorMap figure", GraphicOutput.VIBES | GraphicOutput.IPE) +fig3.set_window_properties([800,250],[500,500]) + +cmap_haxby=ColorMap.haxby() +cmap_default=ColorMap.basic() +cmap_blue_tube=ColorMap.blue_tube() +cmap_red_tube=ColorMap.red_tube() +cmap_rainbow=ColorMap.rainbow() + +custom_map = ColorMap(Model.RGB) +custom_map[0] = Color([255,0,0]) +custom_map[0.5] = Color([0,255,0]) +custom_map[1] = Color([0,0,255]) + +subdivisions=40 +fig3.set_axes(axis(0,[-1,subdivisions+1]), axis(1,[-1.25,0.05])) + +for i in range (subdivisions+1): + ratio=i/subdivisions + fig3.draw_box([[i,i+1],[-1/5,0]],[Color.black(),cmap_default.color(ratio)]) + fig3.draw_box([[i,i+1],[-2/5,-1/5]],[Color.black(),cmap_haxby.color(ratio)]) + fig3.draw_box([[i,i+1],[-3/5,-2/5]],[Color.black(),cmap_rainbow.color(ratio)]) + fig3.draw_box([[i,i+1],[-4/5,-3/5]],[Color.black(),cmap_blue_tube.color(ratio)]) + fig3.draw_box([[i,i+1],[-5/5,-4/5]],[Color.black(),cmap_red_tube.color(ratio)]) + fig3.draw_box([[i,i+1],[-6/5,-5/5]],[Color.black(),custom_map.color(ratio)]) + +fig4 = Figure2D("My figure 4", GraphicOutput.VIBES) + +fig4.set_window_properties([500,50],[500,500]) +fig4.set_axes(axis(0,[-10,10]), axis(1,[-10,10])) + +a = 0.8 +t=ScalarVar() +# Fermat's spiral +f1=AnalyticFunction([t], [a*sqrt(t)*cos(t),a*sqrt(t)*sin(t)]) +traj4=AnalyticTraj([0,100],f1) +fig4.draw_trajectory(traj4, StyleGradientProperties(ColorMap.rainbow(),"..")) \ No newline at end of file diff --git a/doc/manual/manual/visualization/3d_example.rst b/doc/manual/manual/visualization/3d_example.rst new file mode 100644 index 000000000..68d03790f --- /dev/null +++ b/doc/manual/manual/visualization/3d_example.rst @@ -0,0 +1,20 @@ +.. _sec-graphics-3d-example: + +3D graphical example +==================== + +Below is an example covering a wide variety of drawing functions, colors, styles etc. + +.. tabs:: + + .. group-tab:: Python + + .. literalinclude:: 3d_example_src/src.py + :language: py + :dedent: 0 + + .. group-tab:: C++ + + .. literalinclude:: 3d_example_src/src.cpp + :language: c++ + :dedent: 0 \ No newline at end of file diff --git a/doc/manual/manual/visualization/3d_example_src/src.cpp b/doc/manual/manual/visualization/3d_example_src/src.cpp new file mode 100644 index 000000000..a77f85495 --- /dev/null +++ b/doc/manual/manual/visualization/3d_example_src/src.cpp @@ -0,0 +1,80 @@ +// The generated .obj files can be visualized on https://3dviewer.net + +#include + +using namespace std; +using namespace codac2; + +int main() +{ + VectorVar x(3); + + AnalyticFunction f { {x}, + { + -sqr(x[2])+2*x[2]*sin(x[2]*x[0])+cos(x[2]*x[1]), + 2*x[2]*cos(x[2]*x[0])-sin(x[2]*x[1]) + } + }; + + + CtcInverse ctc(f, IntervalVector::zero(2)); + auto p_ctc = pave({{0,2},{2,4},{0,10}}, ctc, 0.02); + Figure3D fig_ctc("Paving contractor"); + fig_ctc.draw_paving(p_ctc); + + + SepInverse sep_ellipsoid1( + AnalyticFunction({x}, 0.5*sqr(x[0])+x[0]*x[1]+x[0]*x[2]+2*sqr(x[1])+2*sqr(x[2])), + Interval(0.4,1)); + SepInverse sep_ellipsoid2( + AnalyticFunction({x}, 3*sqr(x[0])+x[0]*x[1]+x[0]*x[2]+sqr(x[1])+sqr(x[2])), + Interval(0,1)); + + auto p_sep = pave({{-1.1,1.1},{-1.1,1.1},{-1.1,1.1}}, sep_ellipsoid1&sep_ellipsoid2, 0.1); + + Figure3D fig_sep("Paving separator"); + fig_sep.draw_axes(0.4); + fig_sep.draw_paving(p_sep); + + + Figure3D fig_examples("3D examples"); + fig_examples.draw_axes(); + fig_examples.draw_axes(0.5); + fig_examples.draw_axes(2.0,{0.5,0.5,0.5}); + fig_examples.draw_triangle({1,0,0},{0,1,0},{0,0,1},{ Color::dark_green(0.5), "triangle1" }); + fig_examples.draw_triangle({2,0,0},{{-1,0,0},{0,1,1},{0,0,-1}}, + {1,0,0},{0,1,0},{0,0,1},Color::purple(0.5)); + fig_examples.draw_sphere({0,0,2},{{-1,0,0},{0,1,1},{0,0,-1}}, + { Color::yellow(0.6), "sphere" }); + fig_examples.draw_arrow({0,2,0},{{-1,0,0},{0,1,1},{0,0,-1}}, + Color::red(1.0)); + fig_examples.draw_car({-1,0,0},0.3*Matrix::Identity(3,3), + { Color::green(0.8), "car" }); + fig_examples.draw_plane({3,0,0},0.5*Matrix::Identity(3,3),true, + { Color::dark_gray(0.8), "plane" }); + + + fig_examples.draw_zonotope({{1.5,1.5,1.5}, + {{0.3,-0.2,-0.2,0.3,-0.1,0.0}, + {0.2,0.1,-0.1,0.0,0.05,0.2}, + {0.4,0.3,0.0,-0.1,0.2,0.1}}}, + { Color::dark_green(1.0), "zonotope" }); + fig_examples.draw_zonotope({{-1.5,-1.5,-1.5}, + {{0.3,-0.2,-0.2,0.3,-0.2,-0.1,0.0,0.0}, + {0.2,0.1,-0.1,0.0,0.0,0.05,0.2,0.0}, + {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1}}}, + { Color::dark_green(1.0), "zonotope2" }); + + fig_examples.draw_parallelepiped({{1,-1.5,1.5}, + {{1,0,0},{0,0.5,0},{0,0.2,0.1}}}, + { Color::blue(0.5), "parallelepiped" }); + + fig_examples.draw_surface({0,-2,0}, 0.5*Matrix::Identity(3,3), Interval(0,2*PI), + 0.05*PI, Interval(0,2*PI), 0.05*PI, + [](double phi,double psi) -> Vector + { return {(1-cos(phi))*sin(phi), + (1-cos(2*phi))*cos(phi)*cos(psi), + (1-cos(phi))*cos(phi)*sin(psi) }; }, + { Color::red(0.6), "example_surface" }); + +} diff --git a/doc/manual/manual/visualization/3d_example_src/src.py b/doc/manual/manual/visualization/3d_example_src/src.py new file mode 100644 index 000000000..4ebf27354 --- /dev/null +++ b/doc/manual/manual/visualization/3d_example_src/src.py @@ -0,0 +1,63 @@ +# The generated .obj files can be visualized on https://3dviewer.net + +from codac import * +import math + +x = VectorVar(3) +f = AnalyticFunction([x], [ + -sqr(x[2])+2*x[2]*sin(x[2]*x[0])+cos(x[2]*x[1]), + 2*x[2]*cos(x[2]*x[0])-sin(x[2]*x[1]) +]) + +ctc = CtcInverse(f, [0,0]) +p_ctc = pave([[0,2],[2,4],[0,10]], ctc, 0.02) +fig_ctc=Figure3D("Paving contractor") +fig_ctc.draw_paving(p_ctc) + +sep_ellipsoid1=SepInverse (AnalyticFunction([x], 0.5*sqr(x[0])+x[0]*x[1]+x[0]*x[2]+2*sqr(x[1])+2*sqr(x[2])),Interval(0.4,1)) +sep_ellipsoid2=SepInverse (AnalyticFunction([x], 3*sqr(x[0])+x[0]*x[1]+x[0]*x[2]+sqr(x[1])+sqr(x[2])),Interval(0.,1)) +p_sep = pave([[-1.5,1.5],[-1.5,1.5],[-1.5,1.5]], sep_ellipsoid1&sep_ellipsoid2, 0.1) +fig_sep = Figure3D("Paving separator") +fig_sep.draw_axes(0.4) +fig_sep.draw_paving(p_sep) + +fig_examples = Figure3D("3D examples") +fig_examples.draw_axes() +fig_examples.draw_axes(0.5) +fig_examples.draw_axes(2.0,[0.5,0.5,0.5]) +fig_examples.draw_triangle([1,0,0],[0,1,0],[0,0,1],StyleProperties(Color.dark_green(0.5),"triangle")) +fig_examples.draw_triangle([2,0,0], + Matrix([[2,0,0],[-1,0,0],[0,1,1]]), + [1,0,0],[0,1,0],[0,0,1],Color.purple(0.5)) +fig_examples.draw_sphere([0,0,2],Matrix([[-1,0,0],[0,1,1],[0,0,-1]]), + StyleProperties(Color.yellow(0.6),"sphere")) +fig_examples.draw_arrow([0,2,0],Matrix([[-1,0,0],[0,1,1],[0,0,-1]]),Color.red(1.0)) +fig_examples.draw_car([-1,0,0],0.3*Matrix.eye(3,3), + StyleProperties(Color.green(0.8),"car")) +fig_examples.draw_plane([3,0,0],0.5*Matrix.eye(3,3),True, + StyleProperties(Color.dark_gray(0.8),"plane")) + +fig_examples.draw_zonotope(Zonotope([1.5,1.5,1.5], + Matrix([[0.3,-0.2,-0.2,0.3,-0.1,0.0],[0.2,0.1,-0.1,0.0,0.05,0.2],[0.4,0.3,0.0,-0.1,0.2,0.1]])),StyleProperties(Color.dark_green(1.0),"zonotope")) +fig_examples.draw_zonotope(Zonotope([-1.5,-1.5,-1.5], + Matrix([[0.3,-0.2,-0.2,0.3,-0.2,-0.1,0.0,0.0], + [0.2,0.1,-0.1,0.0,0.0,0.05,0.2,0.0], + [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1]])), + StyleProperties(Color.dark_green(1.0),"zonotope2")) + +fig_examples.draw_parallelepiped(Parallelepiped([1,-1.5,1.5], + Matrix([[1,0,0],[0,0.5,0],[0,0.2,0.1]])),StyleProperties(Color.blue(0.5),"parallelepiped")) + +def f(phi,psi): + return Vector([(1-math.cos(phi))*math.sin(phi), + (1-math.cos(2*phi))*math.cos(phi)*math.cos(psi), + (1-math.cos(phi))*math.cos(phi)*math.sin(psi)]) + +fig_examples.draw_surface([0,-2,0], 0.5*Matrix.eye(3,3), + [0,2*PI],0.05*PI,[0,2*PI],0.05*PI, + f,StyleProperties(Color.red(0.6),"example_surface")) + +# to flush the files +del fig_ctc +del fig_sep +del fig_examples diff --git a/doc/manual/manual/visualization/colors.rst b/doc/manual/manual/visualization/colors.rst index a728c1b35..aaba29598 100644 --- a/doc/manual/manual/visualization/colors.rst +++ b/doc/manual/manual/visualization/colors.rst @@ -128,7 +128,7 @@ Additionnal methods are available for any useful purpose: fig.draw_box(IntervalVector({{2.6,3.1},{2.6,3.1}}),StyleProperties({Color({108,90,78},Model().HSV),Color({108,90,78,20},Model().HSV)})); -.. _subsec-graphics-colors-styleproperties: +.. _subsec-graphics-colors-style-properties: StyleProperties --------------- @@ -208,7 +208,7 @@ For more information, see :ref:`subsec-graphics-colors-optional-arguments`. fig.draw_box(IntervalVector({{2,5},{2,5}}), StyleProperties(Color().red(), "..", "layer1", "w:0.1", "z:1.5")); % Red edge, dotted line, line width of 0.1, z-value of 1.5 and on layer1 -.. _subsec-graphics-colors-pavingstyle: +.. _subsec-graphics-colors-paving-style: Paving style ------------ @@ -341,7 +341,7 @@ You can also create your own color map : Note that you can add RGB and HSV colors to the same color map. The model of the color map will define the interpolation space. -.. _subsec-graphics-colors-stylegradientproperties: +.. _subsec-graphics-colors-style-gradient-properties: StyleGradientProperties ----------------------- diff --git a/doc/manual/manual/visualization/functions.rst b/doc/manual/manual/visualization/functions.rst index 38c1475ff..93ff22e54 100644 --- a/doc/manual/manual/visualization/functions.rst +++ b/doc/manual/manual/visualization/functions.rst @@ -102,7 +102,7 @@ Geometric shapes ---------------- All the drawable geometric objects can take a last optionnal argument to set up their stroke color, fill color, line style etc. -For further details, refer to :ref:`subsec-graphics-colors-styleproperties`. +For further details, refer to :ref:`subsec-graphics-colors-style-properties`. The geometric shapes that can be drawn and their arguments are listed below : @@ -181,8 +181,8 @@ Trajectories and tubes All the drawable trajectories and tubes can take a last optionnal argument to set up their stroke color, fill color, line style etc. -For further details, refer to :ref:`subsec-graphics-colors-styleproperties` for constant fill and edge color, -and :ref:`subsec-graphics-colors-stylegradientproperties` for the use of a colormap. +For further details, refer to :ref:`subsec-graphics-colors-style-properties` for constant fill and edge color, +and :ref:`subsec-graphics-colors-style-gradient-properties` for the use of a colormap. The trajectories and tubes that can be drawn are listed below: @@ -215,7 +215,7 @@ Vehicles -------- All the drawable vehicles can take a last optionnal argument to set up their stroke color, fill color, line style etc. -For further details, refer to :ref:`subsec-graphics-colors-styleproperties`. +For further details, refer to :ref:`subsec-graphics-colors-style-properties`. The vehicles that can be drawn and their arguments are listed below : @@ -238,7 +238,7 @@ Paving ------ All the drawable pavings can take a last optionnal argument to set up their style for the inside, boundary and outside boxes. -For further details, refer to :ref:`subsec-graphics-colors-pavingstyle`. +For further details, refer to :ref:`subsec-graphics-colors-paving-style`. The paving that can be drawn and their arguments are listed below : @@ -259,7 +259,7 @@ Miscellaneous ------------- Other objects can be drawn and can take a last optionnal argument to set up their stroke color, fill color, line style etc. -For further details, refer to :ref:`subsec-graphics-colors-styleproperties`. +For further details, refer to :ref:`subsec-graphics-colors-style-properties`. These objects are : diff --git a/doc/manual/manual/visualization/index.rst b/doc/manual/manual/visualization/index.rst index b129f8f69..042b77f2c 100644 --- a/doc/manual/manual/visualization/index.rst +++ b/doc/manual/manual/visualization/index.rst @@ -11,4 +11,6 @@ Visualization colors.rst vibes.rst ipe.rst - 3d_visualization.rst \ No newline at end of file + 2d_example.rst + 3d_visualization.rst + 3d_example.rst \ No newline at end of file From e62d2f31182ec0b04b1152d54230882b589ae51c Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 21 Jul 2026 16:30:00 +0200 Subject: [PATCH 09/13] [matlab] graphical example and bindings --- .../manual/visualization/3d_example.rst | 8 +- .../manual/visualization/3d_example_src/src.m | 57 ++ examples/00_graphics/animation_tank.bmp | Bin 0 -> 750054 bytes examples/00_graphics/animation_tank.jpg | Bin 0 -> 10792 bytes examples/00_graphics/animation_tank.png | Bin 0 -> 13175 bytes examples/00_graphics/animation_tank.svg | 832 ++++++++++++++++++ examples/06_graphics_3D/main.cpp | 6 +- examples/06_graphics_3D/main.m | 57 ++ examples/06_graphics_3D/main.py | 2 +- python/src/core/separators/codac2_py_Sep.cpp | 52 +- .../core/separators/codac2_py_SepInter.cpp | 33 +- 11 files changed, 1023 insertions(+), 24 deletions(-) create mode 100644 doc/manual/manual/visualization/3d_example_src/src.m create mode 100644 examples/00_graphics/animation_tank.bmp create mode 100644 examples/00_graphics/animation_tank.jpg create mode 100644 examples/00_graphics/animation_tank.png create mode 100644 examples/00_graphics/animation_tank.svg create mode 100644 examples/06_graphics_3D/main.m diff --git a/doc/manual/manual/visualization/3d_example.rst b/doc/manual/manual/visualization/3d_example.rst index 68d03790f..4ef81d4ff 100644 --- a/doc/manual/manual/visualization/3d_example.rst +++ b/doc/manual/manual/visualization/3d_example.rst @@ -17,4 +17,10 @@ Below is an example covering a wide variety of drawing functions, colors, styles .. literalinclude:: 3d_example_src/src.cpp :language: c++ - :dedent: 0 \ No newline at end of file + :dedent: 0 + + .. group-tab:: Matlab + + .. literalinclude:: 3d_example_src/src.m + :language: matlab + :dedent: 0 diff --git a/doc/manual/manual/visualization/3d_example_src/src.m b/doc/manual/manual/visualization/3d_example_src/src.m new file mode 100644 index 000000000..e0429cff8 --- /dev/null +++ b/doc/manual/manual/visualization/3d_example_src/src.m @@ -0,0 +1,57 @@ +import py.codac4matlab.* + +x = VectorVar(3); +f = AnalyticFunction({x},vec(-sqr(x(3))+2*x(3)*sin(x(3)*x(1))+cos(x(3)*x(2)),2*x(3)*cos(x(3)*x(1))-sin(x(3)*x(2)))); + +ctc = CtcInverse(f,IntervalVector().zero(2)); +p_ctc = pave(IntervalVector({{0,2},{2,4},{0,10}}), ctc, 0.02); +fig_ctc = Figure3D("Paving contractor"); +fig_ctc.draw_paving(p_ctc); + +sep_ellipsoid1 = SepInverse (AnalyticFunction({x},0.5*sqr(x(1))+x(1)*x(2)+x(1)*x(3)+2*sqr(x(2))+2*sqr(x(3))),Interval(0.4,1)); +sep_ellipsoid2 = SepInverse (AnalyticFunction({x},3*sqr(x(1))+x(1)*x(2)+x(1)*x(3)+sqr(x(2))+sqr(x(3))),Interval(0.,1)); +p_sep = pave(IntervalVector({{-1.5,1.5},{-1.5,1.5},{-1.5,1.5}}), sep_ellipsoid1.inter(sep_ellipsoid2), 0.1); +fig_sep = Figure3D("Paving separator"); +fig_sep.draw_axes(0.4); +fig_sep.draw_paving(p_sep); + +eye_3d = Matrix({{1,0,0},{0,1,0},{0,0,1}}); + +fig_examples = Figure3D("3D examples"); +fig_examples.draw_axes(); +fig_examples.draw_axes(0.5); +fig_examples.draw_axes(2.0,Vector([0.5,0.5,0.5])); +fig_examples.draw_triangle(Vector([1,0,0]),Vector([0,1,0]),Vector([0,0,1]),StyleProperties(Color().dark_green(0.5),"triangle")) +fig_examples.draw_triangle(Vector([2,0,0]),Matrix({{-1,0,0},{0,1,1},{0,0,-1}}), Vector([1.,0.,0.]),Vector([0.,1.,0.]),Vector([0.,0.,1.]),StyleProperties(Color().purple(0.5))); +fig_examples.draw_sphere(Vector([0,0,2]),Matrix({{-1,0,0},{0,1,1},{0,0,-1}}), StyleProperties(Color().yellow(0.6),"sphere")); +fig_examples.draw_arrow(Vector([0,2,0]),Matrix({{-1,0,0},{0,1,1},{0,0,-1}}),StyleProperties(Color().red(1.0))); +fig_examples.draw_car(Vector([-1,0,0]),0.3*eye_3d, StyleProperties(Color().green(0.8),"car")); +fig_examples.draw_plane(Vector([3,0,0]),0.5*eye_3d,true,StyleProperties(Color().dark_gray(0.8),"plane")); + +fig_examples.draw_zonotope(Zonotope(Vector([1.5,1.5,1.5]), ... + Matrix({{0.3,-0.2,-0.2,0.3,-0.1,0.0},{0.2,0.1,-0.1,0.0,0.05,0.2},{0.4,0.3,0.0,-0.1,0.2,0.1}})),StyleProperties(Color().dark_green(1.0),"zonotope")); +fig_examples.draw_zonotope(Zonotope(Vector([-1.5,-1.5,-1.5]), ... + Matrix({{0.3,-0.2,-0.2,0.3,-0.2,-0.1,0.0,0.0}, ... + {0.2,0.1,-0.1,0.0,0.0,0.05,0.2,0.0}, ... + {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1}})), ... + StyleProperties(Color().dark_green(1.0),"zonotope2")); + +code = sprintf([ ... + 'import math\n' ... + 'from codac4matlab import Vector\n' ... + 'f = lambda phi, psi: Vector([\n' ... + ' (1-math.cos(phi))*math.sin(phi),\n' ... + ' (1-math.cos(2*phi))*math.cos(phi)*math.cos(psi),\n' ... + ' (1-math.cos(phi))*math.cos(phi)*math.sin(psi)\n' ... + '])']); + +f = pyrun(code, "f"); + +fig_examples.draw_surface( ... + Vector([0, -2, 0]), ... + 0.5 * eye_3d, ... + Interval(0, 2*pi), 0.05*pi, ... + Interval(0, 2*pi), 0.05*pi, ... + f, ... + StyleProperties(Color().red(0.6), "example_surface") ... +); \ No newline at end of file diff --git a/examples/00_graphics/animation_tank.bmp b/examples/00_graphics/animation_tank.bmp new file mode 100644 index 0000000000000000000000000000000000000000..cc501c7d69c943b54e52082c214cf031619b6223 GIT binary patch literal 750054 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 TP)TY#{>Suxg;Bv6jYa-H(T;Vx literal 0 HcmV?d00001 diff --git a/examples/00_graphics/animation_tank.jpg b/examples/00_graphics/animation_tank.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8803ab9eb3899c6a8cafbd9962c813114fb63543 GIT binary patch literal 10792 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 SzqShckIm^{G6vA))c*nHl%$3L literal 0 HcmV?d00001 diff --git a/examples/00_graphics/animation_tank.png b/examples/00_graphics/animation_tank.png new file mode 100644 index 0000000000000000000000000000000000000000..9b84c43a912389233e2b7ea317f3a8dd9a4e2fa5 GIT binary patch literal 13175 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 G*M9?>Ezhd} literal 0 HcmV?d00001 diff --git a/examples/00_graphics/animation_tank.svg b/examples/00_graphics/animation_tank.svg new file mode 100644 index 000000000..2475f32c0 --- /dev/null +++ b/examples/00_graphics/animation_tank.svg @@ -0,0 +1,832 @@ + + +VIBes figure +Graphics generated with VIBes on Fri Jul 3 14:27:33 2026. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +-0.5 + + + + + + + +0 + + + + + + + +0.5 + + + + + + + +1 + + + + + + + +1.5 + + + + + + + +2 + + + + + + + +2.5 + + + + + + + +3 + + + + + + + +3.5 + + + + + + + +4 + + + + + + + +-0.4 + + + + + + + +-0.2 + + + + + + + +0 + + + + + + + +0.2 + + + + + + + +0.4 + + + + + + + +0.6 + + + + + + + +0.8 + + + + + + + +1 + + + + + + + +1.2 + + + + + + + +1.4 + + + + + + diff --git a/examples/06_graphics_3D/main.cpp b/examples/06_graphics_3D/main.cpp index a77f85495..d0fcf103f 100644 --- a/examples/06_graphics_3D/main.cpp +++ b/examples/06_graphics_3D/main.cpp @@ -48,9 +48,9 @@ int main() { Color::yellow(0.6), "sphere" }); fig_examples.draw_arrow({0,2,0},{{-1,0,0},{0,1,1},{0,0,-1}}, Color::red(1.0)); - fig_examples.draw_car({-1,0,0},0.3*Matrix::Identity(3,3), + fig_examples.draw_car({-1,0,0},0.3*Matrix::eye(3,3), { Color::green(0.8), "car" }); - fig_examples.draw_plane({3,0,0},0.5*Matrix::Identity(3,3),true, + fig_examples.draw_plane({3,0,0},0.5*Matrix::eye(3,3),true, { Color::dark_gray(0.8), "plane" }); @@ -69,7 +69,7 @@ int main() {{1,0,0},{0,0.5,0},{0,0.2,0.1}}}, { Color::blue(0.5), "parallelepiped" }); - fig_examples.draw_surface({0,-2,0}, 0.5*Matrix::Identity(3,3), Interval(0,2*PI), + fig_examples.draw_surface({0,-2,0}, 0.5*Matrix::eye(3,3), Interval(0,2*PI), 0.05*PI, Interval(0,2*PI), 0.05*PI, [](double phi,double psi) -> Vector { return {(1-cos(phi))*sin(phi), diff --git a/examples/06_graphics_3D/main.m b/examples/06_graphics_3D/main.m new file mode 100644 index 000000000..e0429cff8 --- /dev/null +++ b/examples/06_graphics_3D/main.m @@ -0,0 +1,57 @@ +import py.codac4matlab.* + +x = VectorVar(3); +f = AnalyticFunction({x},vec(-sqr(x(3))+2*x(3)*sin(x(3)*x(1))+cos(x(3)*x(2)),2*x(3)*cos(x(3)*x(1))-sin(x(3)*x(2)))); + +ctc = CtcInverse(f,IntervalVector().zero(2)); +p_ctc = pave(IntervalVector({{0,2},{2,4},{0,10}}), ctc, 0.02); +fig_ctc = Figure3D("Paving contractor"); +fig_ctc.draw_paving(p_ctc); + +sep_ellipsoid1 = SepInverse (AnalyticFunction({x},0.5*sqr(x(1))+x(1)*x(2)+x(1)*x(3)+2*sqr(x(2))+2*sqr(x(3))),Interval(0.4,1)); +sep_ellipsoid2 = SepInverse (AnalyticFunction({x},3*sqr(x(1))+x(1)*x(2)+x(1)*x(3)+sqr(x(2))+sqr(x(3))),Interval(0.,1)); +p_sep = pave(IntervalVector({{-1.5,1.5},{-1.5,1.5},{-1.5,1.5}}), sep_ellipsoid1.inter(sep_ellipsoid2), 0.1); +fig_sep = Figure3D("Paving separator"); +fig_sep.draw_axes(0.4); +fig_sep.draw_paving(p_sep); + +eye_3d = Matrix({{1,0,0},{0,1,0},{0,0,1}}); + +fig_examples = Figure3D("3D examples"); +fig_examples.draw_axes(); +fig_examples.draw_axes(0.5); +fig_examples.draw_axes(2.0,Vector([0.5,0.5,0.5])); +fig_examples.draw_triangle(Vector([1,0,0]),Vector([0,1,0]),Vector([0,0,1]),StyleProperties(Color().dark_green(0.5),"triangle")) +fig_examples.draw_triangle(Vector([2,0,0]),Matrix({{-1,0,0},{0,1,1},{0,0,-1}}), Vector([1.,0.,0.]),Vector([0.,1.,0.]),Vector([0.,0.,1.]),StyleProperties(Color().purple(0.5))); +fig_examples.draw_sphere(Vector([0,0,2]),Matrix({{-1,0,0},{0,1,1},{0,0,-1}}), StyleProperties(Color().yellow(0.6),"sphere")); +fig_examples.draw_arrow(Vector([0,2,0]),Matrix({{-1,0,0},{0,1,1},{0,0,-1}}),StyleProperties(Color().red(1.0))); +fig_examples.draw_car(Vector([-1,0,0]),0.3*eye_3d, StyleProperties(Color().green(0.8),"car")); +fig_examples.draw_plane(Vector([3,0,0]),0.5*eye_3d,true,StyleProperties(Color().dark_gray(0.8),"plane")); + +fig_examples.draw_zonotope(Zonotope(Vector([1.5,1.5,1.5]), ... + Matrix({{0.3,-0.2,-0.2,0.3,-0.1,0.0},{0.2,0.1,-0.1,0.0,0.05,0.2},{0.4,0.3,0.0,-0.1,0.2,0.1}})),StyleProperties(Color().dark_green(1.0),"zonotope")); +fig_examples.draw_zonotope(Zonotope(Vector([-1.5,-1.5,-1.5]), ... + Matrix({{0.3,-0.2,-0.2,0.3,-0.2,-0.1,0.0,0.0}, ... + {0.2,0.1,-0.1,0.0,0.0,0.05,0.2,0.0}, ... + {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.1}})), ... + StyleProperties(Color().dark_green(1.0),"zonotope2")); + +code = sprintf([ ... + 'import math\n' ... + 'from codac4matlab import Vector\n' ... + 'f = lambda phi, psi: Vector([\n' ... + ' (1-math.cos(phi))*math.sin(phi),\n' ... + ' (1-math.cos(2*phi))*math.cos(phi)*math.cos(psi),\n' ... + ' (1-math.cos(phi))*math.cos(phi)*math.sin(psi)\n' ... + '])']); + +f = pyrun(code, "f"); + +fig_examples.draw_surface( ... + Vector([0, -2, 0]), ... + 0.5 * eye_3d, ... + Interval(0, 2*pi), 0.05*pi, ... + Interval(0, 2*pi), 0.05*pi, ... + f, ... + StyleProperties(Color().red(0.6), "example_surface") ... +); \ No newline at end of file diff --git a/examples/06_graphics_3D/main.py b/examples/06_graphics_3D/main.py index 4ebf27354..a92d701bd 100644 --- a/examples/06_graphics_3D/main.py +++ b/examples/06_graphics_3D/main.py @@ -27,7 +27,7 @@ fig_examples.draw_axes(2.0,[0.5,0.5,0.5]) fig_examples.draw_triangle([1,0,0],[0,1,0],[0,0,1],StyleProperties(Color.dark_green(0.5),"triangle")) fig_examples.draw_triangle([2,0,0], - Matrix([[2,0,0],[-1,0,0],[0,1,1]]), + Matrix([[-1,0,0],[0,1,1],[0,0,-1]]), [1,0,0],[0,1,0],[0,0,1],Color.purple(0.5)) fig_examples.draw_sphere([0,0,2],Matrix([[-1,0,0],[0,1,1],[0,0,-1]]), StyleProperties(Color.yellow(0.6),"sphere")) diff --git a/python/src/core/separators/codac2_py_Sep.cpp b/python/src/core/separators/codac2_py_Sep.cpp index b3dcde5ee..ca3ca25be 100644 --- a/python/src/core/separators/codac2_py_Sep.cpp +++ b/python/src/core/separators/codac2_py_Sep.cpp @@ -82,21 +82,49 @@ py::class_ export_Sep(py::module& m) py::return_value_policy::reference_internal, py::keep_alive<1,0>()) + ; + // Intersection of separators + if constexpr(!FOR_MATLAB) + { + py_sep + .def("__and__", [](const SepBase& s1, const SepBase& s2) + { + return SepInter(s1.copy(),s2.copy()); + }, + SEPINTER_OPERATORINTER_CONST_S1_REF_CONST_S2_REF) + + .def("__and__", [](const SepBase& s1, const IntervalVector& x2) + { + auto s2 = SepWrapper(x2); + return SepInter(s1.copy(),s2.copy()); + }, + SEPINTER_OPERATORINTER_CONST_INTERVALVECTOR_REF_CONST_S2_REF) + + ; + } + + if constexpr(FOR_MATLAB) + { + py_sep + .def("inter", [](const SepBase& s1, const SepBase& s2) + { + return SepInter(s1.copy(),s2.copy()); + }, + SEPINTER_OPERATORINTER_CONST_S1_REF_CONST_S2_REF) + + .def("inter", [](const SepBase& s1, const IntervalVector& x2) + { + auto s2 = SepWrapper(x2); + return SepInter(s1.copy(),s2.copy()); + }, + SEPINTER_OPERATORINTER_CONST_INTERVALVECTOR_REF_CONST_S2_REF) + + ; + } - .def("__and__", [](const SepBase& s1, const SepBase& s2) - { - return SepInter(s1.copy(),s2.copy()); - }, - SEPINTER_OPERATORINTER_CONST_S1_REF_CONST_S2_REF) - - .def("__and__", [](const SepBase& s1, const IntervalVector& x2) - { - auto s2 = SepWrapper(x2); - return SepInter(s1.copy(),s2.copy()); - }, - SEPINTER_OPERATORINTER_CONST_INTERVALVECTOR_REF_CONST_S2_REF) + py_sep .def("__rand__", [](const SepBase& s1, const IntervalVector& x2) { auto s2 = SepWrapper(x2); diff --git a/python/src/core/separators/codac2_py_SepInter.cpp b/python/src/core/separators/codac2_py_SepInter.cpp index d650f67c1..25792ac95 100644 --- a/python/src/core/separators/codac2_py_SepInter.cpp +++ b/python/src/core/separators/codac2_py_SepInter.cpp @@ -47,11 +47,30 @@ void export_SepInter(py::module& m, py::class_& pysep) BOXPAIR_SEPINTER_SEPARATE_CONST_INTERVALVECTOR_REF_CONST, "x"_a) - .def("__iand__", [](SepInter& s1, const SepBase& s2) - { - s1 &= s2.copy(); - return s1; - }, - SEPINTER_REF_SEPINTER_OPERATORINTEREQ_CONST_S_REF) - ; + ; + + if constexpr(!FOR_MATLAB) + { + exported + + .def("__iand__", [](SepInter& s1, const SepBase& s2) + { + s1 &= s2.copy(); + return s1; + }, + SEPINTER_REF_SEPINTER_OPERATORINTEREQ_CONST_S_REF) + ; + } + + if constexpr(FOR_MATLAB) + { + exported + .def("self_inter", [](SepInter& s1, const SepBase& s2) + { + s1 &= s2.copy(); + return s1; + }, + SEPINTER_REF_SEPINTER_OPERATORINTEREQ_CONST_S_REF) + ; + } } \ No newline at end of file From 055ee10dd94eebe0a214061fe1e1e52bf5cd6d6f Mon Sep 17 00:00:00 2001 From: godardma Date: Tue, 21 Jul 2026 16:31:29 +0200 Subject: [PATCH 10/13] [matlab] graphical example and bindings --- examples/00_graphics/animation_tank.bmp | Bin 750054 -> 0 bytes examples/00_graphics/animation_tank.jpg | Bin 10792 -> 0 bytes examples/00_graphics/animation_tank.png | Bin 13175 -> 0 bytes examples/00_graphics/animation_tank.svg | 832 ------------------------ 4 files changed, 832 deletions(-) delete mode 100644 examples/00_graphics/animation_tank.bmp delete mode 100644 examples/00_graphics/animation_tank.jpg delete mode 100644 examples/00_graphics/animation_tank.png delete mode 100644 examples/00_graphics/animation_tank.svg diff --git a/examples/00_graphics/animation_tank.bmp b/examples/00_graphics/animation_tank.bmp deleted file mode 100644 index cc501c7d69c943b54e52082c214cf031619b6223..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 750054 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 TP)TY#{>Suxg;Bv6jYa-H(T;Vx diff --git a/examples/00_graphics/animation_tank.jpg b/examples/00_graphics/animation_tank.jpg deleted file mode 100644 index 8803ab9eb3899c6a8cafbd9962c813114fb63543..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10792 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 SzqShckIm^{G6vA))c*nHl%$3L diff --git a/examples/00_graphics/animation_tank.png b/examples/00_graphics/animation_tank.png deleted file mode 100644 index 9b84c43a912389233e2b7ea317f3a8dd9a4e2fa5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13175 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 G*M9?>Ezhd} diff --git a/examples/00_graphics/animation_tank.svg b/examples/00_graphics/animation_tank.svg deleted file mode 100644 index 2475f32c0..000000000 --- a/examples/00_graphics/animation_tank.svg +++ /dev/null @@ -1,832 +0,0 @@ - - -VIBes figure -Graphics generated with VIBes on Fri Jul 3 14:27:33 2026. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --0.5 - - - - - - - -0 - - - - - - - -0.5 - - - - - - - -1 - - - - - - - -1.5 - - - - - - - -2 - - - - - - - -2.5 - - - - - - - -3 - - - - - - - -3.5 - - - - - - - -4 - - - - - - - --0.4 - - - - - - - --0.2 - - - - - - - -0 - - - - - - - -0.2 - - - - - - - -0.4 - - - - - - - -0.6 - - - - - - - -0.8 - - - - - - - -1 - - - - - - - -1.2 - - - - - - - -1.4 - - - - - - From d30ef6a16a2a3b4b9ce1a316e914910d570e42ea Mon Sep 17 00:00:00 2001 From: godardma Date: Wed, 22 Jul 2026 14:47:53 +0200 Subject: [PATCH 11/13] [doc] rewrite 3D figure doc to avoid including Doxygen doc --- .../manual/visualization/3d_visualization.rst | 143 ++++++++++++------ 1 file changed, 98 insertions(+), 45 deletions(-) diff --git a/doc/manual/manual/visualization/3d_visualization.rst b/doc/manual/manual/visualization/3d_visualization.rst index bfe22788b..b092d5bc7 100644 --- a/doc/manual/manual/visualization/3d_visualization.rst +++ b/doc/manual/manual/visualization/3d_visualization.rst @@ -36,86 +36,139 @@ Drawing functions Below are the detailled available drawing functions. The shapes that can be drawn are: Geometric shapes - - Triangle - - Parallelogram - - Star-shaped polygon - Box - - Parallelepiped - - Zonotope + - Sphere - Arrow + - Zonotope + - Parallelogram + - Parallelepiped + - Triangle + - Star-shaped polygon - Parametric surface - - Sphere + +Vehicles + - Car + - Plane Paving - PavingOut (Paving with contractors) - PavingInOut (Paving with separators) - Subpaving -Vehicles - - Car - - Plane - -In addition, a function ``draw_axes`` is available to draw the three axes of the 3D space. -.. doxygenfunction:: codac2::Figure3D::draw_axes(double) - :project: codac Note that only the stroke color is used in all of the supported drawing functions. +In addition, a function ``draw_axes`` is available to draw the three axes of the 3D space. It can take two arguments : + +- float : the size of the axes +- Vector : the origin of the axes + + Geometric shapes ---------------- -.. doxygenfunction:: codac2::Figure3D::draw_triangle(const Vector&, const Matrix&, const Vector&, const Vector&, const Vector&, const StyleProperties&) - :project: codac +All the drawable geometric objects can take a last optionnal argument to set up their stroke color. +For further details, refer to :ref:`subsec-graphics-colors-style-properties`. -.. doxygenfunction:: codac2::Figure3D::draw_triangle(const Vector&, const Vector&, const Vector&, const StyleProperties&) - :project: codac +The geometric shapes that can be drawn and their arguments are listed below : + +- draw_box + + - IntervalVector : the box to draw + +- draw_sphere + + - Vector : the center of the sphere + - Matrix : the scaling matrix + +- draw_arrow + + - Vector : start of the arrow + - Matrix : orientation of the arrow (first column) + +- draw_zonotope + + - Zonotope: the zonotope to draw + +- draw_parallelepiped + + - Parallelepiped : the parallelepiped to draw + +- draw_parallelogram (defined by :math:`c + A (p + [-1,1]*v1 + [-1,1]*v2)`) + + - Vector : c, the translation + - Matrix : A, the scaling + - Vector : p, base point + - Vector : v1, first generator + - Vector : v2, second generator + +- draw_triangle + + - Vector : first point + - Vector : second point + - Vector : third point + +- draw_triangle + + - Vector : translation applied to the triangle + - Matrix : scaling matrix applied to the triangle + - Vector : first point + - Vector : second point + - Vector : third point The ``draw_polygon`` can be used to draw a `star-shaped polygon `_ when the vectors are coplanar, and more generally a sequence of adjacent triangles sharing a same vertex. -.. doxygenfunction:: codac2::Figure3D::draw_polygon(const Vector&, const Matrix&, const std::vector&, const StyleProperties&) - :project: codac +- draw_polygon -.. doxygenfunction:: codac2::Figure3D::draw_box(const IntervalVector&, const StyleProperties&) - :project: codac + - Vector : translation applied to the polygon + - Matrix : scaling matrix applied to the polygon + - vector : vector where each element is a point of the polygon to draw -.. doxygenfunction:: codac2::Figure3D::draw_parallelogram(const Vector&, const Matrix&, const Vector&, const Vector&, const Vector&, const StyleProperties&) - :project: codac +- draw_surface -.. doxygenfunction:: codac2::Figure3D::draw_parallelepiped(const Parallelepiped&, const StyleProperties&) - :project: codac + - Vector : the translation applied to the surface + - Matrix : scaling applied to the surface + - Interval : bounds of p1 + - double : incrementation for p1 + - Interval : bounds of p2 + - double : incrementation for p2 + - function -\> Vector : the function of the surface, linking each (p1,p2) to a 3D point -.. doxygenfunction:: codac2::Figure3D::draw_zonotope(const Zonotope&, const StyleProperties&) - :project: codac +Vehicles +-------- -.. doxygenfunction:: codac2::Figure3D::draw_arrow(const Vector&, const Matrix& A, const StyleProperties&) - :project: codac +All the drawable vehicles can take a last optionnal argument to set up their stroke color. +For further details, refer to :ref:`subsec-graphics-colors-style-properties`. -.. doxygenfunction:: codac2::Figure3D::draw_surface(const Vector&, const Matrix&, const Interval&, double, const Interval&, double, std::function, const StyleProperties&) - :project: codac +The vehicles that can be drawn and their arguments are listed below : -.. doxygenfunction:: codac2::Figure3D::draw_sphere(const Vector&, const Matrix&, const StyleProperties&) - :project: codac +- draw_car + + - Vector : center of the car + - Matrix : orientation of the car + +- draw_plane + + - Vector : center of the plane + - Matrix : orientation of the plane + - bool : (optionnal) defines if the yaw axis is up, default to true Paving ------ -.. doxygenfunction:: codac2::Figure3D::draw_paving(const PavingOut& p, const StyleProperties&) - :project: codac +When a paving is drawn, only the inside and boundary boxes are drawn. This is done to avoid outside boxes masking them. -.. doxygenfunction:: codac2::Figure3D::draw_paving(const PavingInOut& p, const StyleProperties&, const StyleProperties&) - :project: codac +If only one type of paving is drawn (for example a paving with contractors), only one :ref:`subsec-graphics-colors-style-properties` can be defined to choose its edge color. +If two types are drawn (boundary and inside), two :ref:`subsec-graphics-colors-style-properties` can be passed to select both colors. -.. doxygenfunction:: codac2::Figure3D::draw_subpaving(const Subpaving

&, const StyleProperties&) - :project: codac +The paving that can be drawn and their arguments are listed below : -Vehicles --------- +- draw_paving -.. doxygenfunction:: codac2::Figure3D::draw_car(const Vector&, const Matrix&, const StyleProperties&) - :project: codac + - PavingOut | PavingInOut : the paving to draw -.. doxygenfunction:: codac2::Figure3D::draw_plane(const Vector&, const Matrix&, bool, const StyleProperties&) - :project: codac +- draw_subpaving + - Subpaving : the subpaving to draw \ No newline at end of file From 0e957accb59f60e7a3ef4ef534056d4bec8f52b1 Mon Sep 17 00:00:00 2001 From: godardma Date: Wed, 22 Jul 2026 14:49:32 +0200 Subject: [PATCH 12/13] [doc] minor update --- doc/manual/manual/visualization/3d_example_src/src.m | 2 ++ doc/manual/manual/visualization/3d_visualization.rst | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/manual/manual/visualization/3d_example_src/src.m b/doc/manual/manual/visualization/3d_example_src/src.m index e0429cff8..e0cccc1d0 100644 --- a/doc/manual/manual/visualization/3d_example_src/src.m +++ b/doc/manual/manual/visualization/3d_example_src/src.m @@ -1,3 +1,5 @@ +% The generated .obj files can be visualized on https://3dviewer.net + import py.codac4matlab.* x = VectorVar(3); diff --git a/doc/manual/manual/visualization/3d_visualization.rst b/doc/manual/manual/visualization/3d_visualization.rst index b092d5bc7..8c2ee2766 100644 --- a/doc/manual/manual/visualization/3d_visualization.rst +++ b/doc/manual/manual/visualization/3d_visualization.rst @@ -40,8 +40,8 @@ Geometric shapes - Sphere - Arrow - Zonotope - - Parallelogram - Parallelepiped + - Parallelogram - Triangle - Star-shaped polygon - Parametric surface From 6b0ffe8483cf4cfe1febe27598ecfea86ba4ee3f Mon Sep 17 00:00:00 2001 From: godardma Date: Fri, 24 Jul 2026 17:18:58 +0200 Subject: [PATCH 13/13] [examples] modified custom Sep to return a BoxPair --- .gitignore | 4 ++++ examples/custom_sep/custom_sep.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c35bf0562..64523ced0 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,10 @@ wheelhouse/ # Graphics files examples/**/*.xml +examples/**/*.bmp +examples/**/*.png +examples/**/*.jpg +examples/**/*.svg *.ipe # Matlab files diff --git a/examples/custom_sep/custom_sep.py b/examples/custom_sep/custom_sep.py index 850c4969d..4bb71a10c 100644 --- a/examples/custom_sep/custom_sep.py +++ b/examples/custom_sep/custom_sep.py @@ -10,7 +10,7 @@ def __init__(self, S_): def separate(self, x): inner,outer = self.S.separate(x) # separates x into two boxes - return [outer,inner] # inner/outer boxes are permuted + return BoxPair(inner,outer) # inner/outer boxes are permuted # Trying this custom separator