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/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..4ef81d4ff --- /dev/null +++ b/doc/manual/manual/visualization/3d_example.rst @@ -0,0 +1,26 @@ +.. _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 + + .. group-tab:: Matlab + + .. literalinclude:: 3d_example_src/src.m + :language: matlab + :dedent: 0 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.m b/doc/manual/manual/visualization/3d_example_src/src.m new file mode 100644 index 000000000..e0cccc1d0 --- /dev/null +++ b/doc/manual/manual/visualization/3d_example_src/src.m @@ -0,0 +1,59 @@ +% The generated .obj files can be visualized on https://3dviewer.net + +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/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/3d_visualization.rst b/doc/manual/manual/visualization/3d_visualization.rst index bfe22788b..8c2ee2766 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 + - Parallelepiped + - Parallelogram + - 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 diff --git a/doc/manual/manual/visualization/colors.rst b/doc/manual/manual/visualization/colors.rst index 4a44c86c7..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-style-properties: StyleProperties --------------- @@ -208,6 +208,48 @@ 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-paving-style: +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 ---------- @@ -299,6 +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-style-gradient-properties: StyleGradientProperties ----------------------- 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/doc/manual/manual/visualization/functions.rst b/doc/manual/manual/visualization/functions.rst index b3efcc917..93ff22e54 100644 --- a/doc/manual/manual/visualization/functions.rst +++ b/doc/manual/manual/visualization/functions.rst @@ -101,115 +101,175 @@ 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-style-properties`. -.. 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-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: + +- plot_trajectory + + - SampledTraj | AnalyticTraj : the 1D trajectory to draw (x-axis is the time) -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. +- plot_trajectories -.. doxygenfunction:: codac2::Figure2D::draw_trajectory(const SampledTraj&, const StyleGradientProperties&) - :project: codac + - SampledTraj | AnalyticTraj : the nD trajectory to draw component by component (x-axis is the time) -.. doxygenfunction:: codac2::Figure2D::draw_trajectory(const AnalyticTraj&, const StyleGradientProperties&) - :project: codac +- plot_tube -.. doxygenfunction:: codac2::Figure2D::draw_tube(const SlicedTube&, const StyleProperties&, int) - :project: codac + - SlicedTube : the 1D tube to draw (x-axis is the time) -.. doxygenfunction:: codac2::Figure2D::draw_tube(const SlicedTube&, const StyleGradientProperties&, int) - :project: codac +- plot_tube -.. doxygenfunction:: codac2::Figure2D::plot_tube(const SlicedTube&, const StyleProperties&) - :project: codac + - SlicedTube : the 1D tube to draw (x-axis is the time) + - SlicedTube : the derivative of the tube to draw -.. doxygenfunction:: codac2::Figure2D::plot_tube(const SlicedTube&, const SlicedTube&, const StyleProperties&) - :project: codac +- 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-style-properties`. -.. doxygenfunction:: codac2::Figure2D::draw_AUV(const Vector&, float, const StyleProperties&) - :project: codac +The vehicles that can be drawn and their arguments are listed below : -.. doxygenfunction:: codac2::Figure2D::draw_motor_boat(const Vector&, float, const StyleProperties&) - :project: codac +- draw_tank -Miscellaneous -------------- + - Vector : the 3D state of the tank to draw (x,y,theta in radian) + - float : the size of the tank -.. doxygenfunction:: codac2::Figure2D::draw_text(const std::string&, const Vector&, double, const StyleProperties&) - :project: codac +- draw_AUV -.. doxygenfunction:: codac2::Figure2D::draw_raster(const std::string&, const IntervalVector&, const StyleProperties&) - :project: codac + - 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 ------ -.. doxygenfunction:: codac2::Figure2D::draw_paving(const PavingOut&, const PavingStyle&) - :project: codac +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-paving-style`. + +The paving that can be drawn and their arguments are listed below : + +- draw_paving + + - PavingOut | PavingInOut : the paving to draw + +- draw_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-style-properties`. + +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 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 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/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/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 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 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 38c465bbf..3b5da24b3 100644 --- a/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp +++ b/src/graphics/3rd/ipe/codac2_Figure2D_IPE.cpp @@ -16,7 +16,7 @@ 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 +25,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 +156,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() @@ -190,10 +176,26 @@ void Figure2D_IPE::clear() // clear _color map and layers _colors.clear(); _layers.clear(); + _items.clear(); init_figure(); } +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) { 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: