summaryrefslogtreecommitdiff
path: root/modules/renderer/src
diff options
context:
space:
mode:
authorShashank2017-05-29 12:40:26 +0530
committerShashank2017-05-29 12:40:26 +0530
commit0345245e860375a32c9a437c4a9d9cae807134e9 (patch)
treead51ecbfa7bcd3cc5f09834f1bb8c08feaa526a4 /modules/renderer/src
downloadscilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.tar.gz
scilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.tar.bz2
scilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.zip
CMSCOPE changed
Diffstat (limited to 'modules/renderer/src')
-rwxr-xr-xmodules/renderer/src/c/DllmainRenderer.c33
-rwxr-xr-xmodules/renderer/src/cpp/.deps/.dirstamp0
-rwxr-xr-xmodules/renderer/src/cpp/.deps/libscirenderer_la-GetJavaProperty.Plo350
-rwxr-xr-xmodules/renderer/src/cpp/.deps/libscirenderer_la-JavaInteraction.Plo350
-rwxr-xr-xmodules/renderer/src/cpp/.deps/libscirenderer_la-RendererFontManager.Plo357
-rwxr-xr-xmodules/renderer/src/cpp/.deps/libscirenderer_la-SetJavaProperty.Plo364
-rwxr-xr-xmodules/renderer/src/cpp/.dirstamp0
-rwxr-xr-xmodules/renderer/src/cpp/.libs/libscirenderer_la-GetJavaProperty.obin0 -> 29832 bytes
-rwxr-xr-xmodules/renderer/src/cpp/.libs/libscirenderer_la-JavaInteraction.obin0 -> 25872 bytes
-rwxr-xr-xmodules/renderer/src/cpp/.libs/libscirenderer_la-RendererFontManager.obin0 -> 50432 bytes
-rwxr-xr-xmodules/renderer/src/cpp/.libs/libscirenderer_la-SetJavaProperty.obin0 -> 24392 bytes
-rwxr-xr-xmodules/renderer/src/cpp/GetJavaProperty.cpp86
-rwxr-xr-xmodules/renderer/src/cpp/JavaInteraction.cpp36
-rwxr-xr-xmodules/renderer/src/cpp/RendererFontManager.cpp182
-rwxr-xr-xmodules/renderer/src/cpp/SetJavaProperty.cpp42
-rwxr-xr-xmodules/renderer/src/cpp/libscirenderer_la-GetJavaProperty.lo12
-rwxr-xr-xmodules/renderer/src/cpp/libscirenderer_la-JavaInteraction.lo12
-rwxr-xr-xmodules/renderer/src/cpp/libscirenderer_la-RendererFontManager.lo12
-rwxr-xr-xmodules/renderer/src/cpp/libscirenderer_la-SetJavaProperty.lo12
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/CallRenderer.java204
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/AxisDrawer.java371
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/DataManager.java572
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/DrawerVisitor.java1334
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/FecDrawer.java291
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/ScilabTextureManager.java201
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/arrowDrawing/ArrowDrawer.java537
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/AxesDrawer.java1468
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/Geometries.java113
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/AxesRulerDrawer.java696
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/AxesRulerSpriteFactory.java256
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/RulerDrawerManager.java160
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/UserDefineGraduation.java167
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/contouredObject/ContouredObjectDrawer.java109
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/datatip/DatatipTextDrawer.java366
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/editor/FigureFrame.java49
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/editor/SciTreeModel.java156
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/DragPointRubberBox.java135
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/DragZoomRotateInteraction.java373
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/FigureInteraction.java140
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/InteractionManager.java124
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/OnePointRubberBox.java72
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/PointRubberBox.java24
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/RubberBox.java539
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/RubberBoxListener.java25
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/TwoPointsRubberBox.java30
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/ZoomRubberBox.java109
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/AbstractPointComputer.java131
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/CubeFacesPointComputer.java81
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/HelpersGeometry.java112
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointAComputer.java60
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointBComputer.java122
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointCComputer.java72
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointComputer.java53
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointDComputer.java71
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/AxisLabelPositioner.java320
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelManager.java411
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelPositioner.java502
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelSpriteDrawer.java76
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/TitlePositioner.java136
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/YAxisLabelPositioner.java47
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/legend/LegendDrawer.java753
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/legend/LegendSpriteDrawer.java96
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/mark/MarkSpriteFactory.java495
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/mark/MarkSpriteManager.java126
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/postRendering/PostRendered.java11
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/text/TextManager.java649
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/text/TextSpriteDrawer.java112
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/BufferAllocation.java100
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/ColorFactory.java52
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/FormattedTextSpriteDrawer.java121
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/LightingUtils.java119
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/OutOfMemoryException.java23
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/ScaleUtils.java131
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/TextObjectSpriteDrawer.java405
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/utils/textRendering/FontManager.java432
-rwxr-xr-xmodules/renderer/src/java/org/scilab/modules/renderer/utils/textRendering/XlFontManager.java130
-rwxr-xr-xmodules/renderer/src/jni/.deps/.dirstamp0
-rwxr-xr-xmodules/renderer/src/jni/.deps/libscirenderer_la-CallRenderer.Plo341
-rwxr-xr-xmodules/renderer/src/jni/.deps/libscirenderer_la-XlFontManager.Plo341
-rwxr-xr-xmodules/renderer/src/jni/.dirstamp0
-rwxr-xr-xmodules/renderer/src/jni/.libs/libscirenderer_la-CallRenderer.obin0 -> 411744 bytes
-rwxr-xr-xmodules/renderer/src/jni/.libs/libscirenderer_la-XlFontManager.obin0 -> 286344 bytes
-rwxr-xr-xmodules/renderer/src/jni/CallRenderer.cpp513
-rwxr-xr-xmodules/renderer/src/jni/CallRenderer.hxx202
-rwxr-xr-xmodules/renderer/src/jni/XlFontManager.cpp435
-rwxr-xr-xmodules/renderer/src/jni/XlFontManager.giws.xml38
-rwxr-xr-xmodules/renderer/src/jni/XlFontManager.hxx208
-rwxr-xr-xmodules/renderer/src/jni/libscirenderer_la-CallRenderer.lo12
-rwxr-xr-xmodules/renderer/src/jni/libscirenderer_la-XlFontManager.lo12
-rwxr-xr-xmodules/renderer/src/jni/renderer.giws.xml40
-rwxr-xr-xmodules/renderer/src/norenderer/norenderer.h18
-rwxr-xr-xmodules/renderer/src/norenderer/norenderer.rc97
92 files changed, 18675 insertions, 0 deletions
diff --git a/modules/renderer/src/c/DllmainRenderer.c b/modules/renderer/src/c/DllmainRenderer.c
new file mode 100755
index 000000000..fd2dc1763
--- /dev/null
+++ b/modules/renderer/src/c/DllmainRenderer.c
@@ -0,0 +1,33 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2007 - INRIA - Allan CORNET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+#include <windows.h>
+/*--------------------------------------------------------------------------*/
+#pragma comment(lib,"../../bin/libintl.lib")
+/*--------------------------------------------------------------------------*/
+int WINAPI DllMain (HINSTANCE hInstance , DWORD reason, PVOID pvReserved)
+{
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return 1;
+}
+/*--------------------------------------------------------------------------*/
+
diff --git a/modules/renderer/src/cpp/.deps/.dirstamp b/modules/renderer/src/cpp/.deps/.dirstamp
new file mode 100755
index 000000000..e69de29bb
--- /dev/null
+++ b/modules/renderer/src/cpp/.deps/.dirstamp
diff --git a/modules/renderer/src/cpp/.deps/libscirenderer_la-GetJavaProperty.Plo b/modules/renderer/src/cpp/.deps/libscirenderer_la-GetJavaProperty.Plo
new file mode 100755
index 000000000..c15c6207a
--- /dev/null
+++ b/modules/renderer/src/cpp/.deps/libscirenderer_la-GetJavaProperty.Plo
@@ -0,0 +1,350 @@
+src/cpp/libscirenderer_la-GetJavaProperty.lo: src/cpp/GetJavaProperty.cpp \
+ /usr/include/stdc-predef.h ../../modules/jvm/includes/getScilabJavaVM.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/jni.h /usr/include/stdio.h \
+ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+ /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h \
+ /usr/include/x86_64-linux-gnu/bits/types.h \
+ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/wchar.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio2.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h \
+ includes/GetJavaProperty.h includes/dynlib_renderer.h \
+ src/jni/CallRenderer.hxx /usr/include/c++/5/iostream \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \
+ /usr/include/c++/5/ostream /usr/include/c++/5/ios \
+ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \
+ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \
+ /usr/include/c++/5/cwchar /usr/include/x86_64-linux-gnu/bits/wchar.h \
+ /usr/include/xlocale.h /usr/include/x86_64-linux-gnu/bits/wchar2.h \
+ /usr/include/c++/5/exception \
+ /usr/include/c++/5/bits/atomic_lockfree_defines.h \
+ /usr/include/c++/5/bits/char_traits.h \
+ /usr/include/c++/5/bits/stl_algobase.h \
+ /usr/include/c++/5/bits/functexcept.h \
+ /usr/include/c++/5/bits/exception_defines.h \
+ /usr/include/c++/5/bits/cpp_type_traits.h \
+ /usr/include/c++/5/ext/type_traits.h \
+ /usr/include/c++/5/ext/numeric_traits.h \
+ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \
+ /usr/include/c++/5/bits/concept_check.h \
+ /usr/include/c++/5/bits/stl_iterator_base_types.h \
+ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \
+ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \
+ /usr/include/c++/5/bits/ptr_traits.h \
+ /usr/include/c++/5/bits/predefined_ops.h \
+ /usr/include/c++/5/bits/localefwd.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \
+ /usr/include/c++/5/clocale /usr/include/locale.h \
+ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \
+ /usr/include/ctype.h /usr/include/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \
+ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \
+ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \
+ /usr/include/x86_64-linux-gnu/bits/sched.h \
+ /usr/include/x86_64-linux-gnu/bits/time.h \
+ /usr/include/x86_64-linux-gnu/bits/timex.h \
+ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
+ /usr/include/x86_64-linux-gnu/bits/setjmp.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \
+ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \
+ /usr/include/c++/5/bits/allocator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \
+ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \
+ /usr/include/c++/5/bits/ostream_insert.h \
+ /usr/include/c++/5/bits/cxxabi_forced.h \
+ /usr/include/c++/5/bits/stl_function.h \
+ /usr/include/c++/5/backward/binders.h \
+ /usr/include/c++/5/bits/range_access.h \
+ /usr/include/c++/5/bits/basic_string.h \
+ /usr/include/c++/5/ext/alloc_traits.h \
+ /usr/include/c++/5/bits/basic_string.tcc \
+ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \
+ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \
+ /usr/include/c++/5/bits/basic_ios.h \
+ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \
+ /usr/include/wctype.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \
+ /usr/include/c++/5/bits/streambuf_iterator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \
+ /usr/include/c++/5/bits/locale_facets.tcc \
+ /usr/include/c++/5/bits/basic_ios.tcc \
+ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \
+ /usr/include/c++/5/bits/istream.tcc /usr/include/string.h \
+ /usr/include/x86_64-linux-gnu/bits/string3.h /usr/include/stdlib.h \
+ /usr/include/x86_64-linux-gnu/bits/waitflags.h \
+ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \
+ /usr/include/x86_64-linux-gnu/sys/types.h \
+ /usr/include/x86_64-linux-gnu/sys/select.h \
+ /usr/include/x86_64-linux-gnu/bits/select.h \
+ /usr/include/x86_64-linux-gnu/bits/sigset.h \
+ /usr/include/x86_64-linux-gnu/bits/select2.h \
+ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib.h \
+ ../../modules/commons/src/jni/GiwsException.hxx
+
+/usr/include/stdc-predef.h:
+
+../../modules/jvm/includes/getScilabJavaVM.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/jni.h:
+
+/usr/include/stdio.h:
+
+/usr/include/features.h:
+
+/usr/include/x86_64-linux-gnu/sys/cdefs.h:
+
+/usr/include/x86_64-linux-gnu/bits/wordsize.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h:
+
+/usr/include/x86_64-linux-gnu/bits/types.h:
+
+/usr/include/x86_64-linux-gnu/bits/typesizes.h:
+
+/usr/include/libio.h:
+
+/usr/include/_G_config.h:
+
+/usr/include/wchar.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio_lim.h:
+
+/usr/include/x86_64-linux-gnu/bits/sys_errlist.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio2.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h:
+
+includes/GetJavaProperty.h:
+
+includes/dynlib_renderer.h:
+
+src/jni/CallRenderer.hxx:
+
+/usr/include/c++/5/iostream:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h:
+
+/usr/include/c++/5/ostream:
+
+/usr/include/c++/5/ios:
+
+/usr/include/c++/5/iosfwd:
+
+/usr/include/c++/5/bits/stringfwd.h:
+
+/usr/include/c++/5/bits/memoryfwd.h:
+
+/usr/include/c++/5/bits/postypes.h:
+
+/usr/include/c++/5/cwchar:
+
+/usr/include/x86_64-linux-gnu/bits/wchar.h:
+
+/usr/include/xlocale.h:
+
+/usr/include/x86_64-linux-gnu/bits/wchar2.h:
+
+/usr/include/c++/5/exception:
+
+/usr/include/c++/5/bits/atomic_lockfree_defines.h:
+
+/usr/include/c++/5/bits/char_traits.h:
+
+/usr/include/c++/5/bits/stl_algobase.h:
+
+/usr/include/c++/5/bits/functexcept.h:
+
+/usr/include/c++/5/bits/exception_defines.h:
+
+/usr/include/c++/5/bits/cpp_type_traits.h:
+
+/usr/include/c++/5/ext/type_traits.h:
+
+/usr/include/c++/5/ext/numeric_traits.h:
+
+/usr/include/c++/5/bits/stl_pair.h:
+
+/usr/include/c++/5/bits/move.h:
+
+/usr/include/c++/5/bits/concept_check.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_types.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_funcs.h:
+
+/usr/include/c++/5/debug/debug.h:
+
+/usr/include/c++/5/bits/stl_iterator.h:
+
+/usr/include/c++/5/bits/ptr_traits.h:
+
+/usr/include/c++/5/bits/predefined_ops.h:
+
+/usr/include/c++/5/bits/localefwd.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h:
+
+/usr/include/c++/5/clocale:
+
+/usr/include/locale.h:
+
+/usr/include/x86_64-linux-gnu/bits/locale.h:
+
+/usr/include/c++/5/cctype:
+
+/usr/include/ctype.h:
+
+/usr/include/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap-16.h:
+
+/usr/include/c++/5/bits/ios_base.h:
+
+/usr/include/c++/5/ext/atomicity.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h:
+
+/usr/include/pthread.h:
+
+/usr/include/sched.h:
+
+/usr/include/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/sched.h:
+
+/usr/include/x86_64-linux-gnu/bits/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/timex.h:
+
+/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h:
+
+/usr/include/x86_64-linux-gnu/bits/setjmp.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h:
+
+/usr/include/c++/5/bits/locale_classes.h:
+
+/usr/include/c++/5/string:
+
+/usr/include/c++/5/bits/allocator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h:
+
+/usr/include/c++/5/ext/new_allocator.h:
+
+/usr/include/c++/5/new:
+
+/usr/include/c++/5/bits/ostream_insert.h:
+
+/usr/include/c++/5/bits/cxxabi_forced.h:
+
+/usr/include/c++/5/bits/stl_function.h:
+
+/usr/include/c++/5/backward/binders.h:
+
+/usr/include/c++/5/bits/range_access.h:
+
+/usr/include/c++/5/bits/basic_string.h:
+
+/usr/include/c++/5/ext/alloc_traits.h:
+
+/usr/include/c++/5/bits/basic_string.tcc:
+
+/usr/include/c++/5/bits/locale_classes.tcc:
+
+/usr/include/c++/5/stdexcept:
+
+/usr/include/c++/5/streambuf:
+
+/usr/include/c++/5/bits/streambuf.tcc:
+
+/usr/include/c++/5/bits/basic_ios.h:
+
+/usr/include/c++/5/bits/locale_facets.h:
+
+/usr/include/c++/5/cwctype:
+
+/usr/include/wctype.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h:
+
+/usr/include/c++/5/bits/streambuf_iterator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h:
+
+/usr/include/c++/5/bits/locale_facets.tcc:
+
+/usr/include/c++/5/bits/basic_ios.tcc:
+
+/usr/include/c++/5/bits/ostream.tcc:
+
+/usr/include/c++/5/istream:
+
+/usr/include/c++/5/bits/istream.tcc:
+
+/usr/include/string.h:
+
+/usr/include/x86_64-linux-gnu/bits/string3.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitflags.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitstatus.h:
+
+/usr/include/x86_64-linux-gnu/sys/types.h:
+
+/usr/include/x86_64-linux-gnu/sys/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/sigset.h:
+
+/usr/include/x86_64-linux-gnu/bits/select2.h:
+
+/usr/include/x86_64-linux-gnu/sys/sysmacros.h:
+
+/usr/include/alloca.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-float.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib.h:
+
+../../modules/commons/src/jni/GiwsException.hxx:
diff --git a/modules/renderer/src/cpp/.deps/libscirenderer_la-JavaInteraction.Plo b/modules/renderer/src/cpp/.deps/libscirenderer_la-JavaInteraction.Plo
new file mode 100755
index 000000000..4826e5fe6
--- /dev/null
+++ b/modules/renderer/src/cpp/.deps/libscirenderer_la-JavaInteraction.Plo
@@ -0,0 +1,350 @@
+src/cpp/libscirenderer_la-JavaInteraction.lo: src/cpp/JavaInteraction.cpp \
+ /usr/include/stdc-predef.h includes/JavaInteraction.h \
+ includes/dynlib_renderer.h ../../modules/jvm/includes/getScilabJavaVM.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/jni.h /usr/include/stdio.h \
+ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+ /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h \
+ /usr/include/x86_64-linux-gnu/bits/types.h \
+ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/wchar.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio2.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h \
+ src/jni/CallRenderer.hxx /usr/include/c++/5/iostream \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \
+ /usr/include/c++/5/ostream /usr/include/c++/5/ios \
+ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \
+ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \
+ /usr/include/c++/5/cwchar /usr/include/x86_64-linux-gnu/bits/wchar.h \
+ /usr/include/xlocale.h /usr/include/x86_64-linux-gnu/bits/wchar2.h \
+ /usr/include/c++/5/exception \
+ /usr/include/c++/5/bits/atomic_lockfree_defines.h \
+ /usr/include/c++/5/bits/char_traits.h \
+ /usr/include/c++/5/bits/stl_algobase.h \
+ /usr/include/c++/5/bits/functexcept.h \
+ /usr/include/c++/5/bits/exception_defines.h \
+ /usr/include/c++/5/bits/cpp_type_traits.h \
+ /usr/include/c++/5/ext/type_traits.h \
+ /usr/include/c++/5/ext/numeric_traits.h \
+ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \
+ /usr/include/c++/5/bits/concept_check.h \
+ /usr/include/c++/5/bits/stl_iterator_base_types.h \
+ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \
+ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \
+ /usr/include/c++/5/bits/ptr_traits.h \
+ /usr/include/c++/5/bits/predefined_ops.h \
+ /usr/include/c++/5/bits/localefwd.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \
+ /usr/include/c++/5/clocale /usr/include/locale.h \
+ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \
+ /usr/include/ctype.h /usr/include/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \
+ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \
+ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \
+ /usr/include/x86_64-linux-gnu/bits/sched.h \
+ /usr/include/x86_64-linux-gnu/bits/time.h \
+ /usr/include/x86_64-linux-gnu/bits/timex.h \
+ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
+ /usr/include/x86_64-linux-gnu/bits/setjmp.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \
+ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \
+ /usr/include/c++/5/bits/allocator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \
+ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \
+ /usr/include/c++/5/bits/ostream_insert.h \
+ /usr/include/c++/5/bits/cxxabi_forced.h \
+ /usr/include/c++/5/bits/stl_function.h \
+ /usr/include/c++/5/backward/binders.h \
+ /usr/include/c++/5/bits/range_access.h \
+ /usr/include/c++/5/bits/basic_string.h \
+ /usr/include/c++/5/ext/alloc_traits.h \
+ /usr/include/c++/5/bits/basic_string.tcc \
+ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \
+ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \
+ /usr/include/c++/5/bits/basic_ios.h \
+ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \
+ /usr/include/wctype.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \
+ /usr/include/c++/5/bits/streambuf_iterator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \
+ /usr/include/c++/5/bits/locale_facets.tcc \
+ /usr/include/c++/5/bits/basic_ios.tcc \
+ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \
+ /usr/include/c++/5/bits/istream.tcc /usr/include/string.h \
+ /usr/include/x86_64-linux-gnu/bits/string3.h /usr/include/stdlib.h \
+ /usr/include/x86_64-linux-gnu/bits/waitflags.h \
+ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \
+ /usr/include/x86_64-linux-gnu/sys/types.h \
+ /usr/include/x86_64-linux-gnu/sys/select.h \
+ /usr/include/x86_64-linux-gnu/bits/select.h \
+ /usr/include/x86_64-linux-gnu/bits/sigset.h \
+ /usr/include/x86_64-linux-gnu/bits/select2.h \
+ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib.h \
+ ../../modules/commons/src/jni/GiwsException.hxx
+
+/usr/include/stdc-predef.h:
+
+includes/JavaInteraction.h:
+
+includes/dynlib_renderer.h:
+
+../../modules/jvm/includes/getScilabJavaVM.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/jni.h:
+
+/usr/include/stdio.h:
+
+/usr/include/features.h:
+
+/usr/include/x86_64-linux-gnu/sys/cdefs.h:
+
+/usr/include/x86_64-linux-gnu/bits/wordsize.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h:
+
+/usr/include/x86_64-linux-gnu/bits/types.h:
+
+/usr/include/x86_64-linux-gnu/bits/typesizes.h:
+
+/usr/include/libio.h:
+
+/usr/include/_G_config.h:
+
+/usr/include/wchar.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio_lim.h:
+
+/usr/include/x86_64-linux-gnu/bits/sys_errlist.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio2.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h:
+
+src/jni/CallRenderer.hxx:
+
+/usr/include/c++/5/iostream:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h:
+
+/usr/include/c++/5/ostream:
+
+/usr/include/c++/5/ios:
+
+/usr/include/c++/5/iosfwd:
+
+/usr/include/c++/5/bits/stringfwd.h:
+
+/usr/include/c++/5/bits/memoryfwd.h:
+
+/usr/include/c++/5/bits/postypes.h:
+
+/usr/include/c++/5/cwchar:
+
+/usr/include/x86_64-linux-gnu/bits/wchar.h:
+
+/usr/include/xlocale.h:
+
+/usr/include/x86_64-linux-gnu/bits/wchar2.h:
+
+/usr/include/c++/5/exception:
+
+/usr/include/c++/5/bits/atomic_lockfree_defines.h:
+
+/usr/include/c++/5/bits/char_traits.h:
+
+/usr/include/c++/5/bits/stl_algobase.h:
+
+/usr/include/c++/5/bits/functexcept.h:
+
+/usr/include/c++/5/bits/exception_defines.h:
+
+/usr/include/c++/5/bits/cpp_type_traits.h:
+
+/usr/include/c++/5/ext/type_traits.h:
+
+/usr/include/c++/5/ext/numeric_traits.h:
+
+/usr/include/c++/5/bits/stl_pair.h:
+
+/usr/include/c++/5/bits/move.h:
+
+/usr/include/c++/5/bits/concept_check.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_types.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_funcs.h:
+
+/usr/include/c++/5/debug/debug.h:
+
+/usr/include/c++/5/bits/stl_iterator.h:
+
+/usr/include/c++/5/bits/ptr_traits.h:
+
+/usr/include/c++/5/bits/predefined_ops.h:
+
+/usr/include/c++/5/bits/localefwd.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h:
+
+/usr/include/c++/5/clocale:
+
+/usr/include/locale.h:
+
+/usr/include/x86_64-linux-gnu/bits/locale.h:
+
+/usr/include/c++/5/cctype:
+
+/usr/include/ctype.h:
+
+/usr/include/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap-16.h:
+
+/usr/include/c++/5/bits/ios_base.h:
+
+/usr/include/c++/5/ext/atomicity.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h:
+
+/usr/include/pthread.h:
+
+/usr/include/sched.h:
+
+/usr/include/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/sched.h:
+
+/usr/include/x86_64-linux-gnu/bits/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/timex.h:
+
+/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h:
+
+/usr/include/x86_64-linux-gnu/bits/setjmp.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h:
+
+/usr/include/c++/5/bits/locale_classes.h:
+
+/usr/include/c++/5/string:
+
+/usr/include/c++/5/bits/allocator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h:
+
+/usr/include/c++/5/ext/new_allocator.h:
+
+/usr/include/c++/5/new:
+
+/usr/include/c++/5/bits/ostream_insert.h:
+
+/usr/include/c++/5/bits/cxxabi_forced.h:
+
+/usr/include/c++/5/bits/stl_function.h:
+
+/usr/include/c++/5/backward/binders.h:
+
+/usr/include/c++/5/bits/range_access.h:
+
+/usr/include/c++/5/bits/basic_string.h:
+
+/usr/include/c++/5/ext/alloc_traits.h:
+
+/usr/include/c++/5/bits/basic_string.tcc:
+
+/usr/include/c++/5/bits/locale_classes.tcc:
+
+/usr/include/c++/5/stdexcept:
+
+/usr/include/c++/5/streambuf:
+
+/usr/include/c++/5/bits/streambuf.tcc:
+
+/usr/include/c++/5/bits/basic_ios.h:
+
+/usr/include/c++/5/bits/locale_facets.h:
+
+/usr/include/c++/5/cwctype:
+
+/usr/include/wctype.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h:
+
+/usr/include/c++/5/bits/streambuf_iterator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h:
+
+/usr/include/c++/5/bits/locale_facets.tcc:
+
+/usr/include/c++/5/bits/basic_ios.tcc:
+
+/usr/include/c++/5/bits/ostream.tcc:
+
+/usr/include/c++/5/istream:
+
+/usr/include/c++/5/bits/istream.tcc:
+
+/usr/include/string.h:
+
+/usr/include/x86_64-linux-gnu/bits/string3.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitflags.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitstatus.h:
+
+/usr/include/x86_64-linux-gnu/sys/types.h:
+
+/usr/include/x86_64-linux-gnu/sys/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/sigset.h:
+
+/usr/include/x86_64-linux-gnu/bits/select2.h:
+
+/usr/include/x86_64-linux-gnu/sys/sysmacros.h:
+
+/usr/include/alloca.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-float.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib.h:
+
+../../modules/commons/src/jni/GiwsException.hxx:
diff --git a/modules/renderer/src/cpp/.deps/libscirenderer_la-RendererFontManager.Plo b/modules/renderer/src/cpp/.deps/libscirenderer_la-RendererFontManager.Plo
new file mode 100755
index 000000000..11efb07c5
--- /dev/null
+++ b/modules/renderer/src/cpp/.deps/libscirenderer_la-RendererFontManager.Plo
@@ -0,0 +1,357 @@
+src/cpp/libscirenderer_la-RendererFontManager.lo: \
+ src/cpp/RendererFontManager.cpp /usr/include/stdc-predef.h \
+ src/jni/XlFontManager.hxx /usr/include/c++/5/iostream \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \
+ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+ /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \
+ /usr/include/c++/5/ostream /usr/include/c++/5/ios \
+ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \
+ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \
+ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \
+ /usr/include/x86_64-linux-gnu/bits/wchar.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \
+ /usr/include/x86_64-linux-gnu/bits/wchar2.h /usr/include/c++/5/exception \
+ /usr/include/c++/5/bits/atomic_lockfree_defines.h \
+ /usr/include/c++/5/bits/char_traits.h \
+ /usr/include/c++/5/bits/stl_algobase.h \
+ /usr/include/c++/5/bits/functexcept.h \
+ /usr/include/c++/5/bits/exception_defines.h \
+ /usr/include/c++/5/bits/cpp_type_traits.h \
+ /usr/include/c++/5/ext/type_traits.h \
+ /usr/include/c++/5/ext/numeric_traits.h \
+ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \
+ /usr/include/c++/5/bits/concept_check.h \
+ /usr/include/c++/5/bits/stl_iterator_base_types.h \
+ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \
+ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \
+ /usr/include/c++/5/bits/ptr_traits.h \
+ /usr/include/c++/5/bits/predefined_ops.h \
+ /usr/include/c++/5/bits/localefwd.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \
+ /usr/include/c++/5/clocale /usr/include/locale.h \
+ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \
+ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \
+ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \
+ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \
+ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \
+ /usr/include/x86_64-linux-gnu/bits/sched.h \
+ /usr/include/x86_64-linux-gnu/bits/time.h \
+ /usr/include/x86_64-linux-gnu/bits/timex.h \
+ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
+ /usr/include/x86_64-linux-gnu/bits/setjmp.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \
+ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \
+ /usr/include/c++/5/bits/allocator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \
+ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \
+ /usr/include/c++/5/bits/ostream_insert.h \
+ /usr/include/c++/5/bits/cxxabi_forced.h \
+ /usr/include/c++/5/bits/stl_function.h \
+ /usr/include/c++/5/backward/binders.h \
+ /usr/include/c++/5/bits/range_access.h \
+ /usr/include/c++/5/bits/basic_string.h \
+ /usr/include/c++/5/ext/alloc_traits.h \
+ /usr/include/c++/5/bits/basic_string.tcc \
+ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \
+ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \
+ /usr/include/c++/5/bits/basic_ios.h \
+ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \
+ /usr/include/wctype.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \
+ /usr/include/c++/5/bits/streambuf_iterator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \
+ /usr/include/c++/5/bits/locale_facets.tcc \
+ /usr/include/c++/5/bits/basic_ios.tcc \
+ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \
+ /usr/include/c++/5/bits/istream.tcc /usr/include/string.h \
+ /usr/include/x86_64-linux-gnu/bits/string3.h /usr/include/stdlib.h \
+ /usr/include/x86_64-linux-gnu/bits/waitflags.h \
+ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \
+ /usr/include/x86_64-linux-gnu/sys/types.h \
+ /usr/include/x86_64-linux-gnu/sys/select.h \
+ /usr/include/x86_64-linux-gnu/bits/select.h \
+ /usr/include/x86_64-linux-gnu/bits/sigset.h \
+ /usr/include/x86_64-linux-gnu/bits/select2.h \
+ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/jni.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio2.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h \
+ ../../modules/commons/src/jni/GiwsException.hxx \
+ ../../modules/jvm/includes/getScilabJavaVM.h \
+ includes/RendererFontManager.h includes/dynlib_renderer.h \
+ ../../modules/core/includes/BOOL.h ../../modules/core/includes/MALLOC.h \
+ ../../modules/core/includes/sci_mem_alloc.h
+
+/usr/include/stdc-predef.h:
+
+src/jni/XlFontManager.hxx:
+
+/usr/include/c++/5/iostream:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h:
+
+/usr/include/features.h:
+
+/usr/include/x86_64-linux-gnu/sys/cdefs.h:
+
+/usr/include/x86_64-linux-gnu/bits/wordsize.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h:
+
+/usr/include/c++/5/ostream:
+
+/usr/include/c++/5/ios:
+
+/usr/include/c++/5/iosfwd:
+
+/usr/include/c++/5/bits/stringfwd.h:
+
+/usr/include/c++/5/bits/memoryfwd.h:
+
+/usr/include/c++/5/bits/postypes.h:
+
+/usr/include/c++/5/cwchar:
+
+/usr/include/wchar.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h:
+
+/usr/include/x86_64-linux-gnu/bits/wchar.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h:
+
+/usr/include/xlocale.h:
+
+/usr/include/x86_64-linux-gnu/bits/wchar2.h:
+
+/usr/include/c++/5/exception:
+
+/usr/include/c++/5/bits/atomic_lockfree_defines.h:
+
+/usr/include/c++/5/bits/char_traits.h:
+
+/usr/include/c++/5/bits/stl_algobase.h:
+
+/usr/include/c++/5/bits/functexcept.h:
+
+/usr/include/c++/5/bits/exception_defines.h:
+
+/usr/include/c++/5/bits/cpp_type_traits.h:
+
+/usr/include/c++/5/ext/type_traits.h:
+
+/usr/include/c++/5/ext/numeric_traits.h:
+
+/usr/include/c++/5/bits/stl_pair.h:
+
+/usr/include/c++/5/bits/move.h:
+
+/usr/include/c++/5/bits/concept_check.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_types.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_funcs.h:
+
+/usr/include/c++/5/debug/debug.h:
+
+/usr/include/c++/5/bits/stl_iterator.h:
+
+/usr/include/c++/5/bits/ptr_traits.h:
+
+/usr/include/c++/5/bits/predefined_ops.h:
+
+/usr/include/c++/5/bits/localefwd.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h:
+
+/usr/include/c++/5/clocale:
+
+/usr/include/locale.h:
+
+/usr/include/x86_64-linux-gnu/bits/locale.h:
+
+/usr/include/c++/5/cctype:
+
+/usr/include/ctype.h:
+
+/usr/include/x86_64-linux-gnu/bits/types.h:
+
+/usr/include/x86_64-linux-gnu/bits/typesizes.h:
+
+/usr/include/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap-16.h:
+
+/usr/include/c++/5/bits/ios_base.h:
+
+/usr/include/c++/5/ext/atomicity.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h:
+
+/usr/include/pthread.h:
+
+/usr/include/sched.h:
+
+/usr/include/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/sched.h:
+
+/usr/include/x86_64-linux-gnu/bits/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/timex.h:
+
+/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h:
+
+/usr/include/x86_64-linux-gnu/bits/setjmp.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h:
+
+/usr/include/c++/5/bits/locale_classes.h:
+
+/usr/include/c++/5/string:
+
+/usr/include/c++/5/bits/allocator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h:
+
+/usr/include/c++/5/ext/new_allocator.h:
+
+/usr/include/c++/5/new:
+
+/usr/include/c++/5/bits/ostream_insert.h:
+
+/usr/include/c++/5/bits/cxxabi_forced.h:
+
+/usr/include/c++/5/bits/stl_function.h:
+
+/usr/include/c++/5/backward/binders.h:
+
+/usr/include/c++/5/bits/range_access.h:
+
+/usr/include/c++/5/bits/basic_string.h:
+
+/usr/include/c++/5/ext/alloc_traits.h:
+
+/usr/include/c++/5/bits/basic_string.tcc:
+
+/usr/include/c++/5/bits/locale_classes.tcc:
+
+/usr/include/c++/5/stdexcept:
+
+/usr/include/c++/5/streambuf:
+
+/usr/include/c++/5/bits/streambuf.tcc:
+
+/usr/include/c++/5/bits/basic_ios.h:
+
+/usr/include/c++/5/bits/locale_facets.h:
+
+/usr/include/c++/5/cwctype:
+
+/usr/include/wctype.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h:
+
+/usr/include/c++/5/bits/streambuf_iterator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h:
+
+/usr/include/c++/5/bits/locale_facets.tcc:
+
+/usr/include/c++/5/bits/basic_ios.tcc:
+
+/usr/include/c++/5/bits/ostream.tcc:
+
+/usr/include/c++/5/istream:
+
+/usr/include/c++/5/bits/istream.tcc:
+
+/usr/include/string.h:
+
+/usr/include/x86_64-linux-gnu/bits/string3.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitflags.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitstatus.h:
+
+/usr/include/x86_64-linux-gnu/sys/types.h:
+
+/usr/include/x86_64-linux-gnu/sys/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/sigset.h:
+
+/usr/include/x86_64-linux-gnu/bits/select2.h:
+
+/usr/include/x86_64-linux-gnu/sys/sysmacros.h:
+
+/usr/include/alloca.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-float.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/jni.h:
+
+/usr/include/libio.h:
+
+/usr/include/_G_config.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio_lim.h:
+
+/usr/include/x86_64-linux-gnu/bits/sys_errlist.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio2.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h:
+
+../../modules/commons/src/jni/GiwsException.hxx:
+
+../../modules/jvm/includes/getScilabJavaVM.h:
+
+includes/RendererFontManager.h:
+
+includes/dynlib_renderer.h:
+
+../../modules/core/includes/BOOL.h:
+
+../../modules/core/includes/MALLOC.h:
+
+../../modules/core/includes/sci_mem_alloc.h:
diff --git a/modules/renderer/src/cpp/.deps/libscirenderer_la-SetJavaProperty.Plo b/modules/renderer/src/cpp/.deps/libscirenderer_la-SetJavaProperty.Plo
new file mode 100755
index 000000000..bbfc507d7
--- /dev/null
+++ b/modules/renderer/src/cpp/.deps/libscirenderer_la-SetJavaProperty.Plo
@@ -0,0 +1,364 @@
+src/cpp/libscirenderer_la-SetJavaProperty.lo: src/cpp/SetJavaProperty.cpp \
+ /usr/include/stdc-predef.h includes/SetJavaProperty.h \
+ includes/dynlib_renderer.h \
+ ../../modules/commons/src/jni/GiwsException.hxx \
+ /usr/include/c++/5/iostream \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \
+ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+ /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \
+ /usr/include/c++/5/ostream /usr/include/c++/5/ios \
+ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \
+ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \
+ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \
+ /usr/include/x86_64-linux-gnu/bits/wchar.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \
+ /usr/include/x86_64-linux-gnu/bits/wchar2.h /usr/include/c++/5/exception \
+ /usr/include/c++/5/bits/atomic_lockfree_defines.h \
+ /usr/include/c++/5/bits/char_traits.h \
+ /usr/include/c++/5/bits/stl_algobase.h \
+ /usr/include/c++/5/bits/functexcept.h \
+ /usr/include/c++/5/bits/exception_defines.h \
+ /usr/include/c++/5/bits/cpp_type_traits.h \
+ /usr/include/c++/5/ext/type_traits.h \
+ /usr/include/c++/5/ext/numeric_traits.h \
+ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \
+ /usr/include/c++/5/bits/concept_check.h \
+ /usr/include/c++/5/bits/stl_iterator_base_types.h \
+ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \
+ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \
+ /usr/include/c++/5/bits/ptr_traits.h \
+ /usr/include/c++/5/bits/predefined_ops.h \
+ /usr/include/c++/5/bits/localefwd.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \
+ /usr/include/c++/5/clocale /usr/include/locale.h \
+ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \
+ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \
+ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \
+ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \
+ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \
+ /usr/include/x86_64-linux-gnu/bits/sched.h \
+ /usr/include/x86_64-linux-gnu/bits/time.h \
+ /usr/include/x86_64-linux-gnu/bits/timex.h \
+ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
+ /usr/include/x86_64-linux-gnu/bits/setjmp.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \
+ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \
+ /usr/include/c++/5/bits/allocator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \
+ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \
+ /usr/include/c++/5/bits/ostream_insert.h \
+ /usr/include/c++/5/bits/cxxabi_forced.h \
+ /usr/include/c++/5/bits/stl_function.h \
+ /usr/include/c++/5/backward/binders.h \
+ /usr/include/c++/5/bits/range_access.h \
+ /usr/include/c++/5/bits/basic_string.h \
+ /usr/include/c++/5/ext/alloc_traits.h \
+ /usr/include/c++/5/bits/basic_string.tcc \
+ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \
+ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \
+ /usr/include/c++/5/bits/basic_ios.h \
+ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \
+ /usr/include/wctype.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \
+ /usr/include/c++/5/bits/streambuf_iterator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \
+ /usr/include/c++/5/bits/locale_facets.tcc \
+ /usr/include/c++/5/bits/basic_ios.tcc \
+ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \
+ /usr/include/c++/5/bits/istream.tcc /usr/include/string.h \
+ /usr/include/x86_64-linux-gnu/bits/string3.h /usr/include/stdlib.h \
+ /usr/include/x86_64-linux-gnu/bits/waitflags.h \
+ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \
+ /usr/include/x86_64-linux-gnu/sys/types.h \
+ /usr/include/x86_64-linux-gnu/sys/select.h \
+ /usr/include/x86_64-linux-gnu/bits/select.h \
+ /usr/include/x86_64-linux-gnu/bits/sigset.h \
+ /usr/include/x86_64-linux-gnu/bits/select2.h \
+ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/jni.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio2.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h \
+ ../../modules/output_stream/includes/Scierror.h \
+ ../../modules/output_stream/includes/do_error_number.h \
+ ../../modules/core/includes/machine.h \
+ ../../modules/output_stream/includes/sciprint.h \
+ ../../modules/core/includes/BOOL.h \
+ ../../modules/jvm/includes/getScilabJavaVM.h src/jni/CallRenderer.hxx
+
+/usr/include/stdc-predef.h:
+
+includes/SetJavaProperty.h:
+
+includes/dynlib_renderer.h:
+
+../../modules/commons/src/jni/GiwsException.hxx:
+
+/usr/include/c++/5/iostream:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h:
+
+/usr/include/features.h:
+
+/usr/include/x86_64-linux-gnu/sys/cdefs.h:
+
+/usr/include/x86_64-linux-gnu/bits/wordsize.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h:
+
+/usr/include/c++/5/ostream:
+
+/usr/include/c++/5/ios:
+
+/usr/include/c++/5/iosfwd:
+
+/usr/include/c++/5/bits/stringfwd.h:
+
+/usr/include/c++/5/bits/memoryfwd.h:
+
+/usr/include/c++/5/bits/postypes.h:
+
+/usr/include/c++/5/cwchar:
+
+/usr/include/wchar.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h:
+
+/usr/include/x86_64-linux-gnu/bits/wchar.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h:
+
+/usr/include/xlocale.h:
+
+/usr/include/x86_64-linux-gnu/bits/wchar2.h:
+
+/usr/include/c++/5/exception:
+
+/usr/include/c++/5/bits/atomic_lockfree_defines.h:
+
+/usr/include/c++/5/bits/char_traits.h:
+
+/usr/include/c++/5/bits/stl_algobase.h:
+
+/usr/include/c++/5/bits/functexcept.h:
+
+/usr/include/c++/5/bits/exception_defines.h:
+
+/usr/include/c++/5/bits/cpp_type_traits.h:
+
+/usr/include/c++/5/ext/type_traits.h:
+
+/usr/include/c++/5/ext/numeric_traits.h:
+
+/usr/include/c++/5/bits/stl_pair.h:
+
+/usr/include/c++/5/bits/move.h:
+
+/usr/include/c++/5/bits/concept_check.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_types.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_funcs.h:
+
+/usr/include/c++/5/debug/debug.h:
+
+/usr/include/c++/5/bits/stl_iterator.h:
+
+/usr/include/c++/5/bits/ptr_traits.h:
+
+/usr/include/c++/5/bits/predefined_ops.h:
+
+/usr/include/c++/5/bits/localefwd.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h:
+
+/usr/include/c++/5/clocale:
+
+/usr/include/locale.h:
+
+/usr/include/x86_64-linux-gnu/bits/locale.h:
+
+/usr/include/c++/5/cctype:
+
+/usr/include/ctype.h:
+
+/usr/include/x86_64-linux-gnu/bits/types.h:
+
+/usr/include/x86_64-linux-gnu/bits/typesizes.h:
+
+/usr/include/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap-16.h:
+
+/usr/include/c++/5/bits/ios_base.h:
+
+/usr/include/c++/5/ext/atomicity.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h:
+
+/usr/include/pthread.h:
+
+/usr/include/sched.h:
+
+/usr/include/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/sched.h:
+
+/usr/include/x86_64-linux-gnu/bits/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/timex.h:
+
+/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h:
+
+/usr/include/x86_64-linux-gnu/bits/setjmp.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h:
+
+/usr/include/c++/5/bits/locale_classes.h:
+
+/usr/include/c++/5/string:
+
+/usr/include/c++/5/bits/allocator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h:
+
+/usr/include/c++/5/ext/new_allocator.h:
+
+/usr/include/c++/5/new:
+
+/usr/include/c++/5/bits/ostream_insert.h:
+
+/usr/include/c++/5/bits/cxxabi_forced.h:
+
+/usr/include/c++/5/bits/stl_function.h:
+
+/usr/include/c++/5/backward/binders.h:
+
+/usr/include/c++/5/bits/range_access.h:
+
+/usr/include/c++/5/bits/basic_string.h:
+
+/usr/include/c++/5/ext/alloc_traits.h:
+
+/usr/include/c++/5/bits/basic_string.tcc:
+
+/usr/include/c++/5/bits/locale_classes.tcc:
+
+/usr/include/c++/5/stdexcept:
+
+/usr/include/c++/5/streambuf:
+
+/usr/include/c++/5/bits/streambuf.tcc:
+
+/usr/include/c++/5/bits/basic_ios.h:
+
+/usr/include/c++/5/bits/locale_facets.h:
+
+/usr/include/c++/5/cwctype:
+
+/usr/include/wctype.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h:
+
+/usr/include/c++/5/bits/streambuf_iterator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h:
+
+/usr/include/c++/5/bits/locale_facets.tcc:
+
+/usr/include/c++/5/bits/basic_ios.tcc:
+
+/usr/include/c++/5/bits/ostream.tcc:
+
+/usr/include/c++/5/istream:
+
+/usr/include/c++/5/bits/istream.tcc:
+
+/usr/include/string.h:
+
+/usr/include/x86_64-linux-gnu/bits/string3.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitflags.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitstatus.h:
+
+/usr/include/x86_64-linux-gnu/sys/types.h:
+
+/usr/include/x86_64-linux-gnu/sys/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/sigset.h:
+
+/usr/include/x86_64-linux-gnu/bits/select2.h:
+
+/usr/include/x86_64-linux-gnu/sys/sysmacros.h:
+
+/usr/include/alloca.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-float.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/jni.h:
+
+/usr/include/libio.h:
+
+/usr/include/_G_config.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio_lim.h:
+
+/usr/include/x86_64-linux-gnu/bits/sys_errlist.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio2.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h:
+
+../../modules/output_stream/includes/Scierror.h:
+
+../../modules/output_stream/includes/do_error_number.h:
+
+../../modules/core/includes/machine.h:
+
+../../modules/output_stream/includes/sciprint.h:
+
+../../modules/core/includes/BOOL.h:
+
+../../modules/jvm/includes/getScilabJavaVM.h:
+
+src/jni/CallRenderer.hxx:
diff --git a/modules/renderer/src/cpp/.dirstamp b/modules/renderer/src/cpp/.dirstamp
new file mode 100755
index 000000000..e69de29bb
--- /dev/null
+++ b/modules/renderer/src/cpp/.dirstamp
diff --git a/modules/renderer/src/cpp/.libs/libscirenderer_la-GetJavaProperty.o b/modules/renderer/src/cpp/.libs/libscirenderer_la-GetJavaProperty.o
new file mode 100755
index 000000000..329104985
--- /dev/null
+++ b/modules/renderer/src/cpp/.libs/libscirenderer_la-GetJavaProperty.o
Binary files differ
diff --git a/modules/renderer/src/cpp/.libs/libscirenderer_la-JavaInteraction.o b/modules/renderer/src/cpp/.libs/libscirenderer_la-JavaInteraction.o
new file mode 100755
index 000000000..514ce9992
--- /dev/null
+++ b/modules/renderer/src/cpp/.libs/libscirenderer_la-JavaInteraction.o
Binary files differ
diff --git a/modules/renderer/src/cpp/.libs/libscirenderer_la-RendererFontManager.o b/modules/renderer/src/cpp/.libs/libscirenderer_la-RendererFontManager.o
new file mode 100755
index 000000000..cacc360d2
--- /dev/null
+++ b/modules/renderer/src/cpp/.libs/libscirenderer_la-RendererFontManager.o
Binary files differ
diff --git a/modules/renderer/src/cpp/.libs/libscirenderer_la-SetJavaProperty.o b/modules/renderer/src/cpp/.libs/libscirenderer_la-SetJavaProperty.o
new file mode 100755
index 000000000..601423b5a
--- /dev/null
+++ b/modules/renderer/src/cpp/.libs/libscirenderer_la-SetJavaProperty.o
Binary files differ
diff --git a/modules/renderer/src/cpp/GetJavaProperty.cpp b/modules/renderer/src/cpp/GetJavaProperty.cpp
new file mode 100755
index 000000000..12d123cfb
--- /dev/null
+++ b/modules/renderer/src/cpp/GetJavaProperty.cpp
@@ -0,0 +1,86 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2007 - INRIA - Jean-Baptiste Silvy
+ * Copyright (C) 2010 - Paul Griffiths
+ * Copyright (C) 2012 - DIGITEO - Manuel Juliachs
+ * desc : Interface functions between between GetProperty functions and the C++/Java part of module
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+extern "C"
+{
+#include "getScilabJavaVM.h"
+#include "GetJavaProperty.h"
+}
+
+#include "CallRenderer.hxx"
+
+using namespace org_scilab_modules_renderer;
+
+/*---------------------------------------------------------------------------------*/
+void sciGetJava2dViewPixelCoordinates(int iSubwinUID, const double userCoords[3], int pixCoords[2])
+{
+ double *tmp = NULL;
+ double coords[3];
+
+ coords[0] = userCoords[0];
+ coords[1] = userCoords[1];
+ coords[2] = userCoords[2];
+
+ tmp = CallRenderer::getPixelFrom2dViewCoordinates(getScilabJavaVM(), iSubwinUID, coords, 3);
+
+ pixCoords[0] = (int) tmp[0];
+ pixCoords[1] = (int) tmp[1];
+}
+
+/*---------------------------------------------------------------------------------*/
+void sciGetJava2dViewCoordinates(int iSubwinUID, const double userCoords3D[3], double userCoords2D[2])
+{
+ double *tmp = NULL;
+ double coords[3];
+
+ coords[0] = userCoords3D[0];
+ coords[1] = userCoords3D[1];
+ coords[2] = userCoords3D[2];
+
+ tmp = CallRenderer::get2dViewCoordinates(getScilabJavaVM(), iSubwinUID, coords, 3);
+
+ userCoords2D[0] = tmp[0];
+ userCoords2D[1] = tmp[1];
+}
+
+/*---------------------------------------------------------------------------------*/
+void sciGetJava2dViewCoordFromPixel(int iSubwinUID, const int pixCoords[2], double userCoords2D[2])
+{
+ double *tmp = NULL;
+ double coords[2];
+
+ coords[0] = (double) pixCoords[0];
+ coords[1] = (double) pixCoords[1];
+
+ tmp = CallRenderer::get2dViewFromPixelCoordinates(getScilabJavaVM(), iSubwinUID, coords, 2);
+
+ userCoords2D[0] = tmp[0];
+ userCoords2D[1] = tmp[1];
+}
+
+/*---------------------------------------------------------------------------------*/
+void sciGetJavaViewingArea(int iSubwinUID, int *xPos, int *yPos, int *width, int *height)
+{
+ double *tmp = NULL;
+
+ tmp = CallRenderer::getViewingArea(getScilabJavaVM(), iSubwinUID);
+
+ *xPos = (int) tmp[0];
+ *yPos = (int) tmp[1];
+ *width = (int) tmp[2];
+ *height = (int) tmp[3];
+}
+
+/*---------------------------------------------------------------------------------*/
diff --git a/modules/renderer/src/cpp/JavaInteraction.cpp b/modules/renderer/src/cpp/JavaInteraction.cpp
new file mode 100755
index 000000000..6d3383bc3
--- /dev/null
+++ b/modules/renderer/src/cpp/JavaInteraction.cpp
@@ -0,0 +1,36 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2007 - INRIA - Jean-Baptiste Silvy
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+extern "C" {
+#include "JavaInteraction.h"
+#include "getScilabJavaVM.h"
+}
+
+#include "CallRenderer.hxx"
+
+void startInteractiveZoom(int iObjUID)
+{
+ org_scilab_modules_renderer::CallRenderer::startInteractiveZoom(getScilabJavaVM(), iObjUID);
+}
+
+/*---------------------------------------------------------------------------------*/
+double *javaClickRubberBox(int iObjUID, double *initialRect, int iRectSize)
+{
+ return org_scilab_modules_renderer::CallRenderer::clickRubberBox(getScilabJavaVM(), iObjUID, initialRect, iRectSize);
+}
+
+/*---------------------------------------------------------------------------------*/
+double *javaDragRubberBox(int iObjUID)
+{
+ return org_scilab_modules_renderer::CallRenderer::dragRubberBox(getScilabJavaVM(), iObjUID);
+}
+/*---------------------------------------------------------------------------------*/
diff --git a/modules/renderer/src/cpp/RendererFontManager.cpp b/modules/renderer/src/cpp/RendererFontManager.cpp
new file mode 100755
index 000000000..4a1e1990a
--- /dev/null
+++ b/modules/renderer/src/cpp/RendererFontManager.cpp
@@ -0,0 +1,182 @@
+
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2008 - INRIA - Allan CORNET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+/*--------------------------------------------------------------------------*/
+#include "XlFontManager.hxx"
+
+extern "C" {
+#include <stdlib.h>
+#include "getScilabJavaVM.h"
+#include "RendererFontManager.h"
+#include "MALLOC.h"
+#ifdef _MSC_VER
+#include "strdup_windows.h"
+#endif
+}
+
+using namespace org_scilab_modules_renderer_utils_textRendering;
+
+/*--------------------------------------------------------------------------*/
+int getNbInstalledFonts(void)
+{
+ XlFontManager * fntmgr = new XlFontManager(getScilabJavaVM());
+ int res = fntmgr->getSizeInstalledFontsName();
+ delete fntmgr;
+ return res;
+}
+/*--------------------------------------------------------------------------*/
+char **getInstalledFontsName(int *sizeArray)
+{
+ char **returnedinstalledfontsname = NULL;
+ *sizeArray = 0;
+
+ org_scilab_modules_renderer_utils_textRendering::XlFontManager *fntmgr = new org_scilab_modules_renderer_utils_textRendering::XlFontManager(getScilabJavaVM());
+ if (fntmgr)
+ {
+ char **installedfontsname = NULL;
+
+ *sizeArray = fntmgr->getSizeInstalledFontsName();
+ installedfontsname = fntmgr->getInstalledFontsName();
+ if (installedfontsname)
+ {
+ int i = 0;
+ returnedinstalledfontsname = (char**)MALLOC(sizeof(char*) * (*sizeArray));
+ for ( i = 0; i < *sizeArray; i++)
+ {
+ returnedinstalledfontsname[i] = strdup(installedfontsname[i]);
+ delete [] installedfontsname[i];
+ }
+ delete [] installedfontsname;
+ installedfontsname = NULL;
+ }
+ delete fntmgr;
+ }
+
+ return returnedinstalledfontsname;
+}
+/*--------------------------------------------------------------------------*/
+char **getAvailableFontsName(int *sizeArray)
+{
+ char **returnedavailablefontsname = NULL;
+ *sizeArray = 0;
+
+ org_scilab_modules_renderer_utils_textRendering::XlFontManager *fntmgr = new org_scilab_modules_renderer_utils_textRendering::XlFontManager(getScilabJavaVM());
+ if (fntmgr)
+ {
+ char **availablefontsname = NULL;
+
+ *sizeArray = fntmgr->getSizeAvailableFontsName();
+ availablefontsname = fntmgr->getAvailableFontsName();
+ if (availablefontsname)
+ {
+ int i = 0;
+ returnedavailablefontsname = (char**)MALLOC(sizeof(char*) * (*sizeArray));
+ for ( i = 0; i < *sizeArray; i++)
+ {
+ returnedavailablefontsname[i] = strdup(availablefontsname[i]);
+ delete [] availablefontsname[i];
+ }
+ delete [] availablefontsname;
+ availablefontsname = NULL;
+ }
+ delete fntmgr;
+ }
+
+ return returnedavailablefontsname;
+}
+/*--------------------------------------------------------------------------*/
+BOOL isAvailableFontsName(char *fontname)
+{
+ BOOL bOK = FALSE;
+ org_scilab_modules_renderer_utils_textRendering::XlFontManager *fntmgr = new org_scilab_modules_renderer_utils_textRendering::XlFontManager(getScilabJavaVM());
+ if (fntmgr)
+ {
+ bOK = booltoBOOL(fntmgr->isAvailableFontName(fontname));
+ delete fntmgr;
+ }
+ return bOK;
+}
+/*--------------------------------------------------------------------------*/
+int addFont(char *fontname)
+{
+ int fontID = 0;
+
+ org_scilab_modules_renderer_utils_textRendering::XlFontManager *fntmgr = new org_scilab_modules_renderer_utils_textRendering::XlFontManager(getScilabJavaVM());
+ if (fntmgr)
+ {
+ fontID = (int)fntmgr->addFont(fontname);
+ delete fntmgr;
+ }
+
+ return fontID;
+}
+/*--------------------------------------------------------------------------*/
+int changeFont(int index, char * fontName)
+{
+ int fontID = 0;
+ org_scilab_modules_renderer_utils_textRendering::XlFontManager *fntmgr = new org_scilab_modules_renderer_utils_textRendering::XlFontManager(getScilabJavaVM());
+ if (fntmgr)
+ {
+ fontID = (int)fntmgr->changeFont((long)index, fontName);
+ delete fntmgr;
+ }
+
+ return fontID;
+}
+/*--------------------------------------------------------------------------*/
+int changeFontWithProperty(int index, char * fontName, BOOL isBold, BOOL isItalic)
+{
+ int fontID = 0;
+ org_scilab_modules_renderer_utils_textRendering::XlFontManager *fntmgr = new org_scilab_modules_renderer_utils_textRendering::XlFontManager(getScilabJavaVM());
+ if (fntmgr)
+ {
+ fontID = (int)fntmgr->changeFontWithProperty((long)index, fontName, BOOLtobool(isBold), BOOLtobool(isItalic));
+ delete fntmgr;
+ }
+ return fontID;
+}
+/*--------------------------------------------------------------------------*/
+void resetFontManager(void)
+{
+ org_scilab_modules_renderer_utils_textRendering::XlFontManager *fntmgr = new org_scilab_modules_renderer_utils_textRendering::XlFontManager(getScilabJavaVM());
+ if (fntmgr)
+ {
+ fntmgr->resetXlFontManager();
+ delete fntmgr;
+ }
+}
+/*--------------------------------------------------------------------------*/
+int changeFontFromFilename (int index, char * FontFilename)
+{
+ int fontID = 0;
+ org_scilab_modules_renderer_utils_textRendering::XlFontManager *fntmgr = new org_scilab_modules_renderer_utils_textRendering::XlFontManager(getScilabJavaVM());
+ if (fntmgr)
+ {
+ fontID = (int)fntmgr->changeFontFromFilename((long)index, FontFilename);
+ delete fntmgr;
+ }
+ return fontID;
+}
+/*--------------------------------------------------------------------------*/
+int addFontFromFilename (char * FontFilename)
+{
+ int fontID = 0;
+ org_scilab_modules_renderer_utils_textRendering::XlFontManager *fntmgr = new org_scilab_modules_renderer_utils_textRendering::XlFontManager(getScilabJavaVM());
+ if (fntmgr)
+ {
+ fontID = (int)fntmgr->addFontFromFilename (FontFilename);
+ delete fntmgr;
+ }
+ return fontID;
+}
+/*--------------------------------------------------------------------------*/
diff --git a/modules/renderer/src/cpp/SetJavaProperty.cpp b/modules/renderer/src/cpp/SetJavaProperty.cpp
new file mode 100755
index 000000000..c577f4d86
--- /dev/null
+++ b/modules/renderer/src/cpp/SetJavaProperty.cpp
@@ -0,0 +1,42 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2007 - INRIA - Jean-Baptiste Silvy
+ * Copyright (C) 2008 - INRIA - Vincent Couvert
+ * desc : Interface functions between between SetProperty functions and the C++/Java part of module
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+#include "SetJavaProperty.h"
+#include "GiwsException.hxx"
+
+
+extern "C"
+{
+#include "Scierror.h"
+#include "sciprint.h"
+#include "getScilabJavaVM.h"
+}
+
+#include "CallRenderer.hxx"
+
+using namespace org_scilab_modules_renderer;
+
+/*---------------------------------------------------------------------------------*/
+void sciJavaUpdateSubwinScale(int iObjUID)
+{
+ CallRenderer::updateSubwinScale(getScilabJavaVM(), iObjUID);
+}
+
+/*---------------------------------------------------------------------------------*/
+void sciJavaUpdateTextBoundingBox(int iTextUID)
+{
+ CallRenderer::updateTextBounds(getScilabJavaVM(), iTextUID);
+}
+
+/*---------------------------------------------------------------------------------*/
diff --git a/modules/renderer/src/cpp/libscirenderer_la-GetJavaProperty.lo b/modules/renderer/src/cpp/libscirenderer_la-GetJavaProperty.lo
new file mode 100755
index 000000000..230bf5227
--- /dev/null
+++ b/modules/renderer/src/cpp/libscirenderer_la-GetJavaProperty.lo
@@ -0,0 +1,12 @@
+# src/cpp/libscirenderer_la-GetJavaProperty.lo - a libtool object file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/libscirenderer_la-GetJavaProperty.o'
+
+# Name of the non-PIC object
+non_pic_object=none
+
diff --git a/modules/renderer/src/cpp/libscirenderer_la-JavaInteraction.lo b/modules/renderer/src/cpp/libscirenderer_la-JavaInteraction.lo
new file mode 100755
index 000000000..f2464aa28
--- /dev/null
+++ b/modules/renderer/src/cpp/libscirenderer_la-JavaInteraction.lo
@@ -0,0 +1,12 @@
+# src/cpp/libscirenderer_la-JavaInteraction.lo - a libtool object file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/libscirenderer_la-JavaInteraction.o'
+
+# Name of the non-PIC object
+non_pic_object=none
+
diff --git a/modules/renderer/src/cpp/libscirenderer_la-RendererFontManager.lo b/modules/renderer/src/cpp/libscirenderer_la-RendererFontManager.lo
new file mode 100755
index 000000000..d8425888e
--- /dev/null
+++ b/modules/renderer/src/cpp/libscirenderer_la-RendererFontManager.lo
@@ -0,0 +1,12 @@
+# src/cpp/libscirenderer_la-RendererFontManager.lo - a libtool object file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/libscirenderer_la-RendererFontManager.o'
+
+# Name of the non-PIC object
+non_pic_object=none
+
diff --git a/modules/renderer/src/cpp/libscirenderer_la-SetJavaProperty.lo b/modules/renderer/src/cpp/libscirenderer_la-SetJavaProperty.lo
new file mode 100755
index 000000000..aab1362cc
--- /dev/null
+++ b/modules/renderer/src/cpp/libscirenderer_la-SetJavaProperty.lo
@@ -0,0 +1,12 @@
+# src/cpp/libscirenderer_la-SetJavaProperty.lo - a libtool object file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/libscirenderer_la-SetJavaProperty.o'
+
+# Name of the non-PIC object
+non_pic_object=none
+
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/CallRenderer.java b/modules/renderer/src/java/org/scilab/modules/renderer/CallRenderer.java
new file mode 100755
index 000000000..2c0e5efa0
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/CallRenderer.java
@@ -0,0 +1,204 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - DIGITEO - Manuel Juliachs
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.renderer;
+
+import org.scilab.modules.graphic_objects.ScilabNativeView;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObject;
+import org.scilab.modules.graphic_objects.textObject.Text;
+import org.scilab.modules.graphic_objects.datatip.Datatip;
+
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.axes.AxesDrawer;
+import org.scilab.modules.renderer.JoGLView.text.TextManager;
+import org.scilab.modules.renderer.JoGLView.datatip.DatatipTextDrawer;
+
+/**
+ * This is a static class to access the renderer module directly
+ * from C/C++ code through JNI.
+ * See SCI/modules/renderer/src/jni/renderer.giws.xml for other details.
+ **/
+public final class CallRenderer {
+
+ /**
+ * Start an interactive zoom.
+ * @param id the uid of the figure where the zoom happen.
+ */
+ public static void startInteractiveZoom(int id) {
+ DrawerVisitor visitor = DrawerVisitor.getVisitor(id);
+ if (visitor != null) {
+ visitor.getInteractionManager().startInteractiveZoom();
+ }
+ }
+
+ public static void start_zoom(int figureId) {
+ startInteractiveZoom(ScilabNativeView.ScilabNativeView__getFigureFromIndex(figureId));
+ }
+
+ public static double[] clickRubberBox(int id, double initialRect[]) {
+ DrawerVisitor visitor = DrawerVisitor.getVisitor(id);
+ if (visitor != null) {
+ return visitor.getInteractionManager().startClickRubberBox(initialRect);
+ }
+ return new double[] { -1, -1, -1, -1, -1, -1, -1};
+ }
+
+ public static double[] dragRubberBox(int id) {
+ DrawerVisitor visitor = DrawerVisitor.getVisitor(id);
+ if (visitor != null) {
+ return visitor.getInteractionManager().startDragRubberBox();
+ }
+ return new double[] { -1, -1, -1, -1, -1, -1, -1};
+ }
+ /**
+ * Updates the coordinate transformation of the Axes object given by the identifier.
+ * @param id the Axes' identifier.
+ */
+ public static void updateSubwinScale(int id) {
+ GraphicObject object = GraphicController.getController().getObjectFromId(id);
+
+ if (object != null && object instanceof Axes) {
+ AxesDrawer.updateAxesTransformation((Axes) object);
+ }
+ }
+
+ /**
+ * Updates the corners of the text object corresponding to the identifier.
+ * @param id the text object's identifier.
+ */
+ public static void updateTextBounds(int id) {
+ GraphicObject object = GraphicController.getController().getObjectFromId(id);
+
+ if (object != null) {
+ if (object instanceof Datatip) {
+ DatatipTextDrawer.updateTextCorners((Datatip) object);
+ } else if (object instanceof Text) {
+ TextManager.updateTextCorners((Text) object);
+ }
+ }
+ }
+
+ /**
+ * Computes and returns the coordinates of a point projected onto the default 2d view plane.
+ * The obtained coordinates correspond to the point's object coordinates in the default 2d view
+ * coordinate frame (the point's position being fixed in window coordinates).
+ * The projected point's z coordinate is set to 0, as only x and y are relevant.
+ * @param id the identifier of the Axes object.
+ * @param coords the input object coordinates (3-element array).
+ * @return the 2d view coordinates (3-element array).
+ */
+ public static double[] get2dViewCoordinates(int id, double[] coords) {
+ double[] point2d = new double[] {0.0, 0.0, 0.0};
+
+ GraphicObject object = GraphicController.getController().getObjectFromId(id);
+
+ if (object != null && object instanceof Axes) {
+ double[] tmp = AxesDrawer.compute2dViewCoordinates((Axes) object, coords);
+
+ point2d[0] = tmp[0];
+ point2d[1] = tmp[1];
+ }
+
+ return point2d;
+ }
+
+ /**
+ * Computes and returns the pixel coordinates from a point's coordinates expressed
+ * in the default 2d view coordinate frame, using the given Axes.
+ * The returned pixel coordinates are expressed in the AWT's 2d coordinate frame.
+ * @param id the Axes' identifier.
+ * @param coords the 2d view coordinates (3-element array: x, y, z).
+ * @return the pixel coordinates (2-element array: x, y).
+ */
+ public static double[] getPixelFrom2dViewCoordinates(int id, double[] coords) {
+ double[] pointPix = new double[] {0.0, 0.0};
+
+ GraphicObject object = GraphicController.getController().getObjectFromId(id);
+
+ if (object != null && object instanceof Axes) {
+ double[] tmp = AxesDrawer.computePixelFrom2dViewCoordinates((Axes) object, coords);
+
+ pointPix[0] = tmp[0];
+ pointPix[1] = tmp[1];
+ }
+
+ return pointPix;
+ }
+
+ /**
+ * Computes and returns the coordinates of a point projected onto the default 2d view plane
+ * from its pixel coordinates, using the given Axes. The pixel coordinates are expressed in
+ * the AWT's 2d coordinate frame.
+ * The returned point's z component is set to 0, as we only have x and y as an input.
+ * @param id the Axes' identifier.
+ * @param coords the pixel coordinates (2-element array: x, y).
+ * @return the 2d view coordinates (3-element array: x, y, z).
+ */
+ public static double[] get2dViewFromPixelCoordinates(int id, double[] coords) {
+ double[] point2d = new double[] {0.0, 0.0, 0.0};
+
+ GraphicObject object = GraphicController.getController().getObjectFromId(id);
+
+ if (object != null && object instanceof Axes) {
+ double[] tmp = AxesDrawer.compute2dViewFromPixelCoordinates((Axes) object, coords);
+
+ point2d[0] = tmp[0];
+ point2d[1] = tmp[1];
+ }
+
+ return point2d;
+ }
+
+ public static double[][] getPixelFrom3dCoordinates(int id, double[] coordsX, double[] coordsY, double[] coordsZ) {
+ GraphicObject object = GraphicController.getController().getObjectFromId(id);
+ if (object instanceof Axes) {
+ return AxesDrawer.computePixelFrom3dCoordinates((Axes) object, coordsX, coordsY, coordsZ);
+ }
+
+ return null;
+ }
+
+ public static double[] getPixelFrom3dCoordinates(int id, double[] coord) {
+ GraphicObject object = GraphicController.getController().getObjectFromId(id);
+ if (object instanceof Axes) {
+ return AxesDrawer.computePixelFrom3dCoordinates((Axes) object, coord);
+ }
+
+ return null;
+ }
+
+ /**
+ * Computes and returns the viewing area of the Axes object given by the identifier.
+ * The viewing area is defined by its upper-left corner and its dimensions, all values
+ * are in pixels. It is expressed in the AWT's 2d coordinate frame.
+ * @param id the Axes' identifier.
+ * @return the Axes' viewing area (4-element array: x, y, width, height).
+ */
+ public static double[] getViewingArea(int id) {
+ double[] viewingArea = new double[] {0.0, 0.0, 0.0, 0.0};
+ GraphicObject object = GraphicController.getController().getObjectFromId(id);
+
+ if (object != null && object instanceof Axes) {
+ double[] tmp = AxesDrawer.getViewingArea((Axes) object);
+
+ viewingArea[0] = tmp[0];
+ viewingArea[1] = tmp[1];
+ viewingArea[2] = tmp[2];
+ viewingArea[3] = tmp[3];
+ }
+
+ return viewingArea;
+ }
+
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/AxisDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/AxisDrawer.java
new file mode 100755
index 000000000..26c91ca13
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/AxisDrawer.java
@@ -0,0 +1,371 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.ruler.DefaultRulerModel;
+import org.scilab.forge.scirenderer.ruler.RulerDrawer;
+import org.scilab.forge.scirenderer.ruler.RulerSpriteFactory;
+import org.scilab.forge.scirenderer.ruler.graduations.AbstractGraduations;
+import org.scilab.forge.scirenderer.ruler.graduations.Graduations;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.axis.Axis;
+import org.scilab.modules.graphic_objects.textObject.FormattedText;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+import org.scilab.modules.renderer.JoGLView.util.FormattedTextSpriteDrawer;
+import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
+
+import java.text.DecimalFormat;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Pierre Lando
+ */
+public class AxisDrawer {
+
+ /** Ticks length in pixels. */
+ private static final int TICKS_LENGTH = 8;
+
+ /** Sub-ticks length in pixels. */
+ private static final int SUB_TICKS_LENGTH = 5;
+
+ /**Ticks sprites distance in pixels. */
+ private static final int SPRITE_DISTANCE = 12;
+
+ private final DrawerVisitor drawerVisitor;
+
+ public AxisDrawer(DrawerVisitor drawerVisitor) {
+ this.drawerVisitor = drawerVisitor;
+ }
+
+ public void draw(Axes axes, Axis axis) {
+ double min;
+ double max;
+
+ DefaultRulerModel rulerModel = new DefaultRulerModel();
+ rulerModel.setSpriteDistance(SPRITE_DISTANCE);
+ rulerModel.setSubTicksLength(SUB_TICKS_LENGTH);
+ rulerModel.setTicksLength(TICKS_LENGTH);
+ boolean[] logFlags = new boolean[] {axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
+
+ Double[] xTicksValues;
+ Double[] yTicksValues;
+ double[] xMinAndMax;
+ double[] yMinAndMax;
+ double[][] factors = axes.getScaleTranslateFactors();
+
+ if (axis.getXTicksCoords().length == 1) {
+ xTicksValues = axis.getXTicksCoords();
+ yTicksValues = decodeValue(axis.getYTicksCoords(), axis.getTicksStyle());
+ xMinAndMax = getMinAndMax(xTicksValues);
+ yMinAndMax = getMinAndMax(yTicksValues);
+ min = yMinAndMax[0];
+ max = yMinAndMax[1];
+ rulerModel.setUserGraduation(new AxisGraduation(axis, yTicksValues, yMinAndMax));
+ } else {
+ xTicksValues = decodeValue(axis.getXTicksCoords(), axis.getTicksStyle());
+ yTicksValues = axis.getYTicksCoords();
+ xMinAndMax = getMinAndMax(xTicksValues);
+ yMinAndMax = getMinAndMax(yTicksValues);
+ min = xMinAndMax[0];
+ max = xMinAndMax[1];
+ rulerModel.setUserGraduation(new AxisGraduation(axis, xTicksValues, xMinAndMax));
+ }
+
+ Vector3d start = new Vector3d(xMinAndMax[0], yMinAndMax[0], 0);
+ Vector3d end = new Vector3d(xMinAndMax[1], yMinAndMax[1], 0);
+ start = ScaleUtils.applyLogScale(start, logFlags);
+ end = ScaleUtils.applyLogScale(end, logFlags);
+
+ start = new Vector3d(start.getX() * factors[0][0] + factors[1][0], start.getY() * factors[0][1] + factors[1][1], start.getZ() * factors[0][2] + factors[1][2]);
+ end = new Vector3d(end.getX() * factors[0][0] + factors[1][0], end.getY() * factors[0][1] + factors[1][1], end.getZ() * factors[0][2] + factors[1][2]);
+
+ // TODO : RulerModel should be an interface.
+ rulerModel.setAutoTicks(false);
+ rulerModel.setFirstValue(0);
+ rulerModel.setSecondValue(1);
+ rulerModel.setLineVisible(axis.getTicksSegment());
+ rulerModel.setColor(ColorFactory.createColor(drawerVisitor.getColorMap(), axis.getTicksColor()));
+
+ rulerModel.setPoints(start, end);
+ rulerModel.setTicksDirection(computeTicksDirection(axis.getTicksDirectionAsEnum()));
+
+ DrawingTools drawingTools = drawerVisitor.getDrawingTools();
+
+ RulerDrawer rulerDrawer = new RulerDrawer(drawerVisitor.getCanvas().getTextureManager());
+ rulerDrawer.setSpriteFactory(new AxisSpriteFactory(axis, min, max));
+ rulerDrawer.draw(drawingTools, rulerModel);
+
+ axis.getFormatn();
+ rulerDrawer.disposeResources();
+ }
+
+ /**
+ * Return [min, max] the minimum and maximum of given values.
+ * @param values the given value.
+ * @return [min, max] the minimum and maximum of given values.
+ */
+ private double[] getMinAndMax(Double[] values) {
+ double min = +Double.MAX_VALUE;
+ double max = -Double.MAX_VALUE;
+ for (double value : values) {
+ min = Math.min(min, value);
+ max = Math.max(max, value);
+ }
+ return new double[] {min, max};
+ }
+
+ /**
+ * Decode ticks coordinate.
+ * If ticksStyle='0' then v gives the tics positions along the axis.
+ * If ticksStyle='1' then v must be of size 3. r=[xmin,xmax,n] and n gives the number of intervals.
+ * If ticksStyle='2' then v must be of size 4, r=[k1,k2,a,n]. then xmin=k1*10^a, xmax=k2*10^a and n gives the number of intervals
+ * @param v the given value.
+ * @param ticksStyle used ticks style.
+ * @return decoded ticks coordinate.
+ */
+ private Double[] decodeValue(Double[] v, int ticksStyle) {
+ if ((ticksStyle == 1) && (v.length >= 3)) {
+ double min = v[0], max = v[1];
+ int n = v[2].intValue();
+ Double[] r = new Double[n + 1];
+ double k = (max - min) / n;
+ for (int i = 0 ; i <= n ; i++) {
+ r[i] = min + i * k;
+ }
+ return r;
+ } else if ((ticksStyle == 2) && (v.length >= 4)) {
+ double pow10 = Math.pow(10, v[2]);
+ double min = v[0] * pow10;
+ double max = v[1] * pow10;
+ int n = v[3].intValue();
+ Double[] r = new Double[n + 1];
+ double k = (max - min) / n;
+ for (int i = 0 ; i <= n ; i++) {
+ r[i] = min + i * k;
+ }
+ return r;
+ } else {
+ return v;
+ }
+ }
+
+ /**
+ * Return the ticks direction in scene coordinate.
+ * @param direction the ticks direction as an {@see Axis.TicksDirection}
+ * @return the ticks direction in scene coordinate.
+ */
+ private Vector3d computeTicksDirection(Axis.TicksDirection direction) {
+ switch (direction) {
+ case TOP:
+ return new Vector3d(0, +1, 0);
+ case BOTTOM:
+ return new Vector3d(0, -1, 0);
+ case LEFT:
+ return new Vector3d(-1, 0, 0);
+ default:
+ return new Vector3d(+1, 0, 0);
+ }
+ }
+
+ private class AxisGraduation extends AbstractGraduations {
+ private final List<Double> subTicksValue;
+ private final List<Double> allValues;
+ private final Axis axis;
+
+
+ AxisGraduation(Axis axis, Double[] ticksCoordinate, double[] minAndMax) {
+ super(0., 1.);
+ this.axis = axis;
+ allValues = computeValue(ticksCoordinate, minAndMax);
+ subTicksValue = computeSubValue(allValues, axis.getSubticks());
+ }
+
+
+ /**
+ * Compute the sub-ticks value.
+ * @param allValues the sorted list of ticks value.
+ * @param subTicks the number of sub-division between two ticks.
+ * @return the sub-ticks value.
+ */
+ private List<Double> computeSubValue(List<Double> allValues, Integer subTicks) {
+ if ((allValues == null) || (allValues.size() < 2)) {
+ return new LinkedList<Double>();
+ } else {
+ LinkedList<Double> subTicksValue = new LinkedList<Double>();
+ Iterator<Double> iterator = allValues.iterator();
+ double lastValue = iterator.next();
+ while (iterator.hasNext()) {
+ double currentValue = iterator.next();
+ double k = (currentValue - lastValue) / subTicks;
+ for (int i = 1 ; i < subTicks ; i++) {
+ subTicksValue.add(lastValue + i * k);
+ }
+ lastValue = currentValue;
+ }
+ return subTicksValue;
+ }
+ }
+
+ /**
+ * Return a list of graduation value corresponding to the given coordinate.
+ * Value are in the range [0, 1] and the coordinate are linearly mapped
+ * to this range.
+ * If the coordinates are empty, empty list is returned.
+ * If the coordinates are all the same, a same-sized list of zero is returned.
+ *
+ * @param coordinates given coordinate.
+ * @param minAndMax the min an max of the given coordinate.
+ * @return a list of graduation value corresponding to the given coordinate.
+ */
+ private List<Double> computeValue(Double[] coordinates, double[] minAndMax) {
+ if ((coordinates == null) || (coordinates.length == 0)) {
+ return new LinkedList<Double>();
+ } else if (coordinates.length == 1) {
+ LinkedList<Double> allValues = new LinkedList<Double>();
+ allValues.add(0.);
+ return allValues;
+ } else {
+ LinkedList<Double> allValues = new LinkedList<Double>();
+ double min = minAndMax[0];
+ double max = minAndMax[1];
+ if (max == min) {
+ for (Double coordinate : coordinates) {
+ allValues.add(0.);
+ }
+ } else {
+ double k = 1 / (max - min);
+ for (double value : coordinates) {
+ allValues.add(k * (value - min));
+ }
+ Collections.sort(allValues);
+ }
+ return allValues;
+ }
+ }
+
+ @Override
+ public List<Double> getAllValues() {
+ return allValues;
+ }
+
+ @Override
+ public List<Double> getNewValues() {
+ return allValues;
+ }
+
+ @Override
+ public Graduations getMore() {
+ return null;
+ }
+
+ @Override
+ public Graduations getAlternative() {
+ return null;
+ }
+
+ @Override
+ public Graduations getSubGraduations() {
+ return new AbstractGraduations(this) {
+ @Override
+ public List<Double> getAllValues() {
+ return subTicksValue;
+ }
+
+ @Override
+ public List<Double> getNewValues() {
+ return getAllValues();
+ }
+
+ @Override
+ public Graduations getMore() {
+ return null;
+ }
+
+ @Override
+ public Graduations getAlternative() {
+ return null;
+ }
+
+ @Override
+ public Graduations getSubGraduations() {
+ return null;
+ }
+
+ @Override
+ public int getSubDensity() {
+ return 0;
+ }
+ };
+ }
+
+ @Override
+ public int getSubDensity() {
+ return axis.getSubticks();
+ }
+ }
+
+ private class AxisSpriteFactory implements RulerSpriteFactory {
+ private final Axis axis;
+ private final double min;
+ private final double max;
+
+ public AxisSpriteFactory(Axis axis, double min, double max) {
+ this.axis = axis;
+ this.min = min;
+ this.max = max;
+ }
+
+ @Override
+ public Texture create(double value, DecimalFormat adaptedFormat, TextureManager spriteManager) {
+ String label = getLabel(value);
+ if (label != null) {
+ FormattedText formattedText = new FormattedText();
+ formattedText.setFont(axis.getFont());
+ formattedText.setText(getLabel(value));
+
+ FormattedTextSpriteDrawer textureDrawer = new FormattedTextSpriteDrawer(drawerVisitor.getColorMap(), formattedText);
+ Texture texture = spriteManager.createTexture();
+ texture.setMagnificationFilter(Texture.Filter.LINEAR);
+ texture.setMinifyingFilter(Texture.Filter.LINEAR);
+ texture.setDrawer(textureDrawer);
+
+ return texture;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Return the label corresponding to the given value.
+ * @param value the given value.
+ * @return the label corresponding to the given value.
+ */
+ private String getLabel(double value) {
+ // 0 <= value <= 1
+ // Should find right index through given labels.
+ String[] ticksLabel = axis.getTicksLabels();
+ int index = (int) Math.round(value * (ticksLabel.length - 1));
+ if ((index < 0) || (index > ticksLabel.length) || ticksLabel.length == 0) {
+ return null;
+ } else {
+ return ticksLabel[index];
+ }
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/DataManager.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/DataManager.java
new file mode 100755
index 000000000..145ee554c
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/DataManager.java
@@ -0,0 +1,572 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+import org.scilab.modules.graphic_objects.MainDataLoader;
+import org.scilab.modules.graphic_objects.ObjectRemovedException;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObject;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+import org.scilab.modules.renderer.JoGLView.util.BufferAllocation;
+import org.scilab.modules.renderer.JoGLView.util.OutOfMemoryException;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author Pierre Lando
+ */
+public class DataManager {
+
+ /**
+ * Set of properties that affect Fac3d data.
+ */
+ private static final Set<Integer> FAC3D_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_DATA_MODEL__,
+ GraphicObjectProperties.__GO_COLOR_FLAG__,
+ GraphicObjectProperties.__GO_COLOR_MODE__,
+ GraphicObjectProperties.__GO_DATA_MAPPING__
+ ));
+
+ /**
+ * Set of properties that affect Fec data.
+ */
+ private static final Set<Integer> FEC_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_DATA_MODEL__,
+ GraphicObjectProperties.__GO_Z_BOUNDS__,
+ GraphicObjectProperties.__GO_COLOR_RANGE__,
+ GraphicObjectProperties.__GO_OUTSIDE_COLOR__
+ ));
+
+ /**
+ * Set of properties that affect Grayplot data.
+ */
+ private static final Set<Integer> GRAYPLOT_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_DATA_MODEL__,
+ GraphicObjectProperties.__GO_DATA_MAPPING__
+ ));
+
+ /**
+ * Set of properties that affect Matplot data.
+ */
+ private static final Set<Integer> MATPLOT_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_DATA_MODEL__
+ ));
+
+ /**
+ * Set of properties that affect polyline data.
+ */
+ private static final Set<Integer> POLYLINE_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_DATA_MODEL__,
+ GraphicObjectProperties.__GO_POLYLINE_STYLE__,
+ GraphicObjectProperties.__GO_LINE_MODE__,
+ GraphicObjectProperties.__GO_BAR_WIDTH__,
+ GraphicObjectProperties.__GO_CLOSED__,
+ GraphicObjectProperties.__GO_FILL_MODE__,
+ GraphicObjectProperties.__GO_INTERP_COLOR_VECTOR__,
+ GraphicObjectProperties.__GO_INTERP_COLOR_MODE__
+ ));
+
+ /**
+ * Set of properties that affect Plot3d data.
+ */
+ private static final Set<Integer> PLOT3D_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_DATA_MODEL__
+ ));
+
+ /**
+ * Set of properties that affect Arc data.
+ */
+ private static final Set<Integer> ARC_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_UPPER_LEFT_POINT__,
+ GraphicObjectProperties.__GO_WIDTH__,
+ GraphicObjectProperties.__GO_HEIGHT__,
+ GraphicObjectProperties.__GO_START_ANGLE__,
+ GraphicObjectProperties.__GO_END_ANGLE__
+ ));
+
+ /**
+ * Set of properties that affect Champ data.
+ */
+ private static final Set<Integer> CHAMP_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_BASE_X__,
+ GraphicObjectProperties.__GO_BASE_Y__,
+ GraphicObjectProperties.__GO_BASE_Z__,
+ GraphicObjectProperties.__GO_DIRECTION_X__,
+ GraphicObjectProperties.__GO_DIRECTION_Y__,
+ GraphicObjectProperties.__GO_DIRECTION_Z__,
+ GraphicObjectProperties.__GO_COLORED__
+ ));
+
+ /**
+ * Set of properties that affect Rectangle data.
+ */
+ private static final Set<Integer> RECTANGLE_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_UPPER_LEFT_POINT__,
+ GraphicObjectProperties.__GO_WIDTH__,
+ GraphicObjectProperties.__GO_HEIGHT__
+ ));
+
+ /**
+ * Set of properties that affect Segs data.
+ */
+ private static final Set<Integer> SEGS_DATA_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_BASE__,
+ GraphicObjectProperties.__GO_DIRECTION__,
+ GraphicObjectProperties.__GO_SEGS_COLORS__
+ ));
+
+ private static final double[] DEFAULT_SCALE = new double[] {1, 1, 1};
+ private static final double[] DEFAULT_TRANSLATE = new double[] {0, 0, 0};
+
+ /*
+ * Bit mask specifying whether logarithmic coordinates are used.
+ * Temporarily defined as a constant for now and set to 0 (linear x, y and z coordinates).
+ * To do: pass it as an argument of fillVertexBuffer and fillWireIndexBuffer, when updating data.
+ */
+ private static final int DEFAULT_LOG_MASK = 0;
+
+ private final Map<Integer, TransformedElementsBuffer> vertexBufferMap = new HashMap<Integer, TransformedElementsBuffer>();
+ private final Map<Integer, ElementsBuffer> normalBufferMap = new HashMap<Integer, ElementsBuffer>();
+ private final Map<Integer, ElementsBuffer> colorBufferMap = new ConcurrentHashMap<Integer, ElementsBuffer>();
+ private final Map<Integer, ElementsBuffer> texturesCoordinatesBufferMap = new HashMap<Integer, ElementsBuffer>();
+ private final Map<Integer, IndicesBuffer> indexBufferMap = new HashMap<Integer, IndicesBuffer>();
+ private final Map<Integer, IndicesBuffer> wireIndexBufferMap = new HashMap<Integer, IndicesBuffer>();
+ private final Canvas canvas;
+
+
+ /**
+ * Default constructor.
+ * @param canvas the canvas where managed data live.
+ */
+ public DataManager(Canvas canvas) {
+ this.canvas = canvas;
+ }
+
+ /**
+ * Return the vertex buffer of the given object.
+ * @param id the given object Id.
+ * @return the vertex buffer of the given object.
+ * @throws ObjectRemovedException if the object is now longer present.
+ */
+ public ElementsBuffer getVertexBuffer(Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ GraphicObject currentObject = GraphicController.getController().getObjectFromId(id);
+ Axes axes = (Axes) GraphicController.getController().getObjectFromId(currentObject.getParentAxes());
+ double[][] factors = axes.getScaleTranslateFactors();
+
+ if (vertexBufferMap.containsKey(id)) {
+ TransformedElementsBuffer buf = vertexBufferMap.get(id);
+ if (buf.isSameFactors(factors)) {
+ return buf.getBuffer();
+ }
+ }
+
+ ElementsBuffer vertexBuffer = canvas.getBuffersManager().createElementsBuffer();
+ fillVertexBuffer(vertexBuffer, id, factors[0], factors[1]);
+ vertexBufferMap.put(id, new TransformedElementsBuffer(vertexBuffer, factors));
+
+ return vertexBuffer;
+ }
+
+ /**
+ * Return the normal buffer of the given object.
+ * @param id the given object Id.
+ * @return the vertex buffer of the given object.
+ * @throws ObjectRemovedException if the object is now longer present.
+ */
+ public ElementsBuffer getNormalBuffer(Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ if (normalBufferMap.containsKey(id)) {
+ return normalBufferMap.get(id);
+ } else {
+ ElementsBuffer normalBuffer = canvas.getBuffersManager().createElementsBuffer();
+ fillNormalBuffer(normalBuffer, id);
+ normalBufferMap.put(id, normalBuffer);
+ return normalBuffer;
+ }
+ }
+
+ /**
+ * Texture coordinates getter.
+ * @param identifier the graphic object id.
+ * @return the texture coordinates corresponding to the given graphic object.
+ * @throws ObjectRemovedException if the object is now longer present.
+ */
+ public ElementsBuffer getTextureCoordinatesBuffer(Integer identifier) throws ObjectRemovedException, OutOfMemoryException {
+ if (texturesCoordinatesBufferMap.containsKey(identifier)) {
+ return texturesCoordinatesBufferMap.get(identifier);
+ } else {
+ ElementsBuffer texturesCoordinatesBuffer = canvas.getBuffersManager().createElementsBuffer();
+ fillTextureCoordinatesBuffer(texturesCoordinatesBuffer, identifier);
+ texturesCoordinatesBufferMap.put(identifier, texturesCoordinatesBuffer);
+ return texturesCoordinatesBuffer;
+ }
+ }
+
+ /**
+ * Return the color buffer of the given object.
+ * @param id the given object Id.
+ * @return the color buffer of the given object.
+ * @throws ObjectRemovedException if the object is now longer present.
+ */
+ public ElementsBuffer getColorBuffer(Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ if (colorBufferMap.containsKey(id)) {
+ return colorBufferMap.get(id);
+ } else {
+ ElementsBuffer colorBuffer = canvas.getBuffersManager().createElementsBuffer();
+ fillColorBuffer(colorBuffer, id);
+ colorBufferMap.put(id, colorBuffer);
+ return colorBuffer;
+ }
+ }
+
+ /**
+ * Return the index buffer of the given object.
+ * @param id the given object Id.
+ * @return the index buffer of the given object.
+ * @throws ObjectRemovedException if the object is now longer present.
+ */
+ public IndicesBuffer getIndexBuffer(Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ if (indexBufferMap.containsKey(id)) {
+ return indexBufferMap.get(id);
+ } else {
+ IndicesBuffer indexBuffer = canvas.getBuffersManager().createIndicesBuffer();
+ fillIndexBuffer(indexBuffer, id);
+ indexBufferMap.put(id, indexBuffer);
+ return indexBuffer;
+ }
+ }
+
+ /**
+ * Return the wire index buffer of the given object.
+ * @param id the given object Id.
+ * @return the wire index buffer of the given object.
+ * @throws ObjectRemovedException if the object is now longer present.
+ */
+ public IndicesBuffer getWireIndexBuffer(Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ if (wireIndexBufferMap.containsKey(id)) {
+ return wireIndexBufferMap.get(id);
+ } else {
+ IndicesBuffer indexBuffer = canvas.getBuffersManager().createIndicesBuffer();
+ fillWireIndexBuffer(indexBuffer, id);
+ wireIndexBufferMap.put(id, indexBuffer);
+ return indexBuffer;
+ }
+ }
+
+ /**
+ * Update texture coordinate buffer for the given object.
+ * @param id given object id.
+ * @throws ObjectRemovedException if the object is now longer present.
+ */
+ public void updateTextureCoordinatesBuffer(Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ ElementsBuffer textureCoordinatesBuffer = texturesCoordinatesBufferMap.get(id);
+ if (textureCoordinatesBuffer != null) {
+ fillTextureCoordinatesBuffer(textureCoordinatesBuffer, id);
+ }
+ }
+
+ /**
+ * Update the data if needed.
+ * @param id the modified object.
+ * @param property the changed property.
+ */
+ public void update(Integer id, int property) throws OutOfMemoryException {
+ Integer type = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
+
+ try {
+ if (vertexBufferMap.containsKey(id)) {
+ if ((type.equals(GraphicObjectProperties.__GO_FAC3D__) && FAC3D_DATA_PROPERTIES.contains(property))
+ || (type.equals(GraphicObjectProperties.__GO_FEC__) && FEC_DATA_PROPERTIES.contains(property))
+ || (type.equals(GraphicObjectProperties.__GO_GRAYPLOT__) && GRAYPLOT_DATA_PROPERTIES.contains(property))
+ || (type.equals(GraphicObjectProperties.__GO_MATPLOT__) && MATPLOT_DATA_PROPERTIES.contains(property))
+ || (type.equals(GraphicObjectProperties.__GO_POLYLINE__) && POLYLINE_DATA_PROPERTIES.contains(property))
+ || (type.equals(GraphicObjectProperties.__GO_PLOT3D__) && PLOT3D_DATA_PROPERTIES.contains(property))
+ || (type.equals(GraphicObjectProperties.__GO_ARC__) && ARC_DATA_PROPERTIES.contains(property))
+ || (type.equals(GraphicObjectProperties.__GO_CHAMP__) && CHAMP_DATA_PROPERTIES.contains(property))
+ || (type.equals(GraphicObjectProperties.__GO_RECTANGLE__) && RECTANGLE_DATA_PROPERTIES.contains(property))
+ || (type.equals(GraphicObjectProperties.__GO_SEGS__) && SEGS_DATA_PROPERTIES.contains(property))) {
+ fillBuffers(id);
+ }
+ }
+ if (property == GraphicObjectProperties.__GO_X_AXIS_LOG_FLAG__) {
+ updateChildrenVertexIndex(id, 0x01);
+ }
+
+ if (property == GraphicObjectProperties.__GO_Y_AXIS_LOG_FLAG__) {
+ updateChildrenVertexIndex(id, 0x02);
+ }
+
+ if (property == GraphicObjectProperties.__GO_Z_AXIS_LOG_FLAG__) {
+ updateChildrenVertexIndex(id, 0x04);
+ }
+ } catch (ObjectRemovedException e) {
+ // Object has been removed before drawing : do nothing.
+ }
+ }
+
+ /**
+ * Update the vertex buffer and index buffers of the given object and its descendants.
+ * @param id the id of the object.
+ * @param coordinateMask the coordinateMask to use.
+ * @throws ObjectRemovedException if the object is no longer present.
+ * @throws OutOfMemoryException if there was not enough memory.
+ */
+ private void updateChildrenVertexIndex(Integer id, int coordinateMask) throws ObjectRemovedException, OutOfMemoryException {
+ GraphicObject currentObject = GraphicController.getController().getObjectFromId(id);
+ Axes axes = (Axes) GraphicController.getController().getObjectFromId(currentObject.getParentAxes());
+ double[][] factors = axes.getScaleTranslateFactors();
+
+ TransformedElementsBuffer buf = vertexBufferMap.get(id);
+ if (buf != null) {
+ updateVertexBuffer(buf.getBuffer(), id, coordinateMask, factors[0], factors[1]);
+ }
+
+ ElementsBuffer normalBuffer = normalBufferMap.get(id);
+ if (normalBuffer != null) {
+ fillNormalBuffer(normalBuffer, id);
+ }
+
+ /*
+ * To update the index and wire index buffers, on the contrary to updateVertexBuffer, we must perform a complete fill.
+ * That is because IndicesBuffer's getData method returns a read-only buffer, which cannot be written to, as is
+ * done by updateVertexBuffer, whereas the fill methods allocate new buffers (see the implementations of getData in
+ * SciRenderer's ElementsBuffer and IndicesBuffer). To allow an allocation-free update would require modifying
+ * IndicesBuffer's getData method.
+ */
+ IndicesBuffer indexBuffer = indexBufferMap.get(id);
+ if (indexBuffer != null) {
+ fillIndexBuffer(indexBuffer, id);
+ }
+
+ IndicesBuffer wireIndexBuffer = wireIndexBufferMap.get(id);
+ if (wireIndexBuffer != null) {
+ fillWireIndexBuffer(wireIndexBuffer, id);
+ }
+
+ for (Integer childId : (Integer []) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_CHILDREN__)) {
+ updateChildrenVertexIndex(childId, coordinateMask);
+ }
+ }
+
+ /**
+ * Clear the buffer corresponding to the given object.
+ * @param id object id.
+ */
+ public void dispose(Integer id) {
+ if (vertexBufferMap.containsKey(id)) {
+ canvas.getBuffersManager().dispose(vertexBufferMap.get(id).getBuffer());
+ vertexBufferMap.remove(id);
+ }
+
+ if (normalBufferMap.containsKey(id)) {
+ canvas.getBuffersManager().dispose(normalBufferMap.get(id));
+ normalBufferMap.remove(id);
+ }
+
+ if (colorBufferMap.containsKey(id)) {
+ canvas.getBuffersManager().dispose(colorBufferMap.get(id));
+ colorBufferMap.remove(id);
+ }
+
+ if (texturesCoordinatesBufferMap.containsKey(id)) {
+ canvas.getBuffersManager().dispose(texturesCoordinatesBufferMap.get(id));
+ texturesCoordinatesBufferMap.remove(id);
+ }
+
+ if (indexBufferMap.containsKey(id)) {
+ canvas.getBuffersManager().dispose(indexBufferMap.get(id));
+ indexBufferMap.remove(id);
+ }
+
+ if (wireIndexBufferMap.containsKey(id)) {
+ canvas.getBuffersManager().dispose(wireIndexBufferMap.get(id));
+ wireIndexBufferMap.remove(id);
+ }
+ }
+
+ /**
+ * Clears all the color buffers.
+ */
+ public void disposeAllColorBuffers() {
+ canvas.getBuffersManager().dispose(colorBufferMap.values());
+ colorBufferMap.clear();
+ }
+
+ /**
+ * Clears all the texture coordinates buffers.
+ */
+ public void disposeAllTextureCoordinatesBuffers() {
+ canvas.getBuffersManager().dispose(texturesCoordinatesBufferMap.values());
+ texturesCoordinatesBufferMap.clear();
+ }
+
+ /**
+ * Fill the vertex, color, index and wire index buffers
+ * of a given object.
+ * @param id the object id.
+ * @throws ObjectRemovedException if the object is now longer present.
+ */
+ private void fillBuffers(Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ TransformedElementsBuffer buf = vertexBufferMap.get(id);
+ if (buf != null) {
+ fillVertexBuffer(buf.getBuffer(), id, buf.getScale(), buf.getTranslate());
+ }
+
+ ElementsBuffer normalBuffer = normalBufferMap.get(id);
+ if (normalBuffer != null) {
+ fillNormalBuffer(normalBuffer, id);
+ }
+
+ ElementsBuffer colorBuffer = colorBufferMap.get(id);
+ if (colorBuffer != null) {
+ fillColorBuffer(colorBuffer, id);
+ }
+
+ ElementsBuffer textureCoordinatesBuffer = texturesCoordinatesBufferMap.get(id);
+ if (textureCoordinatesBuffer != null) {
+ fillTextureCoordinatesBuffer(textureCoordinatesBuffer, id);
+ }
+
+ IndicesBuffer indexBuffer = indexBufferMap.get(id);
+ if (indexBuffer != null) {
+ fillIndexBuffer(indexBuffer, id);
+ }
+
+ IndicesBuffer wireIndexBuffer = wireIndexBufferMap.get(id);
+ if (wireIndexBuffer != null) {
+ fillWireIndexBuffer(wireIndexBuffer, id);
+ }
+ }
+
+ private void fillVertexBuffer(ElementsBuffer vertexBuffer, Integer id, double[] scale, double[] translate) throws ObjectRemovedException, OutOfMemoryException {
+ fillVertexBuffer(vertexBuffer, id, 0x01 | 0x02 | 0x04 | 0x08, scale, translate);
+ }
+
+ private void fillVertexBuffer(ElementsBuffer vertexBuffer, Integer id, int coordinateMask, double[] scale, double[] translate) throws ObjectRemovedException, OutOfMemoryException {
+ int logMask = MainDataLoader.getLogMask(id);
+ int length = MainDataLoader.getDataSize(id);
+ FloatBuffer data = BufferAllocation.newFloatBuffer(length * 4);
+ MainDataLoader.fillVertices(id, data, 4, coordinateMask, scale, translate, logMask);
+ vertexBuffer.setData(data, 4);
+ }
+
+ private void fillNormalBuffer(ElementsBuffer normalBuffer, Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ int length = MainDataLoader.getDataSize(id);
+ FloatBuffer data = BufferAllocation.newFloatBuffer(length * 4);
+ MainDataLoader.fillNormals(id, getVertexBuffer(id).getData(), data, 4);
+ normalBuffer.setData(data, 4);
+ }
+
+ private void updateVertexBuffer(ElementsBuffer vertexBuffer, Integer id, int coordinateMask, double[] scale, double[] translate) throws ObjectRemovedException {
+ int logMask = MainDataLoader.getLogMask(id);
+ FloatBuffer data = vertexBuffer.getData();
+ MainDataLoader.fillVertices(id, data, 4, coordinateMask, scale, translate, logMask);
+ vertexBuffer.setData(data, 4);
+ }
+
+ private void fillTextureCoordinatesBuffer(ElementsBuffer colorBuffer, Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ int length = MainDataLoader.getDataSize(id);
+ FloatBuffer data = BufferAllocation.newFloatBuffer(length * 4);
+ MainDataLoader.fillTextureCoordinates(id, data, length);
+ colorBuffer.setData(data, 4);
+ }
+
+ private void fillColorBuffer(ElementsBuffer colorBuffer, Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ int length = MainDataLoader.getDataSize(id);
+ FloatBuffer data = BufferAllocation.newFloatBuffer(length * 4);
+ MainDataLoader.fillColors(id, data, 4);
+ colorBuffer.setData(data, 4);
+ }
+
+ private void fillIndexBuffer(IndicesBuffer indexBuffer, Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ int length = MainDataLoader.getIndicesSize(id);
+ IntBuffer data = BufferAllocation.newIntBuffer(length);
+
+ int actualLength = 0;
+ if (length != 0) {
+ /* Do not call JNI when the buffer is empty */
+ /* Because under Mac OS X, GetDirectBufferAddress returns a NULL pointer in this case */
+ /* This generates an exception in DataLoader_wrap.c */
+ int logMask = MainDataLoader.getLogMask(id);
+ actualLength = MainDataLoader.fillIndices(id, data, logMask);
+ }
+
+ /* Set the buffer size to the actual number of indices */
+ data.limit(actualLength);
+
+ indexBuffer.setData(data);
+ }
+
+ private void fillWireIndexBuffer(IndicesBuffer indexBuffer, Integer id) throws ObjectRemovedException, OutOfMemoryException {
+ int length = MainDataLoader.getWireIndicesSize(id);
+ IntBuffer data = BufferAllocation.newIntBuffer(length);
+
+ int actualLength = 0;
+ if (length != 0) {
+ /* Do not call JNI when the buffer is empty */
+ /* Because under Mac OS X, GetDirectBufferAddress returns a NULL pointer in this case */
+ /* This generates an exception in DataLoader_wrap.c */
+ int logMask = MainDataLoader.getLogMask(id);
+ actualLength = MainDataLoader.fillWireIndices(id, data, logMask);
+ }
+
+ /* Set the buffer size to the actual number of indices */
+ data.limit(actualLength);
+
+ indexBuffer.setData(data);
+ }
+
+ private static class TransformedElementsBuffer {
+
+ ElementsBuffer buffer;
+ double[][] factors;
+
+ TransformedElementsBuffer(ElementsBuffer buffer, double[][] factors) {
+ this.buffer = buffer;
+ this.factors = factors;
+ }
+
+ ElementsBuffer getBuffer() {
+ return buffer;
+ }
+
+ double[] getScale() {
+ return factors[0];
+ }
+
+ double[] getTranslate() {
+ return factors[1];
+ }
+
+ boolean isSameFactors(final double[][] factors) {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (this.factors[i][j] != factors[i][j]) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/DrawerVisitor.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/DrawerVisitor.java
new file mode 100755
index 000000000..20a198570
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/DrawerVisitor.java
@@ -0,0 +1,1334 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.SwingUtilities;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.Drawer;
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.texture.AbstractTextureDataProvider;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
+import org.scilab.forge.scirenderer.tranformations.TransformationStack;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.forge.scirenderer.utils.shapes.geometry.CubeFactory;
+import org.scilab.modules.graphic_objects.ObjectRemovedException;
+import org.scilab.modules.graphic_objects.arc.Arc;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.axes.AxesContainer;
+import org.scilab.modules.graphic_objects.axes.Camera.ViewType;
+import org.scilab.modules.graphic_objects.axis.Axis;
+import org.scilab.modules.graphic_objects.compound.Compound;
+import org.scilab.modules.graphic_objects.datatip.Datatip;
+import org.scilab.modules.graphic_objects.fec.Fec;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.figure.Figure;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObject;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+import org.scilab.modules.graphic_objects.graphicObject.Visitor;
+import org.scilab.modules.graphic_objects.graphicView.GraphicView;
+import org.scilab.modules.graphic_objects.imageplot.Grayplot;
+import org.scilab.modules.graphic_objects.imageplot.Matplot;
+import org.scilab.modules.graphic_objects.label.Label;
+import org.scilab.modules.graphic_objects.legend.Legend;
+import org.scilab.modules.graphic_objects.polyline.Polyline;
+import org.scilab.modules.graphic_objects.rectangle.Rectangle;
+import org.scilab.modules.graphic_objects.surface.Fac3d;
+import org.scilab.modules.graphic_objects.surface.Plot3d;
+import org.scilab.modules.graphic_objects.textObject.Text;
+import org.scilab.modules.graphic_objects.uicontrol.frame.Frame;
+import org.scilab.modules.graphic_objects.vectfield.Arrow;
+import org.scilab.modules.graphic_objects.vectfield.Champ;
+import org.scilab.modules.graphic_objects.vectfield.Segs;
+import org.scilab.modules.renderer.JoGLView.arrowDrawing.ArrowDrawer;
+import org.scilab.modules.renderer.JoGLView.axes.AxesDrawer;
+import org.scilab.modules.renderer.JoGLView.contouredObject.ContouredObjectDrawer;
+import org.scilab.modules.renderer.JoGLView.datatip.DatatipTextDrawer;
+import org.scilab.modules.renderer.JoGLView.interaction.InteractionManager;
+import org.scilab.modules.renderer.JoGLView.label.LabelManager;
+import org.scilab.modules.renderer.JoGLView.legend.LegendDrawer;
+import org.scilab.modules.renderer.JoGLView.mark.MarkSpriteManager;
+import org.scilab.modules.renderer.JoGLView.postRendering.PostRendered;
+import org.scilab.modules.renderer.JoGLView.text.TextManager;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+import org.scilab.modules.renderer.JoGLView.util.LightingUtils;
+import org.scilab.modules.renderer.JoGLView.util.OutOfMemoryException;
+
+/**
+ * @author Pierre Lando
+ */
+public class DrawerVisitor implements Visitor, Drawer, GraphicView {
+
+ /** Set of properties changed during a draw if auto-ticks is on for X axis. */
+ private static final Set<Integer> X_AXIS_TICKS_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_X_AXIS_TICKS_LOCATIONS__,
+ GraphicObjectProperties.__GO_X_AXIS_TICKS_LABELS__
+ ));
+
+ /** Set of properties changed during a draw if auto-ticks is on for Y axis. */
+ private static final Set<Integer> Y_AXIS_TICKS_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_Y_AXIS_TICKS_LOCATIONS__,
+ GraphicObjectProperties.__GO_Y_AXIS_TICKS_LABELS__
+ ));
+
+ /** Set of properties changed during a draw if auto-ticks is on for Z axis. */
+ private static final Set<Integer> Z_AXIS_TICKS_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_Z_AXIS_TICKS_LOCATIONS__,
+ GraphicObjectProperties.__GO_Z_AXIS_TICKS_LABELS__
+ ));
+
+ /** Set of figure properties for witch a change doesn't lead to a redraw */
+ private static final Set<Integer> SILENT_FIGURE_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_ROTATION_TYPE__,
+ GraphicObjectProperties.__GO_INFO_MESSAGE__,
+ GraphicObjectProperties.__GO_FIGURE_NAME__,
+ GraphicObjectProperties.__GO_AUTORESIZE__,
+ GraphicObjectProperties.__GO_POSITION__,
+ GraphicObjectProperties.__GO_SIZE__,
+ GraphicObjectProperties.__GO_ID__
+ ));
+
+ private static final boolean DEBUG_MODE = false;
+
+ private final Component component;
+ private final AxesContainer figure;
+ private final InteractionManager interactionManager;
+
+ private final ColorMapTextureDataProvider colorMapTextureDataProvider;
+
+ private final ScilabTextureManager textureManager;
+ private final MarkSpriteManager markManager;
+ private final LabelManager labelManager;
+ private final DataManager dataManager;
+ private final TextManager textManager;
+
+ private final ContouredObjectDrawer contouredObjectDrawer;
+ private final LegendDrawer legendDrawer;
+ protected final AxesDrawer axesDrawer;
+ private final AxisDrawer axisDrawer;
+ private final ArrowDrawer arrowDrawer;
+ private final FecDrawer fecDrawer;
+ private final DatatipTextDrawer datatipTextDrawer;
+
+ private DrawingTools drawingTools;
+ private Texture colorMapTexture;
+ private ColorMap colorMap;
+
+ private Axes currentAxes;
+ private Canvas canvas;
+
+ /**
+ * The map between the existing Figures' identifiers and their corresponding Visitor.
+ * Used to get access to the DrawerVisitor corresponding to a given Figure when the
+ * renderer module is accessed from another thread than the AWT's.
+ */
+ private final static Map<Integer, DrawerVisitor> visitorMap = new HashMap<Integer, DrawerVisitor>();
+ private final List<PostRendered> postRenderedList = new LinkedList<PostRendered>();
+ private final static Map<Integer, List<Integer>> openGLChildren = new HashMap<Integer, List<Integer>>();
+
+ public static int[] getSize() {
+ return new int[] {visitorMap.size(), openGLChildren.size()};
+ }
+
+ public DrawerVisitor(Component component, Canvas canvas, AxesContainer figure) {
+ GraphicController.getController().register(this);
+
+ this.component = component;
+ this.canvas = canvas;
+ this.figure = figure;
+
+ this.interactionManager = new InteractionManager(this);
+ this.dataManager = new DataManager(canvas);
+ this.textureManager = new ScilabTextureManager(this);
+ this.markManager = new MarkSpriteManager(canvas.getTextureManager());
+ this.textManager = new TextManager(canvas.getTextureManager());
+ this.labelManager = new LabelManager(canvas.getTextureManager());
+ this.axesDrawer = new AxesDrawer(this);
+ this.axisDrawer = new AxisDrawer(this);
+ this.arrowDrawer = new ArrowDrawer(this);
+ this.contouredObjectDrawer = new ContouredObjectDrawer(this, this.dataManager, this.markManager);
+ this.legendDrawer = new LegendDrawer(this);
+ this.fecDrawer = new FecDrawer(this);
+ this.colorMapTextureDataProvider = new ColorMapTextureDataProvider();
+ this.datatipTextDrawer = new DatatipTextDrawer(canvas.getTextureManager());
+
+ visitorMap.put(figure.getIdentifier(), this);
+ }
+
+ public static void changeVisitor(AxesContainer figure, DrawerVisitor visitor) {
+ if (visitor == null) {
+ visitorMap.remove(figure.getIdentifier());
+ } else {
+ visitorMap.put(figure.getIdentifier(), visitor);
+ }
+ }
+
+ public void setDrawingTools(DrawingTools drawingTools) {
+ this.drawingTools = drawingTools;
+ }
+
+ public DrawingTools getDrawingTools() {
+ return drawingTools;
+ }
+
+ public Canvas getCanvas() {
+ return canvas;
+ }
+
+ public void setCanvas(Canvas canvas) {
+ this.canvas = canvas;
+ }
+
+ /**
+ * @return the DataManager
+ */
+ public DataManager getDataManager() {
+ return dataManager;
+ }
+
+ /**
+ * @return the TextManager
+ */
+ public TextManager getTextManager() {
+ return textManager;
+ }
+
+ /**
+ * @return the LegendDrawer
+ */
+ public LegendDrawer getLegendDrawer() {
+ return legendDrawer;
+ }
+
+ /**
+ * Mark manager getter.
+ * @return the mark manager.
+ */
+ public MarkSpriteManager getMarkManager() {
+ return markManager;
+ }
+
+ /**
+ * @return the AxesDrawer
+ */
+ public AxesDrawer getAxesDrawer() {
+ return axesDrawer;
+ }
+
+ /**
+ * @return the ArrowDrawer
+ */
+ public ArrowDrawer getArrowDrawer() {
+ return arrowDrawer;
+ }
+
+ public ColorMap getColorMap() {
+ return colorMap;
+ }
+
+ public DatatipTextDrawer getDatatipTextDrawer() {
+ return datatipTextDrawer;
+ }
+
+ /**
+ * Returns the visitor corresponding to the Figure identifier.
+ * @param figureId the figure identifier.
+ * @return the visitor.
+ */
+ public static DrawerVisitor getVisitor(Integer figureId) {
+ return visitorMap.get(figureId);
+ }
+
+ public void addPostRendering(PostRendered postRendered) {
+ if (postRendered != null) {
+ postRenderedList.add(postRendered);
+ }
+ }
+
+ public void removePostRendering(PostRendered postRendered) {
+ postRenderedList.remove(postRendered);
+ }
+
+ @Override
+ public void draw(DrawingTools drawingTools) {
+ this.drawingTools = drawingTools;
+ if (figure instanceof Figure) {
+ visit((Figure) figure);
+ } else {
+ visit((Frame) figure);
+ }
+
+ for (PostRendered postRendered : postRenderedList) {
+ try {
+ postRendered.draw(drawingTools);
+ } catch (SciRendererException e) {
+ System.err.println("A 'PostRendered' is not drawable because: '" + e.getMessage() + "'");
+ }
+ }
+ drawingTools.getTransformationManager().useSceneCoordinate();
+ }
+
+ /**
+ * Ask the given object to accept visitor.
+ * @param childrenId array of object identifier.
+ */
+ public void askAcceptVisitor(Integer[] childrenId) {
+ if (childrenId != null) {
+
+ for (int i = childrenId.length - 1; i >= 0; --i) {
+ GraphicObject child = GraphicController.getController().getObjectFromId(childrenId[i]);
+ if (child != null) {
+ try {
+ child.accept(this);
+ } catch (ObjectRemovedException e) {
+ if (DEBUG_MODE) {
+ System.err.println("[DEBUG] Try to draw an already removed object");
+ System.err.println("[DEBUG] " + e);
+ System.err.println("[DEBUG] Skipped...");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @return true if it is a 2D view
+ */
+ public boolean is2DView() {
+ return currentAxes.getViewAsEnum() == ViewType.VIEW_2D;
+ }
+
+ @Override
+ public void visit(Axes axes) {
+ synchronized (axes) {
+ if (axes.isValid() && axes.getVisible()) {
+ try {
+ currentAxes = axes;
+ axesDrawer.computeRulers(axes);
+ axesDrawer.draw(axes);
+ } catch (SciRendererException e) {
+ invalidate(axes, e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void visit(Arc arc) {
+ if (arc.isValid() && arc.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, arc.getClipProperty());
+ try {
+ contouredObjectDrawer.draw(arc, currentAxes.getViewAsEnum() == ViewType.VIEW_2D);
+ } catch (OutOfMemoryException e) {
+ invalidate(arc, e);
+ } catch (SciRendererException e) {
+ invalidate(arc, e);
+ } catch (ObjectRemovedException e) {
+ invalidate(arc, e);
+ }
+ axesDrawer.disableClipping(arc.getClipProperty());
+ }
+ }
+
+ @Override
+ public void visit(Axis axis) {
+ if (axis.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, axis.getClipProperty());
+ axisDrawer.draw(currentAxes, axis);
+ axesDrawer.disableClipping(axis.getClipProperty());
+ }
+ }
+
+ @Override
+ public void visit(Compound compound) {
+ if (compound.getVisible()) {
+ askAcceptVisitor(compound.getChildren());
+ }
+ }
+
+ @Override
+ public void visit(Fec fec) throws ObjectRemovedException {
+ if (fec.isValid() && fec.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, fec.getClipProperty());
+ try {
+ fecDrawer.draw(fec);
+ } catch (OutOfMemoryException e) {
+ invalidate(fec, e);
+ }
+ axesDrawer.disableClipping(fec.getClipProperty());
+ }
+ }
+
+ @Override
+ public void visit(Figure figure) {
+ synchronized (figure) {
+ /** Set the current {@see ColorMap}. */
+ try {
+ Dimension dims = getCanvas().getDimension();
+ colorMap = figure.getColorMap();
+ drawingTools.clear(ColorFactory.createColor(colorMap, figure.getBackground()));
+ drawingTools.clearDepthBuffer();
+ if (figure.isValid() && figure.getVisible() && figure.getImmediateDrawing() && dims.width > 1 && dims.height > 1) {
+ askAcceptVisitor(figure.getChildren());
+ }
+ } catch (Exception e) {
+ System.err.println(e);
+ }
+ }
+ }
+
+ public void visit(Frame frame) {
+ synchronized (frame) {
+ /** Set the current {@see ColorMap}. */
+ try {
+ colorMap = frame.getColorMap();
+ drawingTools.clear(ColorFactory.createColor(colorMap, frame.getBackground()));
+ drawingTools.clearDepthBuffer();
+ if (frame.isValid() && frame.getVisible()) {
+ DrawerVisitor visitor = visitorMap.get(frame.getIdentifier());
+ if (visitor != null) {
+ Dimension dims = visitor.getCanvas().getDimension();
+ visitor.setDrawingTools(drawingTools);
+ if (dims.width > 1 && dims.height > 1) {
+ visitor.askAcceptVisitor(frame.getChildren());
+ }
+ }
+ }
+ } catch (Exception e) {
+ System.err.println(e);
+ }
+ }
+ }
+
+ @Override
+ public void visit(final Grayplot grayplot) {
+ if (grayplot.isValid() && grayplot.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, grayplot.getClipProperty());
+ try {
+ DefaultGeometry triangles = new DefaultGeometry();
+ triangles.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ triangles.setVertices(dataManager.getVertexBuffer(grayplot.getIdentifier()));
+ triangles.setColors(dataManager.getColorBuffer(grayplot.getIdentifier()));
+ triangles.setIndices(dataManager.getIndexBuffer(grayplot.getIdentifier()));
+ triangles.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+ Appearance trianglesAppearance = new Appearance();
+ drawingTools.draw(triangles, trianglesAppearance);
+ /*} catch (ObjectRemovedException e) {
+ invalidate(grayplot, e);
+ } catch (SciRendererException e) {
+ invalidate(grayplot, e);
+ } catch (OutOfMemoryException e) {
+ invalidate(grayplot, e);
+ }*/
+ } catch (Exception e) {
+ System.err.println(e);
+ e.printStackTrace();
+ }
+ axesDrawer.disableClipping(grayplot.getClipProperty());
+ }
+ }
+
+ @Override
+ public void visit(final Matplot matplot) {
+ if (matplot.isValid() && matplot.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, matplot.getClipProperty());
+ try {
+ if ((currentAxes != null) && (currentAxes.getXAxisLogFlag() || currentAxes.getYAxisLogFlag())) {
+ DefaultGeometry geometry = new DefaultGeometry();
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ geometry.setVertices(dataManager.getVertexBuffer(matplot.getIdentifier()));
+ geometry.setColors(dataManager.getColorBuffer(matplot.getIdentifier()));
+ geometry.setIndices(dataManager.getIndexBuffer(matplot.getIdentifier()));
+ geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+ Appearance appearance = new Appearance();
+ drawingTools.draw(geometry, appearance);
+ } else {
+ TransformationStack modelViewStack = drawingTools.getTransformationManager().getModelViewStack();
+ double[][] factors = currentAxes.getScaleTranslateFactors();
+ Double[] scale = matplot.getScale();
+ Double[] translate = matplot.getTranslate();
+
+ scale[0] *= factors[0][0];
+ scale[1] *= factors[0][1];
+
+ translate[0] = translate[0] * factors[0][0] + factors[1][0];
+ translate[1] = translate[1] * factors[0][1] + factors[1][1];
+
+ Transformation t = TransformationFactory.getTranslateTransformation(translate[0], translate[1], 0);
+ Transformation t2 = TransformationFactory.getScaleTransformation(scale[0], scale[1], 1);
+ modelViewStack.pushRightMultiply(t);
+ modelViewStack.pushRightMultiply(t2);
+ drawingTools.draw(textureManager.getTexture(matplot.getIdentifier()));
+ modelViewStack.pop();
+ modelViewStack.pop();
+ }
+ } catch (ObjectRemovedException e) {
+ invalidate(matplot, e);
+ } catch (SciRendererException e) {
+ invalidate(matplot, e);
+ } catch (OutOfMemoryException e) {
+ invalidate(matplot, e);
+ }
+ axesDrawer.disableClipping(matplot.getClipProperty());
+ }
+ }
+
+ @Override
+ public void visit(Label label) {
+ if (label.isValid() && label.getVisible() && !label.isEmpty()) {
+ try {
+ labelManager.draw(drawingTools, colorMap, label, axesDrawer);
+ } catch (SciRendererException e) {
+ invalidate(label, e);
+ }
+ }
+ }
+
+ @Override
+ public void visit(Legend legend) {
+ if (legend.isValid() && legend.getVisible()) {
+ try {
+ legendDrawer.draw(legend);
+ } catch (SciRendererException e) {
+ invalidate(legend, e);
+ }
+ }
+ }
+
+ @Override
+ public void visit(final Polyline polyline) {
+ synchronized (polyline) {
+ if (polyline.isValid() && polyline.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, polyline.getClipProperty());
+ try {
+ DefaultGeometry geometry = new DefaultGeometry();
+
+ geometry.setVertices(dataManager.getVertexBuffer(polyline.getIdentifier()));
+ geometry.setIndices(dataManager.getIndexBuffer(polyline.getIdentifier()));
+ geometry.setWireIndices(dataManager.getWireIndexBuffer(polyline.getIdentifier()));
+
+ final int style = polyline.getPolylineStyle();
+ if (style == 1 || style == 2 || style == 4 || style == 5) {
+ geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS_STRIP);
+ } else {
+ geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ }
+
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+
+ geometry.setPolygonOffsetMode(currentAxes.getCamera().getView() == ViewType.VIEW_3D);
+
+ /* Interpolated color rendering is used only for basic polylines for now. */
+ Appearance appearance = new Appearance();
+
+ if (polyline.getInterpColorMode() && style == 1) {
+ geometry.setTextureCoordinates(dataManager.getTextureCoordinatesBuffer(polyline.getIdentifier()));
+ appearance.setTexture(getColorMapTexture());
+ } else {
+ geometry.setColors(null);
+ }
+
+ Integer lineColor = polyline.getSelected() ? polyline.getSelectedColor() : polyline.getLineColor();
+ appearance.setLineColor(ColorFactory.createColor(colorMap, lineColor));
+ appearance.setLineWidth(polyline.getLineThickness().floatValue());
+ appearance.setLinePattern(polyline.getLineStyleAsEnum().asPattern());
+
+ if (!polyline.getInterpColorMode() || style != 1) {
+ int fillColor;
+
+ /*
+ * The line color is used as fill color for the filled patch polyline style
+ * whereas the background color is used for all the other styles.
+ */
+ if (style == 5) {
+ fillColor = lineColor;
+ } else {
+ fillColor = polyline.getBackground();
+ }
+
+ appearance.setFillColor(ColorFactory.createColor(colorMap, fillColor));
+ }
+
+ drawingTools.draw(geometry, appearance);
+
+ if (style == 4) {
+ arrowDrawer.drawArrows(polyline.getParentAxes(), polyline.getIdentifier(), polyline.getArrowSizeFactor(),
+ polyline.getLineThickness(), false, false, lineColor, true);
+ }
+
+ if (polyline.getMarkMode()) {
+ Texture sprite = markManager.getMarkSprite(polyline, colorMap, appearance);
+ ElementsBuffer positions = dataManager.getVertexBuffer(polyline.getIdentifier());
+ int offset = polyline.getMarkOffset();
+ int stride = polyline.getMarkStride();
+ drawingTools.draw(sprite, AnchorPosition.CENTER, positions, offset, stride, 0);
+ }
+ } catch (ObjectRemovedException e) {
+ invalidate(polyline, e);
+ } catch (OutOfMemoryException e) {
+ invalidate(polyline, e);
+ } catch (SciRendererException e) {
+ invalidate(polyline, e);
+ }
+ axesDrawer.disableClipping(polyline.getClipProperty());
+ askAcceptVisitor(polyline.getDatatips());
+ }
+ }
+ }
+
+ @Override
+ public void visit(Rectangle rectangle) {
+ if (rectangle.isValid() && rectangle.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, rectangle.getClipProperty());
+ try {
+ contouredObjectDrawer.draw(rectangle, currentAxes.getCamera().getView() == ViewType.VIEW_2D);
+ } catch (ObjectRemovedException e) {
+ invalidate(rectangle, e);
+ } catch (OutOfMemoryException e) {
+ invalidate(rectangle, e);
+ } catch (SciRendererException e) {
+ invalidate(rectangle, e);
+ }
+ axesDrawer.disableClipping(rectangle.getClipProperty());
+ }
+ }
+
+ /*
+ * To do:
+ * -use common code for both the Fac3d and Plot3d visit methods
+ * as they are mostly similar.
+ */
+ @Override
+ public void visit(final Fac3d fac3d) {
+ if (fac3d.isValid() && fac3d.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, fac3d.getClipProperty());
+ try {
+ if (fac3d.getSurfaceMode()) {
+ DefaultGeometry geometry = new DefaultGeometry();
+ geometry.setVertices(dataManager.getVertexBuffer(fac3d.getIdentifier()));
+ geometry.setNormals(dataManager.getNormalBuffer(fac3d.getIdentifier()));
+ geometry.setIndices(dataManager.getIndexBuffer(fac3d.getIdentifier()));
+
+ geometry.setPolygonOffsetMode(true);
+
+ /* Front-facing triangles */
+ Appearance appearance = new Appearance();
+ appearance.setMaterial(LightingUtils.getMaterial(fac3d.getMaterial()));
+ LightingUtils.setupLights(drawingTools.getLightManager(), currentAxes);
+
+ if (fac3d.getColorMode() != 0) {
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ /* Back-facing triangles */
+ if (fac3d.getHiddenColor() > 0) {
+ geometry.setFaceCullingMode(axesDrawer.getBackFaceCullingMode());
+ Appearance backTrianglesAppearance = new Appearance();
+ backTrianglesAppearance.setFillColor(ColorFactory.createColor(colorMap, fac3d.getHiddenColor()));
+ drawingTools.draw(geometry, backTrianglesAppearance);
+
+ // Now we will draw front face.
+ geometry.setFaceCullingMode(axesDrawer.getFrontFaceCullingMode());
+ } else {
+ geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+ }
+
+ if (fac3d.getColorFlag() == 0) {
+ appearance.setFillColor(ColorFactory.createColor(colorMap, Math.abs(fac3d.getColorMode())));
+ } else if (fac3d.getColorFlag() > 0) {
+ geometry.setTextureCoordinates(dataManager.getTextureCoordinatesBuffer(fac3d.getIdentifier()));
+ appearance.setTexture(getColorMapTexture());
+ } else {
+ geometry.setColors(null);
+ }
+ } else {
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ }
+
+ if ((fac3d.getColorMode() >= 0) && (fac3d.getLineThickness() > 0.0)) {
+ geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ geometry.setWireIndices(dataManager.getWireIndexBuffer(fac3d.getIdentifier()));
+ Integer lineColor = fac3d.getSelected() ? fac3d.getSelectedColor() : fac3d.getLineColor();
+ appearance.setLineColor(ColorFactory.createColor(colorMap, lineColor));
+ appearance.setLineWidth(fac3d.getLineThickness().floatValue());
+ }
+
+ drawingTools.draw(geometry, appearance);
+ LightingUtils.setLightingEnable(drawingTools.getLightManager(), false);
+ }
+
+ if (fac3d.getMarkMode()) {
+ Appearance appearance = null;
+ if (fac3d.getLineThickness() > 0.0) {
+ appearance = new Appearance();
+ appearance.setLineWidth(fac3d.getLineThickness().floatValue());
+ }
+
+ Texture texture = markManager.getMarkSprite(fac3d, colorMap, appearance);
+ ElementsBuffer positions = dataManager.getVertexBuffer(fac3d.getIdentifier());
+ drawingTools.draw(texture, AnchorPosition.CENTER, positions);
+ }
+ } catch (ObjectRemovedException e) {
+ invalidate(fac3d, e);
+ } catch (OutOfMemoryException e) {
+ invalidate(fac3d, e);
+ } catch (SciRendererException e) {
+ invalidate(fac3d, e);
+ }
+ axesDrawer.disableClipping(fac3d.getClipProperty());
+ }
+ }
+
+ @Override
+ public void visit(final Plot3d plot3d) {
+ if (plot3d.isValid() && plot3d.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, plot3d.getClipProperty());
+ try {
+ if (plot3d.getSurfaceMode()) {
+ DefaultGeometry geometry = new DefaultGeometry();
+ if (plot3d.getColorMode() != 0) {
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ } else {
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ }
+
+ geometry.setPolygonOffsetMode(true);
+
+ geometry.setVertices(dataManager.getVertexBuffer(plot3d.getIdentifier()));
+ geometry.setNormals(dataManager.getNormalBuffer(plot3d.getIdentifier()));
+ geometry.setIndices(dataManager.getIndexBuffer(plot3d.getIdentifier()));
+ /* Back-facing triangles */
+ if (plot3d.getHiddenColor() > 0) {
+ geometry.setFaceCullingMode(axesDrawer.getBackFaceCullingMode());
+ Appearance backTrianglesAppearance = new Appearance();
+ backTrianglesAppearance.setFillColor(ColorFactory.createColor(colorMap, plot3d.getHiddenColor()));
+ drawingTools.draw(geometry, backTrianglesAppearance);
+ }
+
+ /* Front-facing triangles */
+ Appearance appearance = new Appearance();
+ appearance.setMaterial(LightingUtils.getMaterial(plot3d.getMaterial()));
+ LightingUtils.setupLights(drawingTools.getLightManager(), currentAxes);
+
+ if (plot3d.getColorFlag() == 1) {
+ geometry.setColors(dataManager.getColorBuffer(plot3d.getIdentifier()));
+ } else {
+ geometry.setColors(null);
+ }
+
+ if (plot3d.getHiddenColor() > 0) {
+ geometry.setFaceCullingMode(axesDrawer.getFrontFaceCullingMode());
+ } else {
+ geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+ }
+
+ if (plot3d.getColorFlag() == 0) {
+ appearance.setFillColor(ColorFactory.createColor(colorMap, Math.abs(plot3d.getColorMode())));
+ }
+
+ if ((plot3d.getColorMode() >= 0) && (plot3d.getLineThickness() > 0.0)) {
+ geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ geometry.setWireIndices(dataManager.getWireIndexBuffer(plot3d.getIdentifier()));
+
+ appearance.setLinePattern(plot3d.getLineStyleAsEnum().asPattern());
+ Integer lineColor = plot3d.getSelected() ? plot3d.getSelectedColor() : plot3d.getLineColor();
+ appearance.setLineColor(ColorFactory.createColor(colorMap, lineColor));
+ appearance.setLineWidth(plot3d.getLineThickness().floatValue());
+ }
+ drawingTools.draw(geometry, appearance);
+ LightingUtils.setLightingEnable(drawingTools.getLightManager(), false);
+ }
+
+ if (plot3d.getMarkMode()) {
+ Appearance appearance = null;
+ if (plot3d.getLineThickness() > 0.0) {
+ appearance = new Appearance();
+ appearance.setLineWidth(plot3d.getLineThickness().floatValue());
+ }
+
+ Texture texture = markManager.getMarkSprite(plot3d, colorMap, appearance);
+ ElementsBuffer positions = dataManager.getVertexBuffer(plot3d.getIdentifier());
+ drawingTools.draw(texture, AnchorPosition.CENTER, positions);
+ }
+ } catch (ObjectRemovedException e) {
+ invalidate(plot3d, e);
+ } catch (OutOfMemoryException e) {
+ invalidate(plot3d, e);
+ } catch (SciRendererException e) {
+ invalidate(plot3d, e);
+ }
+ axesDrawer.disableClipping(plot3d.getClipProperty());
+ }
+
+ }
+
+ @Override
+ public void visit(Text text) {
+ if (text.isValid() && text.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, text.getClipProperty());
+ try {
+ textManager.draw(drawingTools, colorMap, text);
+ } catch (SciRendererException e) {
+ invalidate(text, e);
+ }
+ axesDrawer.disableClipping(text.getClipProperty());
+ }
+ }
+
+ @Override
+ public void visit(Datatip datatip) {
+ if (datatip.isValid() && datatip.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, datatip.getClipProperty());
+ try {
+ if (datatip.getMarkMode()) {
+ /* TODO: appearance can be not-null */
+ Texture texture = markManager.getMarkSprite(datatip, colorMap, null);
+ Vector3d markPos = DatatipTextDrawer.calculateAnchorPoint(datatip);
+ drawingTools.draw(texture, AnchorPosition.CENTER, markPos);
+ }
+ if (datatip.getTipLabelMode()) {
+ datatipTextDrawer.draw(drawingTools, colorMap, datatip);
+ }
+ } catch (SciRendererException e) {
+ invalidate((Text)datatip, e);
+ }
+ axesDrawer.disableClipping(datatip.getClipProperty());
+ }
+ }
+
+ @Override
+ public void visit(Arrow arrow) {
+ // TODO
+ System.out.println("How can I draw an arrow ?");
+ }
+
+ @Override
+ public void visit(final Champ champ) {
+ if (champ.isValid() && champ.getVisible()) {
+ axesDrawer.enableClipping(currentAxes, champ.getClipProperty());
+ try {
+ DefaultGeometry segments = new DefaultGeometry();
+ segments.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ segments.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ segments.setVertices(dataManager.getVertexBuffer(champ.getIdentifier()));
+ segments.setWireIndices(dataManager.getWireIndexBuffer(champ.getIdentifier()));
+ segments.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+ if (champ.getColored()) {
+ segments.setColors(dataManager.getColorBuffer(champ.getIdentifier()));
+ } else {
+ segments.setColors(null);
+ }
+
+ if (champ.getLineMode()) {
+ Appearance segmentAppearance = new Appearance();
+
+ /* If not colored, all segments have the same color. */
+ if (champ.getColored()) {
+ segmentAppearance.setLineColor(null);
+ } else {
+ segmentAppearance.setLineColor(ColorFactory.createColor(colorMap, champ.getLineColor()));
+ }
+
+ segmentAppearance.setLineWidth(champ.getLineThickness().floatValue());
+ segmentAppearance.setLinePattern(champ.getLineStyleAsEnum().asPattern());
+ drawingTools.draw(segments, segmentAppearance);
+ }
+
+ /* Draw the arrows */
+ if (champ.getArrowSize() != 0.0) {
+ arrowDrawer.drawArrows(champ.getParentAxes(), champ.getIdentifier(), champ.getArrowSize(), champ.getLineThickness(), false,
+ champ.getColored(), champ.getLineColor(), false);
+ }
+ } catch (OutOfMemoryException e) {
+ invalidate(champ, e);
+ } catch (ObjectRemovedException e) {
+ invalidate(champ, e);
+ } catch (SciRendererException e) {
+ invalidate(champ, e);
+ }
+ axesDrawer.disableClipping(champ.getClipProperty());
+ }
+ }
+
+ @Override
+ public void visit(final Segs segs) {
+ if (segs.isValid() && segs.getVisible() && segs.getArrows().size() != 0) {
+ axesDrawer.enableClipping(currentAxes, segs.getClipProperty());
+ try {
+ DefaultGeometry segments = new DefaultGeometry();
+ segments.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ segments.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ segments.setVertices(dataManager.getVertexBuffer(segs.getIdentifier()));
+ segments.setColors(dataManager.getColorBuffer(segs.getIdentifier()));
+ segments.setWireIndices(dataManager.getWireIndexBuffer(segs.getIdentifier()));
+ segments.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+
+ if (segs.getLineMode()) {
+ Appearance segmentAppearance = new Appearance();
+ segmentAppearance.setLineColor(null);
+ segmentAppearance.setLineWidth(segs.getLineThickness().floatValue());
+ segmentAppearance.setLinePattern(segs.getLineStyleAsEnum().asPattern());
+ drawingTools.draw(segments, segmentAppearance);
+ }
+
+ /*
+ * Segs does not derive from ContouredObject but Arrow does, hence we have to get the former's first Arrow
+ * in order to obtain the latter's Mark (all arrows are supposed to have the same contour properties for now).
+ */
+ if (segs.getMarkMode()) {
+ Texture texture = markManager.getMarkSprite(segs.getIdentifier(), segs.getArrows().get(0).getMark(), colorMap, null);
+ ElementsBuffer positions = dataManager.getVertexBuffer(segs.getIdentifier());
+ // Take only into account start-end of segs and not the arrow head.
+ positions.getData().limit(segs.getNumberArrows() * 2 * 4);
+ drawingTools.draw(texture, AnchorPosition.CENTER, positions);
+ positions.getData().limit(positions.getData().capacity());
+ }
+
+ /* Draw the arrows */
+ if (segs.getArrowSize() != 0.0) {
+ arrowDrawer.drawArrows(segs.getParentAxes(), segs.getIdentifier(), segs.getArrowSize(), segs.getLineThickness(), true,
+ true, segs.getLineColor(), false);
+ }
+ } catch (OutOfMemoryException e) {
+ invalidate(segs, e);
+ } catch (ObjectRemovedException e) {
+ invalidate(segs, e);
+ } catch (SciRendererException e) {
+ invalidate(segs, e);
+ }
+ axesDrawer.disableClipping(segs.getClipProperty());
+ }
+ }
+
+ @Override
+ public void updateObject(Integer id, int property) {
+ /*
+ * Check if property is CHILDREN and if there is a new child I should care about
+ */
+ Integer type = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
+ int objectStyle = (type == GraphicObjectProperties.__GO_UICONTROL__ ? (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_STYLE__) : -1);
+ if (id.intValue() != figure.getIdentifier().intValue()
+ && ((type == GraphicObjectProperties.__GO_UICONTROL__ && objectStyle != GraphicObjectProperties.__GO_UI_FRAME__)
+ || type == GraphicObjectProperties.__GO_UIMENU__)) {
+ return;
+ }
+
+ if (property == GraphicObjectProperties.__GO_CHILDREN__) {
+ if (id.intValue() != figure.getIdentifier().intValue()) {
+ /* Ignore children that are not mine */
+ return;
+ }
+ Integer[] children = GraphicController.getController().getObjectFromId(id).getChildren();
+ List<Integer> currentOpenGLChildren = openGLChildren.get(id);
+ if (currentOpenGLChildren == null) {
+ /* No openGLChildren in cache, create empty one */
+ openGLChildren.put(id, new ArrayList<Integer>());
+ currentOpenGLChildren = openGLChildren.get(id);
+ }
+ List<Integer> updatedOpenGLChildren = new ArrayList<Integer>();
+ for (int i = 0 ; i < children.length ; ++i) {
+ Integer currentType = (Integer) GraphicController.getController().getProperty(children[i], GraphicObjectProperties.__GO_TYPE__);
+ if (currentType != GraphicObjectProperties.__GO_UICONTROL__ && currentType != GraphicObjectProperties.__GO_UIMENU__) {
+ updatedOpenGLChildren.add(children[i]);
+ }
+ }
+ if (currentOpenGLChildren.size() == updatedOpenGLChildren.size()) {
+ /* No change made on openGL children => nothing to do */
+ return;
+ } else {
+ openGLChildren.put(id, updatedOpenGLChildren);
+ }
+ }
+
+ try {
+ if (needUpdate(id, property)) {
+ if (GraphicObjectProperties.__GO_COLORMAP__ == property) {
+ labelManager.disposeAll();
+ dataManager.disposeAllColorBuffers();
+ dataManager.disposeAllTextureCoordinatesBuffers();
+ markManager.disposeAll();
+ textManager.disposeAll();
+ axesDrawer.disposeAll();
+ fecDrawer.updateAll();
+ colorMapTextureDataProvider.update();
+ datatipTextDrawer.disposeAll();
+ textureManager.disposeAll();
+ } else {
+ labelManager.update(id, property);
+ dataManager.update(id, property);
+ markManager.update(id, property);
+ textManager.update(id, property);
+ axesDrawer.update(id, property);
+ legendDrawer.update(id, property);
+ fecDrawer.update(id, property);
+ datatipTextDrawer.update(id, property);
+ }
+
+ if (GraphicObjectProperties.__GO_ANTIALIASING__ == property) {
+ canvas.setAntiAliasingLevel(figure.getAntialiasing());
+ }
+
+ Figure parentFigure = (Figure) GraphicController.getController().getObjectFromId(figure.getParentFigure());
+ if (figure.getVisible() && parentFigure != null && parentFigure.getVisible()) {
+ if (isImmediateDrawing(id)) {
+ if (GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__ == property) {
+ canvas.redrawAndWait();
+ } else {
+ canvas.redraw();
+ }
+ }
+ }
+ }
+
+ if (GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__ == property && !isImmediateDrawing(id)) {
+ canvas.waitImage();
+ }
+
+ } catch (OutOfMemoryException e) {
+ invalidate(GraphicController.getController().getObjectFromId(id), e);
+ } catch (ObjectRemovedException e) {
+ // Object has been removed before draw : do nothing.
+ }
+ }
+
+ /**
+ * Check if the given changed property make the figure out of date.
+ * @param id the object updated
+ * @param property the changed property.
+ * @return true id the given changed property make the figure out of date.
+ */
+ protected boolean needUpdate(Integer id, int property) {
+ GraphicObject object = GraphicController.getController().getObjectFromId(id);
+ int objectType = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
+ int objectStyle = (objectType == GraphicObjectProperties.__GO_UICONTROL__ ? (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_STYLE__) : -1);
+ if ((object != null) && isFigureChild(id) || (objectType == GraphicObjectProperties.__GO_UICONTROL__ && objectStyle == GraphicObjectProperties.__GO_UI_FRAME__)
+ && objectType != GraphicObjectProperties.__GO_UIMENU__ && objectType != GraphicObjectProperties.__GO_UI_FRAME_BORDER__) {
+
+ if (GraphicObjectProperties.__GO_VALID__ == property) {
+ return false;
+ }
+
+ if (object instanceof Axes) {
+ Axes axes = (Axes) object;
+
+ if ((axes.getXAxisAutoTicks() && X_AXIS_TICKS_PROPERTIES.contains(property)) ||
+ (axes.getYAxisAutoTicks() && Y_AXIS_TICKS_PROPERTIES.contains(property)) ||
+ (axes.getZAxisAutoTicks() && Z_AXIS_TICKS_PROPERTIES.contains(property))) {
+ return false;
+ }
+
+ if ((!axes.getXAxisAutoTicks() && X_AXIS_TICKS_PROPERTIES.contains(property)) ||
+ (!axes.getYAxisAutoTicks() && Y_AXIS_TICKS_PROPERTIES.contains(property)) ||
+ (!axes.getZAxisAutoTicks() && Z_AXIS_TICKS_PROPERTIES.contains(property))) {
+ axesDrawer.computeMargins(axes);
+ return true;
+ }
+
+ if (property != GraphicObjectProperties.__GO_CHILDREN__) {
+ axesDrawer.computeRulers(axes);
+ }
+ }
+
+ if (object instanceof Label || object instanceof Legend) {
+ GraphicObject parent = GraphicController.getController().getObjectFromId(object.getParent());
+ if (parent instanceof Axes) {
+ Axes axes = (Axes) parent;
+ if (axes.getXAxisLabel().equals(id) ||
+ axes.getYAxisLabel().equals(id) ||
+ axes.getZAxisLabel().equals(id) ||
+ axes.getTitle().equals(id)) {
+ labelManager.update(id, property);
+ axesDrawer.computeMargins(axes);
+ } else if (object instanceof Legend && (property == GraphicObjectProperties.__GO_LEGEND_LOCATION__ || property == GraphicObjectProperties.__GO_LINE_WIDTH__)) {
+ legendDrawer.update(id, property);
+ axesDrawer.computeMargins(axes);
+ }
+ }
+ } else if (object instanceof Figure) {
+ if (property == GraphicObjectProperties.__GO_SIZE__
+ || property == GraphicObjectProperties.__GO_AXES_SIZE__
+ || property == GraphicObjectProperties.__GO_CHILDREN__
+ || property == GraphicObjectProperties.__GO_POSITION__) {
+ Figure fig = (Figure) object;
+ for (Integer gid : fig.getChildren()) {
+ GraphicObject go = GraphicController.getController().getObjectFromId(gid);
+ if (go instanceof Axes) {
+ axesDrawer.computeRulers((Axes) go);
+ }
+ }
+ }
+
+ if (SILENT_FIGURE_PROPERTIES.contains(property)) {
+ return false;
+ }
+ } else if (object instanceof Frame
+ && id.intValue() == figure.getIdentifier().intValue()
+ && property == GraphicObjectProperties.__GO_POSITION__) {
+ Frame fig = (Frame) object;
+ for (Integer gid : fig.getChildren()) {
+ GraphicObject go = GraphicController.getController().getObjectFromId(gid);
+ if (go instanceof Axes) {
+ axesDrawer.computeRulers((Axes) go);
+ }
+ }
+
+ } else if (object instanceof Axes && property == GraphicObjectProperties.__GO_X_AXIS_LOCATION__ ||
+ property == GraphicObjectProperties.__GO_Y_AXIS_LOCATION__ || property == GraphicObjectProperties.__GO_AUTO_MARGINS__) {
+ axesDrawer.computeMargins((Axes) object);
+ }
+
+ if (!object.isValid()) {
+ GraphicController.getController().setProperty(id, GraphicObjectProperties.__GO_VALID__, true);
+ }
+
+ return true;
+ }
+ // Special case if top level figure colormap/immediate_drawing has been updated, force redraw
+ if ((property == GraphicObjectProperties.__GO_COLORMAP__ || property == GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__)
+ && id.intValue() == figure.getParentFigure().intValue()) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isImmediateDrawing(Integer id) {
+ Integer parentId = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_PARENT_FIGURE__);
+ if (figure instanceof Frame) {
+ parentId = figure.getParentFigure();
+ }
+ if (figure instanceof Figure && (parentId == null || !parentId.equals(figure.getIdentifier()))) {
+ return false;
+ } else {
+ Boolean b = (Boolean) GraphicController.getController().getProperty(parentId, GraphicObjectProperties.__GO_IMMEDIATE_DRAWING__);
+ return (b == null) ? false : b;
+ }
+ }
+
+ @Override
+ public void createObject(Integer id) {
+ }
+
+ @Override
+ public void deleteObject(Integer id) {
+ Integer type = (Integer) GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_TYPE__);
+ if (!figure.getIdentifier().equals(id) && type == GraphicObjectProperties.__GO_UICONTROL__ || type == GraphicObjectProperties.__GO_UIMENU__) {
+ return; // Not of my managed openGL children
+ }
+
+ openGLChildren.remove(id);
+
+ if (isImmediateDrawing(id)) {
+ canvas.redraw();
+ }
+
+ dataManager.dispose(id);
+ markManager.dispose(id);
+ textManager.dispose(id);
+ labelManager.dispose(id);
+ axesDrawer.dispose(id);
+ legendDrawer.dispose(id);
+ fecDrawer.dispose(id);
+ textureManager.dispose(id);
+ /*
+ * Check we are deleting Figure managed by DrawerVisitor(this)
+ * Otherwise do nothing on deletion.
+ */
+ if (!figure.getIdentifier().equals(id)) {
+ return;
+ }
+
+ visitorMap.remove(id);
+ GraphicController.getController().unregister(this);
+ if (SwingUtilities.isEventDispatchThread()) {
+ canvas.destroy();
+ } else {
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ canvas.destroy();
+ }
+ });
+ } catch (Exception e) { }
+ }
+ }
+
+ /**
+ * Check if the given id correspond to a child of the current {@see Figure}.
+ * @param id the given id.
+ * @return true if the given id correspond to a child of the current {@see Figure}.
+ */
+ private boolean isFigureChild(Integer id) {
+ if (id.intValue() == figure.getIdentifier().intValue()) {
+ return true;
+ }
+
+ Object parentObject = GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_PARENT__);
+ Integer parentUID = parentObject == null ? 0 : (Integer) parentObject;
+ while (parentUID != 0) {
+
+ if (figure.getIdentifier().intValue() == parentUID.intValue()) {
+ return true;
+ }
+
+ Integer parentStyle = (Integer) GraphicController.getController().getProperty(parentUID, GraphicObjectProperties.__GO_STYLE__);
+ if (parentStyle != null && parentStyle.intValue() == GraphicObjectProperties.__GO_UI_FRAME__) {
+ // Drop drawing if parent is a Frame and I'm not the dedicated visitor.
+ return false;
+ }
+
+ parentObject = GraphicController.getController().getProperty(parentUID, GraphicObjectProperties.__GO_PARENT__);
+ parentUID = parentObject == null ? 0 : (Integer) parentObject;
+
+ }
+ return false;
+ }
+
+ /**
+ * Invalidate the given graphic object and inform the user.
+ * @param graphicObject the graphic object to invalidate
+ * @param exception the cause of invalidation.
+ */
+ public void invalidate(GraphicObject graphicObject, Exception exception) {
+ if (DEBUG_MODE) {
+ System.err.println("The " + graphicObject.getType() + " \"" + graphicObject.getIdentifier()
+ + "\" has been invalidated: " + exception.getMessage());
+ exception.printStackTrace();
+ }
+ GraphicController.getController().setProperty(graphicObject.getIdentifier(), GraphicObjectProperties.__GO_VALID__, false);
+ }
+
+ public LabelManager getLabelManager() {
+ return labelManager;
+ }
+
+ public Texture getColorMapTexture() {
+ if (colorMapTexture == null) {
+ colorMapTexture = canvas.getTextureManager().createTexture();
+ colorMapTexture.setMagnificationFilter(Texture.Filter.NEAREST);
+ colorMapTexture.setMinifyingFilter(Texture.Filter.NEAREST);
+ colorMapTexture.setSWrappingMode(Texture.Wrap.CLAMP);
+ colorMapTexture.setTWrappingMode(Texture.Wrap.CLAMP);
+ colorMapTexture.setDataProvider(colorMapTextureDataProvider);
+ }
+ return colorMapTexture;
+ }
+
+ /**
+ * Figure getter.
+ * @return the figure this visitor draw.
+ */
+ public AxesContainer getFigure() {
+ return figure;
+ }
+
+ public Axes getAxes() {
+ return currentAxes;
+ }
+
+ private Geometry cube;
+ public Geometry getCube() {
+ if (cube == null) {
+ cube = CubeFactory.createCube(canvas);
+ }
+ return cube;
+ }
+
+ /**
+ * Component getter.
+ * @return return the attached component.
+ */
+ public Component getComponent() {
+ return component;
+ }
+
+ /**
+ * Interaction manager getter
+ * @return the interaction manager.
+ */
+ public InteractionManager getInteractionManager() {
+ return interactionManager;
+ }
+
+ private class ColorMapTextureDataProvider extends AbstractTextureDataProvider {
+ byte[] whiteColor = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
+ byte[] blackColor = {0x00, 0x00, 0x00, (byte) 0xFF};
+
+ public ColorMapTextureDataProvider() {
+ super();
+ this.imageType = ImageType.RGBA_BYTE;
+ }
+
+ @Override
+ public Dimension getTextureSize() {
+ return new Dimension(colorMap.getSize() + 2, 1);
+ }
+
+ @Override
+ public ByteBuffer getData() {
+ Double[] data = colorMap.getData();
+ ByteBuffer buffer = ByteBuffer.allocate(4 * ((data.length / 3) + 2));
+
+ /* White and black are written in the first and second positions */
+ buffer.put(whiteColor);
+ buffer.put(blackColor);
+
+ for (int i = 0 ; i < data.length / 3 ; i++) {
+ buffer.put(toByte(data[i]));
+ buffer.put(toByte(data[i + colorMap.getSize()].floatValue()));
+ buffer.put(toByte(data[i + 2 * colorMap.getSize()].floatValue()));
+ buffer.put(toByte(1));
+ }
+ buffer.rewind();
+ return buffer;
+ }
+
+ @Override
+ public ByteBuffer getSubData(int x, int y, int width, int height) {
+ /*
+ * For the moment, we presuppose that x and y are 0 and that
+ * width is equal to the colormap's total size (with height == 1).
+ * To be correctly implemented.
+ */
+ return getData();
+ }
+
+ @Override
+ public boolean isValid() {
+ return true;
+ }
+
+ public void update() {
+ fireUpdate();
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/FecDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/FecDrawer.java
new file mode 100755
index 000000000..9f087e3eb
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/FecDrawer.java
@@ -0,0 +1,291 @@
+package org.scilab.modules.renderer.JoGLView;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.texture.AbstractTextureDataProvider;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.modules.graphic_objects.ObjectRemovedException;
+import org.scilab.modules.graphic_objects.fec.Fec;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+import org.scilab.modules.renderer.JoGLView.util.OutOfMemoryException;
+
+import java.awt.Dimension;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Pierre Lando
+ */
+class FecDrawer {
+
+ /** Set of properties that affect the texture. */
+ private static final Set<Integer> TEXTURE_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_Z_BOUNDS__,
+ GraphicObjectProperties.__GO_DATA_MODEL__,
+ GraphicObjectProperties.__GO_COLOR_RANGE__,
+ GraphicObjectProperties.__GO_OUTSIDE_COLOR__
+ ));
+
+ /** The parent drawer visitor. */
+ private final DrawerVisitor drawerVisitor;
+
+ /** Map of texture sorted by fec identifier */
+ private final Map<Integer, Texture> textureMap;
+
+ /**
+ * Default constructor.
+ * @param drawerVisitor the parent drawer visitor.
+ */
+ FecDrawer(DrawerVisitor drawerVisitor) {
+ this.drawerVisitor = drawerVisitor;
+ textureMap = new HashMap<Integer, Texture>();
+ }
+
+ /**
+ * Draw the given fec.
+ * @param fec given fec object.
+ * @throws ObjectRemovedException
+ */
+ public void draw(Fec fec) throws ObjectRemovedException, OutOfMemoryException {
+ if (fec.getVisible()) {
+
+ DrawingTools drawingTools = drawerVisitor.getDrawingTools();
+ DataManager dataManager = drawerVisitor.getDataManager();
+ ColorMap colorMap = drawerVisitor.getColorMap();
+
+ try {
+ DefaultGeometry geometry = new DefaultGeometry();
+ Appearance appearance = new Appearance();
+
+ geometry.setVertices(dataManager.getVertexBuffer(fec.getIdentifier()));
+ geometry.setTextureCoordinates(dataManager.getTextureCoordinatesBuffer(fec.getIdentifier()));
+ geometry.setIndices(dataManager.getIndexBuffer(fec.getIdentifier()));
+
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+ geometry.setPolygonOffsetMode(true);
+
+ if (fec.getLineMode()) {
+ geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ geometry.setWireIndices(dataManager.getWireIndexBuffer(fec.getIdentifier()));
+ appearance.setLineColor(ColorFactory.createColor(colorMap, fec.getLineColor()));
+ }
+ appearance.setTexture(getTexture(fec));
+
+ drawingTools.draw(geometry, appearance);
+ } catch (SciRendererException e) {
+ System.err.println("A '" + fec.getType() + "' is not drawable because: '" + e.getMessage() + "'");
+ }
+ }
+ }
+
+ /**
+ * Texture getter.
+ *
+ * This method return the texture associated with the given fec object.
+ * If no texture is associated, a new one will be created.
+ *
+ * If the texture to return have no data provider a new one is created.
+ *
+ * @param fec given fec object.
+ * @return the texture associated with the given fec.
+ */
+ private Texture getTexture(Fec fec) {
+ Texture texture = textureMap.get(fec.getIdentifier());
+ if (texture == null) {
+ texture = drawerVisitor.getCanvas().getTextureManager().createTexture();
+ texture.setSWrappingMode(Texture.Wrap.CLAMP);
+ texture.setTWrappingMode(Texture.Wrap.CLAMP);
+ texture.setMagnificationFilter(Texture.Filter.NEAREST);
+ texture.setMinifyingFilter(Texture.Filter.NEAREST);
+ textureMap.put(fec.getIdentifier(), texture);
+ }
+ if (texture.getDataProvider() == null) {
+ texture.setDataProvider(new FecColorTexture(fec));
+ }
+ return texture;
+ }
+
+ /**
+ * Manage changes on the given object.
+ *
+ * If the given property affect the texture of a Fec object, the data provider will be reset.
+ *
+ * @param id the given object id.
+ * @param property the changed property.
+ */
+ public void update(Integer id, int property) {
+ if (TEXTURE_PROPERTIES.contains(property)) {
+ Texture texture = textureMap.get(id);
+ if (texture != null) {
+ texture.setDataProvider(null);
+ }
+ }
+ }
+
+ /**
+ * Update all texture.
+ * Reset all texture data provider.
+ * @throws ObjectRemovedException
+ */
+ void updateAll() throws ObjectRemovedException, OutOfMemoryException {
+ for (Map.Entry<Integer, Texture> entry : textureMap.entrySet()) {
+ drawerVisitor.getDataManager().updateTextureCoordinatesBuffer(entry.getKey());
+ entry.getValue().setDataProvider(null);
+ }
+ }
+
+ /**
+ * Dispose the given object.
+ * @param id given object identifier.
+ */
+ public void dispose(Integer id) {
+ /** TODO
+ Texture texture = textureMap.get(id);
+ if (texture != null) {
+ drawerVisitor.getCanvas().getTextureManager().release(texture);
+ }
+ **/
+ textureMap.remove(id);
+ }
+
+ /**
+ * This class is an implementation of {@link TextureDataProvider} that provide texture data for a given fec object.
+ *
+ * The texture is a 1D texture with:
+ * - at first the minimal outside color.
+ * - main colors:
+ * . If colorRange is enable, all color in the color range, in order.
+ * . If colorRange is disable, all color from the color map, in order.
+ * - at last, the maximal outside color.
+ *
+ * The outside colors are always presents.
+ * .As user defined outside colors if any.
+ * .As minimal and maximal color from the main colors otherwise.
+ */
+ private class FecColorTexture extends AbstractTextureDataProvider {
+
+ /** The fec object for which this class provide texture data */
+ private final Fec fec;
+
+ /**
+ * Default constructor.
+ * @param fec The fec object for which this class will provide texture data.
+ */
+ public FecColorTexture(Fec fec) {
+ this.fec = fec;
+ this.imageType = ImageType.RGBA_BYTE;
+ }
+
+ @Override
+ public Dimension getTextureSize() {
+ return new Dimension(getTextureLength(), 1);
+ }
+
+ @Override
+ public ByteBuffer getData() {
+ ColorMap colorMap = drawerVisitor.getColorMap();
+ Integer[] outsideColor = fec.getOutsideColor();
+
+ ByteBuffer buffer = ByteBuffer.allocate(4 * getTextureLength());
+
+ int min;
+ int max;
+ if (useColorRange()) {
+ Integer[] colorRange = fec.getColorRange();
+ min = Math.max(1, colorRange[0]);
+ max = Math.min(colorMap.getSize(), colorRange[1]);
+ } else {
+ min = 1;
+ max = colorMap.getSize();
+ }
+
+
+ if (outsideColor[0] == 0) {
+ buffer.put(toByte(ColorFactory.createRGBAColor(colorMap, min)));
+ } else if (outsideColor[0] > 0) {
+ buffer.put(toByte(ColorFactory.createRGBAColor(colorMap, outsideColor[0])));
+ } else {
+ // TODO: transparency.
+ buffer.put(toByte(ColorFactory.createRGBAColor(colorMap, -2)));
+ }
+
+ for (int i = min; i <= max; i++) {
+ buffer.put(toByte(ColorFactory.createRGBAColor(colorMap, i)));
+ }
+
+ if (outsideColor[1] == 0) {
+ buffer.put(toByte(ColorFactory.createRGBAColor(colorMap, max)));
+ } else if (outsideColor[1] > 0) {
+ buffer.put(toByte(ColorFactory.createRGBAColor(colorMap, outsideColor[1])));
+ } else {
+ // TODO: transparency.
+ buffer.put(toByte(ColorFactory.createRGBAColor(colorMap, -2)));
+ }
+
+ buffer.rewind();
+ return buffer;
+ }
+
+ @Override
+ public ByteBuffer getSubData(int x, int y, int width, int height) {
+ ByteBuffer buffer = getData();
+ ByteBuffer tempBuffer = ByteBuffer.allocate(4 * width * height);
+ buffer.position(x + y * getTextureLength());
+ byte[] data = new byte[4];
+ for (int i = x; i < x + width; i++) {
+ for (int j = y; j < y + height; j++) {
+ buffer.get(data);
+ tempBuffer.put(data);
+ }
+ }
+ tempBuffer.rewind();
+ buffer.rewind();
+ return tempBuffer;
+ }
+
+ @Override
+ public boolean isValid() {
+ return true;
+ }
+
+ /**
+ * Check if color range option is enable.
+ * @return true if the color range is valid and not [0, 0].
+ */
+ private boolean useColorRange() {
+ Integer[] colorRange = fec.getColorRange();
+ return (colorRange != null) && (colorRange.length == 2) && ((colorRange[0] != 0) || (colorRange[1] != 0));
+ }
+
+ /**
+ * Compute the texture length.
+ * @return the texture length.
+ */
+ private int getTextureLength() {
+ ColorMap colorMap = drawerVisitor.getColorMap();
+ int length;
+ if (useColorRange()) {
+ Integer[] colorRange = fec.getColorRange();
+ int min = Math.max(1, colorRange[0]);
+ int max = Math.min(colorMap.getSize(), colorRange[1]);
+ length = 1 + max - min;
+ } else {
+ length = colorMap.getSize();
+ }
+
+ // For outside colors.
+ length += 2;
+ return length;
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/ScilabTextureManager.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/ScilabTextureManager.java
new file mode 100755
index 000000000..144471a7e
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/ScilabTextureManager.java
@@ -0,0 +1,201 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.texture.AbstractTextureDataProvider;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.modules.graphic_objects.MainDataLoader;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicView.GraphicView;
+import org.scilab.modules.renderer.JoGLView.util.BufferAllocation;
+import org.scilab.modules.renderer.JoGLView.util.OutOfMemoryException;
+
+import java.awt.Dimension;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Pierre Lando
+ */
+public class ScilabTextureManager {
+
+ private final Map<Integer, Texture> hashMap = new HashMap<Integer, Texture>();
+ private final DrawerVisitor drawerVisitor;
+ private final Canvas canvas;
+
+
+ public ScilabTextureManager(DrawerVisitor drawerVisitor) {
+ this.drawerVisitor = drawerVisitor;
+ this.canvas = drawerVisitor.getCanvas();
+ }
+
+ /**
+ * {@link Texture} getter.
+ * @param identifier object identifier.
+ * @return the {@link Texture} used to drawn the object who have the given identifier.
+ */
+ public Texture getTexture(Integer identifier) {
+ Texture texture = hashMap.get(identifier);
+ if (texture == null) {
+ texture = canvas.getTextureManager().createTexture();
+ texture.setDataProvider(new ScilabTextureDataProvider(identifier));
+ texture.setMagnificationFilter(Texture.Filter.NEAREST);
+ texture.setMinifyingFilter(Texture.Filter.NEAREST);
+ hashMap.put(identifier, texture);
+ }
+ return texture;
+ }
+
+ public void dispose(Integer identifier) {
+ Texture texture = hashMap.get(identifier);
+ if (texture != null) {
+ hashMap.remove(identifier);
+ canvas.getTextureManager().dispose(texture);
+ }
+ }
+
+ public void disposeAll() {
+ for (Map.Entry<Integer, Texture> entry : hashMap.entrySet()) {
+ Texture t = entry.getValue();
+ if (t != null) {
+ canvas.getTextureManager().dispose(t);
+ }
+ }
+
+ hashMap.clear();
+ }
+
+ private class ScilabTextureDataProvider extends AbstractTextureDataProvider implements GraphicView {
+
+ private final Integer identifier;
+ private Dimension dimension;
+ private int datatype = -1;
+ private int iType = -1;
+ private boolean isValid;
+ private boolean isRowOrder;
+ private ByteBuffer buffer;
+
+ public ScilabTextureDataProvider(Integer identifier) {
+ this.identifier = identifier;
+ this.isValid = (identifier != null);
+
+ if (isValid()) {
+ updateData();
+ }
+ GraphicController.getController().register(this);
+ }
+
+ @Override
+ public boolean isRowMajorOrder() {
+ return isRowOrder;
+ }
+
+ private void updateData() {
+ int width = MainDataLoader.getTextureWidth(identifier);
+ int height = MainDataLoader.getTextureHeight(identifier);
+ int gltype = MainDataLoader.getTextureGLType(identifier);
+ int itype = MainDataLoader.getTextureImageType(identifier);
+ int datatype = MainDataLoader.getTextureDataType(identifier);
+ boolean isRowOrder = MainDataLoader.isTextureRowOrder(identifier);
+ // todo gerer le cas itype == -1;
+ imageType = ImageType.fromInt(gltype);
+ if (dimension == null || dimension.width != width || dimension.height != height || itype != iType || this.isRowOrder != isRowOrder || this.datatype != datatype) {
+ dimension = new Dimension(width, height);
+ this.isRowOrder = isRowOrder;
+ this.datatype = datatype;
+
+ // 3 is MATPLOT_INDEX
+ dispose(iType == 3);
+ iType = itype;
+ }
+
+ fireUpdate();
+ }
+
+ public void dispose(boolean isIndex) {
+ if (buffer != null) {
+ if (isIndex) {
+ MainDataLoader.disposeTextureData(identifier, buffer);
+ }
+ buffer = null;
+ }
+ }
+
+ @Override
+ public Dimension getTextureSize() {
+ if (isValid()) {
+ return new Dimension(dimension);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public ByteBuffer getData() {
+ if (buffer == null) {
+ buffer = MainDataLoader.getTextureData(identifier);
+ updateData();
+ }
+
+ if (iType == 3) {
+ // Indexed colors, so we need to recalculate the color (if needed)
+ MainDataLoader.fillTextureData(identifier, buffer, buffer.capacity());
+ }
+
+ return buffer;
+ }
+
+ @Override
+ public ByteBuffer getSubData(int x, int y, int width, int height) {
+ int bufferLength = width * height * 4;
+ ByteBuffer buffer;
+ try {
+ buffer = BufferAllocation.newByteBuffer(bufferLength);
+ } catch (OutOfMemoryException exception) {
+ drawerVisitor.invalidate(GraphicController.getController().getObjectFromId(identifier), exception);
+ return null;
+ }
+ MainDataLoader.fillTextureData(identifier, buffer, bufferLength, x, y, width, height);
+ buffer.rewind();
+ return buffer;
+ }
+
+ @Override
+ public boolean isValid() {
+ return isValid;
+ }
+
+ @Override
+ public void updateObject(Integer id, int property) {
+ if (isValid() && identifier.equals(id)) {
+ // TODO check Property.
+ updateData();
+ }
+ }
+
+ @Override
+ public void deleteObject(Integer id) {
+ if (isValid() && identifier.equals(id)) {
+ isValid = false;
+ GraphicController.getController().unregister(this);
+ // 3 is MATPLOT_INDEX
+ dispose(iType == 3);
+ }
+ }
+
+ @Override
+ public void createObject(Integer id) {
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/arrowDrawing/ArrowDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/arrowDrawing/ArrowDrawer.java
new file mode 100755
index 000000000..f72030e79
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/arrowDrawing/ArrowDrawer.java
@@ -0,0 +1,537 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - DIGITEO - Manuel JULIACHS
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.arrowDrawing;
+
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.ObjectRemovedException;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.renderer.JoGLView.DataManager;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+import org.scilab.modules.renderer.JoGLView.util.OutOfMemoryException;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * ArrowDrawer class.
+ * Utility class used by DrawerVisitor to draw arrows.
+ * Arrows are drawn as identical isoceles triangles, whose sharpness
+ * is specified by the apex angle.
+ *
+ * To do:
+ * -optimize: segment projection occurs twice if a negative arrow size is specified.
+ * -further comment (especially the reduction ratios).
+ * -rationalize: use a map for arrow tip vertex buffers instead of pre-allocating
+ * data or using a single vertex buffer for small sets of segments.
+ *
+ * @author Manuel JULIACHS
+ */
+public class ArrowDrawer {
+
+ /** The DrawerVisitor used. */
+ private final DrawerVisitor visitor;
+
+ /** The angle at the arrow triangle's apex. */
+ private static final double APEX_ANGLE = 40.0;
+
+ /** The cosine of the apex's half-angle. */
+ private static final double COS_HALF_ANGLE = Math.cos(Math.toRadians(0.5 * APEX_ANGLE));
+
+ /** The sine of the apex's half-angle. */
+ private static final double SIN_HALF_ANGLE = Math.sin(Math.toRadians(0.5 * APEX_ANGLE));
+
+ /** The reduction ratio: the size of an arrow relative to the Axes size. */
+ private static final double REDUCTION_RATIO = 0.02;
+
+ /** The reduction ratio for the Segs object: the size of an arrow relative to the Axes size. */
+ private static final double SEGS_REDUCTION_RATIO = 0.075;
+
+ /** The reduction ratio for negative arrow size values: size of an arrow head relative to the length. */
+ private static final double REDUCTION_RATIO_DEPENDING = 0.15;
+
+ /** The vertex buffer used to draw arrow vertices for non-preallocated vertex data. */
+ ElementsBuffer drawerArrowVertices;
+
+ /**
+ * Constructor.
+ * @param visitor the DrawerVisitor {@see DrawerVisitor}.
+ */
+ public ArrowDrawer(DrawerVisitor visitor) {
+ this.visitor = visitor;
+
+ drawerArrowVertices = visitor.getCanvas().getBuffersManager().createElementsBuffer();
+ }
+
+ /**
+ * Computes and returns the arrow size (in pixels) for a set of segments.
+ * It depends on properties of the set's parent Axes (mainly the view-related properties, like the displayed bounds).
+ * @param parentAxes the parent Axes of the object corresponding to the segment set.
+ * @param vertices the segments' vertices (5*Nsegments elements).
+ * @param segmentIndices the segments' indices (2*Nsegments elements).
+ * @param numSegments the number of segments (Nsegments).
+ * @param arrowSize the input arrow size, as defined by the various arrowed segment objects.
+ * @param thickness the arrow segment thickness.
+ * @param isSegs specifies whether arrow size must be computed for a Segs object or not.
+ * @return the arrow size in pixels.
+ */
+ private double computeArrowPixelSize(Axes parentAxes, ElementsBuffer vertices, IndicesBuffer segmentIndices, int numSegments, double arrowSize,
+ double thickness, boolean isSegs) {
+
+ double averageNorm = 0.0;
+ double pixelArrowSize = 0.0;
+ int canvasWidth = visitor.getDrawingTools().getCanvas().getWidth();
+ int canvasHeight = visitor.getDrawingTools().getCanvas().getHeight();
+
+ /* Get the projection */
+ Transformation projection = visitor.getDrawingTools().getTransformationManager().getCanvasProjection();
+
+ Double [] axesBounds = parentAxes.getAxesBounds();
+ Double [] margins = parentAxes.getMargins();
+
+ double[] axesDims = new double[2];
+
+ /* To do: add a function to AxesDrawer to compute the Axes box's window coordinate dimensions */
+ axesDims[0] = axesBounds[2] * (1.0 - margins[0] - margins[1]);
+ axesDims[1] = axesBounds[3] * (1.0 - margins[2] - margins[3]);
+
+ axesDims[0] *= (double) canvasWidth;
+ axesDims[1] *= (double) canvasHeight;
+
+ Double[] bounds = parentAxes.getDisplayedBounds();
+
+ double xRange = (bounds[1] - bounds[0]);
+ double yRange = (bounds[3] - bounds[2]);
+
+ if (arrowSize < 0.0) {
+ averageNorm = computeAverageNorm(projection, vertices.getData(), vertices.getElementsSize(), segmentIndices.getData(), numSegments);
+ }
+
+ pixelArrowSize = computeArrowPixelSize(averageNorm, axesDims, xRange, yRange, isSegs, thickness, arrowSize);
+
+ return pixelArrowSize;
+ }
+
+ /**
+ * Draws arrows for a given object (a set of segments).
+ * Arrow tip vertex data is written into the vertex buffer where segment vertex data is located.
+ * @param parentAxesId the identifier of the object's parent Axes.
+ * @param identifier the object's identifier.
+ * @param arrowSize the arrow size.
+ * @param lineThickness the arrow segment thickness.
+ * @param isSegs specifies whether the object is a Segs object.
+ * @param isColored specifies whether the object is drawn with per-arrow colors.
+ * @param lineColor the line color used for all the arrows (used if isColored is equal to false).
+ * @throws org.scilab.forge.scirenderer.SciRendererException if drawing fails.
+ * @throws ObjectRemovedException
+ */
+ public void drawArrows(Integer parentAxesId, Integer identifier, double arrowSize, double lineThickness, boolean isSegs,
+ boolean isColored, int lineColor, boolean isStripped) throws SciRendererException, ObjectRemovedException, OutOfMemoryException {
+
+ DataManager dataManager = visitor.getDataManager();
+ ColorMap colorMap = visitor.getColorMap();
+
+ ElementsBuffer vertices = dataManager.getVertexBuffer(identifier);
+ IndicesBuffer segmentIndices = dataManager.getWireIndexBuffer(identifier);
+ IndicesBuffer triangleIndices = dataManager.getIndexBuffer(identifier);
+
+ drawArrows(parentAxesId, vertices, dataManager.getColorBuffer(identifier), segmentIndices, triangleIndices, arrowSize, lineThickness, isSegs, isColored, lineColor, isStripped);
+ }
+
+ /**
+ * Draw arrows for a set of segments.
+ * It uses ArrowDrawer's own vertex buffer to write back arrow vertex data and should therefore
+ * be used only for small sets of segments (typically Legend items). It does not allow per-segment colors.
+ * @param parentAxesId the identifier of segment set's parent Axes.
+ * @param vertices the segments' vertices.
+ * @param segmentIndices the segments' indices.
+ * @param arrowSize the arrow size.
+ * @param lineThickness the arrow segment thickness.
+ * @param lineColor the line color used for all the arrows.
+ * @throws org.scilab.forge.scirenderer.SciRendererException if drawing fails.
+ */
+ public void drawArrows(Integer parentAxesId, ElementsBuffer vertices, IndicesBuffer segmentIndices,
+ double arrowSize, double lineThickness, int lineColor, boolean isStripped) throws SciRendererException {
+
+ /*
+ * No colors are specified as a unique color is used for all the segments.
+ * As arrow tip vertices are written to the drawer's vertex buffer, triangle indices
+ * are also set to null.
+ */
+ drawArrows(parentAxesId, vertices, null, segmentIndices, null, arrowSize, lineThickness, false, false, lineColor, isStripped);
+ }
+
+ /**
+ * Draw arrows for a set of line segments.
+ * It computes arrow tip vertex data in window coordinates, using the input segment vertex data.
+ * Depending on whether a triangle index buffer is available, the computed data is written into
+ * the segment vertex buffer or the drawer's own vertex buffer.
+ * @param parentAxesId the identifier of the Axes in which arrows are drawn.
+ * @param vertices the segments' vertices.
+ * @param colors the segments' colors.
+ * @param segmentIndices the segments' indices.
+ * @param triangleIndices the arrow tips' triangle indices.
+ * @param arrowSize the arrow size.
+ * @param lineThickness the arrow segment thickness.
+ * @param isSegs specifies whether arrows are drawn for a Segs object.
+ * @param isColored specifies whether per-arrow colors are used.
+ * @param lineColor the line color used for all the arrows (used if isColored is equal to false).
+ * @throws org.scilab.forge.scirenderer.SciRendererException if drawing fails.
+ */
+ private void drawArrows(Integer parentAxesId, ElementsBuffer vertices, ElementsBuffer colors, IndicesBuffer segmentIndices, IndicesBuffer triangleIndices,
+ double arrowSize, double lineThickness, boolean isSegs, boolean isColored, int lineColor, boolean isStripped) throws SciRendererException {
+
+ int offset = vertices.getElementsSize();
+
+ int numSegments;
+ if (isStripped) {
+ numSegments = segmentIndices.getData().capacity() - 1;
+ } else {
+ numSegments = segmentIndices.getData().capacity() / 2;
+ }
+
+ /* Do not draw if there are no segments */
+ if (numSegments == 0) {
+ return;
+ }
+
+ /* Get the projection */
+ Transformation projection = visitor.getDrawingTools().getTransformationManager().getCanvasProjection();
+
+ /* Compute the arrow pixel size */
+ Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentAxesId);
+
+ arrowSize = computeArrowPixelSize(parentAxes, vertices, segmentIndices, numSegments, arrowSize, lineThickness, isSegs);
+
+ /*
+ * If a triangle index buffer is available, arrow tip vertices are written
+ * into the same buffer as segment vertices, else, they are written into
+ * the drawer's arrow tip buffer.
+ */
+ if (triangleIndices != null) {
+ fillArrowVertexData(projection, vertices, segmentIndices,
+ numSegments, triangleIndices, arrowSize, isStripped);
+
+ /* Forces update */
+ vertices.setData(vertices.getData(), offset);
+ } else {
+ fillArrowVertexData(projection, vertices, segmentIndices,
+ numSegments, drawerArrowVertices, arrowSize, isStripped);
+ }
+
+ DefaultGeometry arrowTips = new DefaultGeometry();
+
+ arrowTips.setLineDrawingMode(Geometry.LineDrawingMode.NONE);
+ arrowTips.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ arrowTips.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+
+ if (triangleIndices != null) {
+ arrowTips.setVertices(vertices);
+ arrowTips.setIndices(triangleIndices);
+ } else {
+ /* No triangle indices are set as the drawer's vertex buffer contains only tip vertices. */
+ arrowTips.setVertices(drawerArrowVertices);
+ }
+
+ Appearance arrowAppearance = new Appearance();
+
+ if (isColored) {
+ arrowTips.setColors(colors);
+ } else {
+ arrowAppearance.setFillColor(ColorFactory.createColor(visitor.getColorMap(), lineColor));
+ }
+
+ /* Draws in window coordinates */
+ visitor.getDrawingTools().getTransformationManager().useWindowCoordinate();
+ visitor.getDrawingTools().draw(arrowTips, arrowAppearance);
+ visitor.getDrawingTools().getTransformationManager().useSceneCoordinate();
+ }
+
+ /**
+ * Computes and fills arrow vertex data for a set of line segments.
+ * Arrow tip vertices are computed in window coordinates and depends on the coordinates of the segment vertices.
+ * These vertices are written to the segments' vertex buffer as specified by the triangle
+ * index buffer. The vertex buffer therefore contains a total of (5*Nsegments) elements and must have been allocated beforehand.
+ * @param projection the projection from object to window coordinates.
+ * @param vertices the buffer storing the segments' vertices and to which arrow tips' vertices are written (5*Nsegments elements).
+ * @param segmentIndices the segments' indices (2*Nsegments elements).
+ * @param numSegments the number of segments (Nsegments).
+ * @param triangleIndices the arrow tips' triangle indices (3*Nsegments elements).
+ * @param arrowSize the arrow size (in pixels).
+ */
+ private void fillArrowVertexData(Transformation projection, ElementsBuffer vertices, IndicesBuffer segmentIndices,
+ int numSegments, IndicesBuffer triangleIndices, double arrowSize, final boolean isStripped) {
+ int[] segmentVertexOffsets = new int[2];
+ int[] triVertexOffsets = new int[3];
+ int offset = vertices.getElementsSize();
+ IntBuffer segmentIndexData = segmentIndices.getData();
+ IntBuffer triangleIndexData = triangleIndices.getData();
+ FloatBuffer vertexData = vertices.getData();
+
+ for (int i = 0; i < numSegments; i++) {
+ if (isStripped) {
+ segmentVertexOffsets[0] = offset * segmentIndexData.get(i);
+ segmentVertexOffsets[1] = offset * segmentIndexData.get(i + 1);
+ } else {
+ segmentVertexOffsets[0] = offset * segmentIndexData.get(2 * i);
+ segmentVertexOffsets[1] = offset * segmentIndexData.get(2 * i + 1);
+ }
+
+ triVertexOffsets[0] = offset * triangleIndexData.get(3 * i);
+ triVertexOffsets[1] = offset * triangleIndexData.get(3 * i + 1);
+ triVertexOffsets[2] = offset * triangleIndexData.get(3 * i + 2);
+
+ /* Vertex data is specified as both the input and output vertex buffer as it contains both the segment and arrow tip vertices. */
+ computeAndWriteSingleArrowVertexData(projection, vertexData, vertexData, segmentVertexOffsets, triVertexOffsets, offset, arrowSize);
+ }
+ }
+
+ /**
+ * Computes and fills arrow vertex data for a set of line segments.
+ * Arrow tip vertices are written into a separate vertex buffer, which is resized as needed.
+ * @param projection the projection from object to window coordinates.
+ * @param vertices the line segments' vertices (2*Nsegments elements).
+ * @param segmentIndices the line segments' indices (2*Nsegments elements).
+ * @param numSegments the number of segments (Nsegments).
+ * @param arrowVertices the arrow tip vertices (3*Nsegment elements).
+ * @param arrowSize the arrow size (in pixels).
+ */
+ private void fillArrowVertexData(Transformation projection, ElementsBuffer vertices, IndicesBuffer segmentIndices,
+ int numSegments, ElementsBuffer arrowVertices, double arrowSize, final boolean isStripped) {
+ int[] segmentVertexOffsets = new int[2];
+ int[] triVertexOffsets = new int[3];
+ int offset = vertices.getElementsSize();
+ int arrowOffset;
+ IntBuffer segmentIndexData = segmentIndices.getData();
+ FloatBuffer vertexData = vertices.getData();
+ FloatBuffer arrowVertexData;
+
+ int bufferOffset = 0;
+
+ /* Check whether resizing is required and accordingly get vertex data */
+ if (isResizeRequired(arrowVertices, numSegments)) {
+ arrowOffset = 4;
+ arrowVertexData = FloatBuffer.allocate(arrowOffset * 3 * numSegments);
+ } else {
+ arrowOffset = arrowVertices.getElementsSize();
+ arrowVertexData = arrowVertices.getData();
+ }
+
+ for (int i = 0; i < numSegments; i++) {
+ if (isStripped) {
+ segmentVertexOffsets[0] = offset * segmentIndexData.get(i);
+ segmentVertexOffsets[1] = offset * segmentIndexData.get(i + 1);
+ } else {
+ segmentVertexOffsets[0] = offset * segmentIndexData.get(2 * i);
+ segmentVertexOffsets[1] = offset * segmentIndexData.get(2 * i + 1);
+ }
+
+ triVertexOffsets[0] = bufferOffset;
+ triVertexOffsets[1] = bufferOffset + arrowOffset;
+ triVertexOffsets[2] = bufferOffset + 2 * arrowOffset;
+
+ computeAndWriteSingleArrowVertexData(projection, vertexData, arrowVertexData, segmentVertexOffsets, triVertexOffsets, arrowOffset, arrowSize);
+
+ bufferOffset += 3 * arrowOffset;
+ }
+
+ arrowVertices.setData(arrowVertexData, arrowOffset);
+ }
+
+ /**
+ * Determines whether the arrow vertex buffer passed as an argument must be resized or not
+ * depending on the number of segments for which arrow tip data must be computed.
+ * @param arrowVertices the arrow vertex buffer.
+ * @param numSegments the number of segments required.
+ * @return true if the buffer must be resized, false if not.
+ */
+ private boolean isResizeRequired(ElementsBuffer arrowVertices, int numSegments) {
+ boolean resize = false;
+
+ if (arrowVertices.getData() == null) {
+ resize = true;
+ } else {
+ int numPreviousVertices = arrowVertices.getData().capacity() / arrowVertices.getElementsSize();
+
+ if (3 * numSegments != numPreviousVertices) {
+ resize = true;
+ }
+ }
+
+ return resize;
+ }
+
+ /**
+ * Computes and returns the 3 vertices of an arrow tip corresponding to a single segment.
+ * Arrow vertex data is computed in window coordinates and depends on the coordinates of the segment vertices.
+ * To do so, the vertices of the segment are projected, and then used to compute the 3 vertices of the corresponding arrow.
+ * @param projection the projection from object to window coordinates.
+ * @param vertexData the segments' vertex data.
+ * @param arrowVertexData the arrow tip vertex data in which the computed vertices are output.
+ * @param segmentVertexOffsets the offsets of the segment's endpoints into the vertex buffer (2 elements).
+ * @param arrowVertexOffsets the offsets of the tip's vertices into the arrow vertex buffer (3 elements).
+ * @param offset the number of components taken by one arrow vertex (3 or 4).
+ * @param arrowSize the arrow size in pixels.
+ */
+ private void computeAndWriteSingleArrowVertexData(Transformation projection, FloatBuffer vertexData, FloatBuffer arrowVertexData,
+ int[] segmentVertexOffsets, int[] arrowVertexOffsets, int offset, double arrowSize) {
+
+ /* Compute the arrow tip vertices in window coordinates from the object coordinate segment vertices */
+ Vector3d v0 = new Vector3d(vertexData.get(segmentVertexOffsets[0]), vertexData.get(segmentVertexOffsets[0] + 1), vertexData.get(segmentVertexOffsets[0] + 2));
+ Vector3d v1 = new Vector3d(vertexData.get(segmentVertexOffsets[1]), vertexData.get(segmentVertexOffsets[1] + 1), vertexData.get(segmentVertexOffsets[1] + 2));
+
+ v0 = projection.project(v0);
+ v1 = projection.project(v1);
+
+ Vector3d direction = v1.minus(v0).getNormalized();
+
+ Vector3d[] singleArrowVertices = computeArrowVertices(v1, direction, arrowSize);
+
+ arrowVertexData.put(arrowVertexOffsets[0], (float) singleArrowVertices[0].getX());
+ arrowVertexData.put(arrowVertexOffsets[0] + 1, (float) singleArrowVertices[0].getY());
+ arrowVertexData.put(arrowVertexOffsets[0] + 2, (float) singleArrowVertices[0].getZ());
+
+ arrowVertexData.put(arrowVertexOffsets[1], (float) singleArrowVertices[1].getX());
+ arrowVertexData.put(arrowVertexOffsets[1] + 1, (float) singleArrowVertices[1].getY());
+ arrowVertexData.put(arrowVertexOffsets[1] + 2, (float) singleArrowVertices[1].getZ());
+
+ arrowVertexData.put(arrowVertexOffsets[2], (float) singleArrowVertices[2].getX());
+ arrowVertexData.put(arrowVertexOffsets[2] + 1, (float) singleArrowVertices[2].getY());
+ arrowVertexData.put(arrowVertexOffsets[2] + 2, (float) singleArrowVertices[2].getZ());
+
+ if (offset == 4) {
+ arrowVertexData.put(arrowVertexOffsets[0] + 3, 1.0f);
+ arrowVertexData.put(arrowVertexOffsets[1] + 3, 1.0f);
+ arrowVertexData.put(arrowVertexOffsets[2] + 3, 1.0f);
+ }
+ }
+
+ /**
+ * Computes the average norm of a set of segments projected in window coordinates.
+ * @param projection the projection from object to window coordinates.
+ * @param vertexData the segments' vertex data (at least 2*Nsegments*offset elements).
+ * @param offset the number of components taken by one vertex (3 or 4).
+ * @param indexData the segments' index data (2*Nsegments elements).
+ * @param numSegments the number of segments (Nsegments).
+ * @return the average norm of the projected segments.
+ */
+ private double computeAverageNorm(Transformation projection, FloatBuffer vertexData, int offset, IntBuffer indexData, int numSegments) {
+ double averageNorm = 0.0;
+
+ for (int i = 0; i < numSegments; i++) {
+ int i0;
+ int i1;
+ i0 = indexData.get(2 * i);
+ i1 = indexData.get(2 * i + 1);
+
+ Vector3d v0 = new Vector3d(vertexData.get(i0 * offset), vertexData.get(i0 * offset + 1), vertexData.get(i0 * offset + 2));
+ Vector3d v1 = new Vector3d(vertexData.get(i1 * offset), vertexData.get(i1 * offset + 1), vertexData.get(i1 * offset + 2));
+
+ v0 = projection.project(v0);
+ v1 = projection.project(v1);
+
+ double norm = v1.minus(v0).getNorm();
+
+ averageNorm += norm;
+ }
+
+ if (numSegments > 0) {
+ averageNorm /= (double) numSegments;
+ }
+
+ return averageNorm;
+ }
+
+ /**
+ * Computes and returns the arrow size in pixels.
+ * It is computed depending on the Axes box's dimensions and the displayed data bounds in order to obtain
+ * a constant size in pixels, or else a size varying with the zoom level.
+ * @param averageNorm the average norm of a segment in window coordinates (used only if the input arrow size is < 0).
+ * @param axesDims the dimensions of the Axes box zone in pixels (2 elements: x and y).
+ * @param xRange the displayed data bounds's x interval.
+ * @param xRange the displayed data bounds's y interval.
+ * @param isSegs specifies whether arrow size must be computed for a Segs object.
+ * @param thickness the arrow segment thickness.
+ * @param arrowSize the input arrow size, as defined by the various arrow segment objects.
+ * @return the arrow size in pixels.
+ */
+ private double computeArrowPixelSize(double averageNorm, double[] axesDims, double xRange, double yRange, boolean isSegs,
+ double thickness, double arrowSize) {
+
+ if (arrowSize < 0.0) {
+ /* If the size is negative, the arrow size depends on the average length of the segments */
+ arrowSize *= thickness;
+ arrowSize = -arrowSize * averageNorm * REDUCTION_RATIO_DEPENDING;
+ } else if (isSegs) {
+ /*
+ * Special case for Segs: the arrow size is adjusted depending on the Axes' dimensions
+ * (in window coordinates) and the displayed bounds' maximum.
+ */
+ double maxRange = Math.max(xRange, yRange);
+
+ if (maxRange == 0.0) {
+ maxRange = 1.0;
+ }
+
+ arrowSize *= thickness;
+ arrowSize = arrowSize * Math.min(axesDims[0], axesDims[1]) * SEGS_REDUCTION_RATIO / maxRange;
+ } else {
+ /* Champ objects: the arrow size remains constant in window coordinates */
+ arrowSize *= thickness;
+ arrowSize = arrowSize * Math.min(axesDims[0], axesDims[1]) * REDUCTION_RATIO;
+ }
+
+ return arrowSize;
+ }
+
+ /**
+ * Computes and returns the 3 vertices of an arrow tip.
+ * The vertices are given starting from the apex and going in counter-clockwise order.
+ * @param tipVertex the arrow tip's apex vertex.
+ * @param direction the normalized direction vector from the tip to the arrow base.
+ * @param arrowSize the arrow size in pixels.
+ * @return the 3 vertices of an arrow tip.
+ */
+ private Vector3d[] computeArrowVertices(Vector3d tipVertex, Vector3d direction, double arrowSize) {
+ Vector3d[] arrowVertices = new Vector3d[3];
+
+ Vector3d orthDirection = new Vector3d(-direction.getY(), direction.getX(), direction.getZ());
+
+ double height = arrowSize * COS_HALF_ANGLE;
+ double halfBase = arrowSize * SIN_HALF_ANGLE;
+
+ Vector3d baseProjection = tipVertex.minus(direction.times(height));
+
+ arrowVertices[0] = tipVertex;
+ arrowVertices[1] = baseProjection.minus(orthDirection.times(halfBase));
+ arrowVertices[2] = baseProjection.plus(orthDirection.times(halfBase));
+
+ return arrowVertices;
+ }
+
+ /**
+ * Disposes all the ArrowDrawer resources.
+ */
+ public void disposeAll() {
+ visitor.getCanvas().getBuffersManager().dispose(drawerArrowVertices);
+ }
+
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/AxesDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/AxesDrawer.java
new file mode 100755
index 000000000..76fa620a6
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/AxesDrawer.java
@@ -0,0 +1,1468 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.axes;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.clipping.ClippingPlane;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry.FaceCullingMode;
+import org.scilab.forge.scirenderer.tranformations.DegenerateMatrixException;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
+import org.scilab.forge.scirenderer.tranformations.TransformationStack;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.forge.scirenderer.tranformations.Vector4d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.axes.AxisProperty;
+import org.scilab.modules.graphic_objects.axes.Box;
+import org.scilab.modules.graphic_objects.axes.Camera.ViewType;
+import org.scilab.modules.graphic_objects.contouredObject.Line;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObject;
+import org.scilab.modules.graphic_objects.graphicObject.ClippableProperty;
+import org.scilab.modules.graphic_objects.graphicObject.ClippableProperty.ClipStateType;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.figure.Figure;
+import org.scilab.modules.graphic_objects.legend.Legend;
+import org.scilab.modules.graphic_objects.legend.Legend.LegendLocation;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.axes.ruler.AxesRulerDrawer;
+import org.scilab.modules.renderer.JoGLView.label.AxisLabelPositioner;
+import org.scilab.modules.renderer.JoGLView.label.LabelManager;
+import org.scilab.modules.renderer.JoGLView.label.TitlePositioner;
+import org.scilab.modules.renderer.JoGLView.label.YAxisLabelPositioner;
+import org.scilab.modules.renderer.JoGLView.legend.LegendDrawer;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
+
+import java.awt.Dimension;
+import java.awt.geom.Rectangle2D;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * AxesDrawer are used by {@see DrawerVisitor} to draw {@see Axes}.
+ *
+ * @author Pierre Lando
+ */
+public class AxesDrawer {
+ private static final double DEFAULT_THETA = 270.0;
+ private static final Line.LineType HIDDEN_BORDER_PATTERN = Line.LineType.DASH;
+
+ /** An epsilon value used to move the clipping planes in order to prevent strict clipping. */
+ private static final double CLIPPING_EPSILON = 1e-5;
+
+ private final DrawerVisitor visitor;
+ private final Geometries geometries;
+
+ private final AxesRulerDrawer rulerDrawer;
+
+ /** The front face culling mode. */
+ private FaceCullingMode frontFaceCullingMode;
+
+ /** The back face culling mode. */
+ private FaceCullingMode backFaceCullingMode;
+
+ /** The label manager. */
+ private final LabelManager labelManager;
+
+ /** The x-axis label positioner. */
+ private final Map<Integer, AxisLabelPositioner> xAxisLabelPositioner = new HashMap<Integer, AxisLabelPositioner>();
+
+ /** The y-axis label positioner. */
+ private final Map<Integer, AxisLabelPositioner> yAxisLabelPositioner = new HashMap<Integer, AxisLabelPositioner>();
+
+ /** The z-axis label positioner. */
+ private final Map<Integer, AxisLabelPositioner> zAxisLabelPositioner = new HashMap<Integer, AxisLabelPositioner>();
+
+ /** The title positioner. */
+ private final Map<Integer, TitlePositioner> titlePositioner = new HashMap<Integer, TitlePositioner>();
+
+ /**
+ * The current reversed bounds. Used by the functions converting
+ * between object and box coordinates.
+ */
+ private double[] reversedBounds;
+
+ /** The current reversed bounds intervals. */
+ private double[] reversedBoundsIntervals;
+
+ /** The current projection (from object to window coordinates) used when drawing objects. */
+ private Transformation currentProjection;
+
+ /** The current data scale and translate transformation. */
+ private Transformation currentDataTransformation;
+
+ /** The set of object to window coordinate projections associated to all the Axes drawn by this drawer. */
+ private final Map<Integer, Transformation> projectionMap = new HashMap<Integer, Transformation>();
+
+ /** The set of object (in 2d view mode) to window coordinate projections associated to all the Axes drawn by this drawer. */
+ private final Map<Integer, Transformation> projection2dViewMap = new HashMap<Integer, Transformation>();
+
+ /** This is a __MAP__ */
+ private final Map<Integer, Transformation> sceneProjectionMap = new HashMap<Integer, Transformation>();
+
+ /**
+ * Default constructor.
+ * @param visitor the parent {@see DrawerVisitor}.
+ */
+ public AxesDrawer(DrawerVisitor visitor) {
+ this.visitor = visitor;
+ this.labelManager = visitor.getLabelManager();
+ this.geometries = new Geometries(visitor.getCanvas());
+ this.rulerDrawer = new AxesRulerDrawer(visitor.getCanvas());
+
+ reversedBounds = new double[6];
+ reversedBoundsIntervals = new double[3];
+ }
+
+ /**
+ * @return the axis label manager
+ */
+ public LabelManager getLabelManager() {
+ return labelManager;
+ }
+
+ public Transformation getCurrentProjection(Axes axes) throws DegenerateMatrixException {
+ DrawingTools drawingTools = visitor.getDrawingTools();
+ Transformation zoneProjection = computeZoneProjection(axes);
+ Transformation transformation = computeBoxTransformation(axes, visitor.getCanvas().getDimension(), false);
+ Transformation dataTransformation = computeDataTransformation(axes);
+ Transformation windowTrans;
+ if (drawingTools == null) {
+ windowTrans = TransformationFactory.getIdentity();
+ } else {
+ windowTrans = drawingTools.getTransformationManager().getWindowTransformation().getInverseTransformation();
+ }
+ Transformation current = zoneProjection.rightTimes(transformation);
+ current = current.rightTimes(dataTransformation);
+
+ return windowTrans.rightTimes(current);
+ }
+
+ /**
+ * Compute the graduations on the axes
+ * @param axes the axes
+ */
+ public void computeRulers(Axes axes) {
+ Figure figure = (Figure) GraphicController.getController().getObjectFromId(axes.getParentFigure());
+
+ //figure may be null during xml loading
+ if (figure == null) {
+ return;
+ }
+
+ final ColorMap colorMap = figure.getColorMap();
+ try {
+ Dimension dims = visitor.getCanvas().getDimension();
+ double w = dims.getWidth() / 2.0;
+ double h = dims.getHeight() / 2.0;
+
+ Transformation windowTrans = TransformationFactory.getAffineTransformation(new Vector3d(w, h, 1), new Vector3d(w, h, 0));
+ Transformation zoneProjection = computeZoneProjection(axes);
+ Transformation transformation = computeBoxTransformation(axes, dims, false);
+ Transformation canvasTrans = windowTrans.rightTimes(zoneProjection).rightTimes(transformation);
+
+ rulerDrawer.computeRulers(axes, this, colorMap, transformation, canvasTrans);
+ } catch (DegenerateMatrixException e) {
+
+ }
+ }
+
+ public void computeMargins(Axes axes) {
+ if (axes.getAutoMargins() && axes.getViewAsEnum() == ViewType.VIEW_2D) {
+ Figure figure = (Figure) GraphicController.getController().getObjectFromId(axes.getParentFigure());
+ ColorMap colorMap = null;
+ if (figure != null) {
+ colorMap = figure.getColorMap();
+ } else {
+ return;
+ }
+
+ Dimension[] marginLabels = labelManager.getLabelsSize(colorMap, axes, this);
+ Integer[] size = {visitor.getCanvas().getWidth(), visitor.getCanvas().getHeight()};
+ // [x_left, y_up, w, h]
+ Double[] axesBounds = axes.getAxesBounds();
+ // [l, r, t, b]
+ Double[] margins = axes.getMargins();
+ // m is a copy of margins
+ Double[] mt = new Double[] { 0., 0., 0., 0. };
+ Double[] ml = new Double[] { 0., 0., 0., 0. };
+ Double[] ma = new Double[] { 0., 0., 0., 0. };
+ Double[] m = new Double[] { 0., 0., 0., 0. };
+ AxisProperty.AxisLocation xloc = axes.getXAxis().getAxisLocation();
+ AxisProperty.AxisLocation yloc = axes.getYAxis().getAxisLocation();
+ final double DEFAULT_MARGIN = 0.125;
+
+ // We compute the adapted margins for axes titles.
+ if (marginLabels[0].height != 0 || marginLabels[2].height != 0 || marginLabels[1].width != 0) {
+ if (marginLabels[2].height != 0) {
+ final double th = (marginLabels[2].height + 2 + TitlePositioner.TITLEOFFSET) / (size[1] * axesBounds[3]);
+ mt[2] = th;
+ }
+
+ if (marginLabels[0].height != 0 && (xloc == AxisProperty.AxisLocation.BOTTOM || xloc == AxisProperty.AxisLocation.TOP)) {
+ final double xh = (marginLabels[0].height + 2) / (size[1] * axesBounds[3]);
+ if (xloc == AxisProperty.AxisLocation.BOTTOM) {
+ mt[3] = xh;
+ } else {
+ mt[2] += xh;
+ }
+ }
+
+ if (marginLabels[1].width != 0 && (yloc == AxisProperty.AxisLocation.LEFT || yloc == AxisProperty.AxisLocation.RIGHT)) {
+ final double yh = (marginLabels[1].width + 2) / (size[0] * axesBounds[2]);
+ if (yloc == AxisProperty.AxisLocation.LEFT) {
+ mt[0] = yh;
+ } else {
+ mt[1] = yh;
+ }
+ }
+ }
+
+ //computeRulers(axes);
+ final double xratio = rulerDrawer.getRulerDrawer(axes, 0).getDistanceRatio();
+ final double yratio = rulerDrawer.getRulerDrawer(axes, 1).getDistanceRatio();
+
+ if (xloc == AxisProperty.AxisLocation.BOTTOM) {
+ ma[3] = (1 - margins[2] - margins[3]) * xratio / 2.;
+ } else if (xloc == AxisProperty.AxisLocation.TOP) {
+ ma[2] = (1 - margins[2] - margins[3]) * xratio / 2.;
+ }
+
+ if (yloc == AxisProperty.AxisLocation.LEFT) {
+ ma[0] = (1 - margins[0] - margins[1]) * yratio / 2.;
+ } else if (yloc == AxisProperty.AxisLocation.RIGHT) {
+ ma[1] = (1 - margins[0] - margins[1]) * yratio / 2.;
+ }
+
+ // Get the legend if any (only one ???)
+ if (axes.getChildren() != null) {
+ for (Integer i : axes.getChildren()) {
+ GraphicObject child = GraphicController.getController().getObjectFromId(i);
+ if (child instanceof Legend) {
+ Legend legend = (Legend) child;
+ Dimension legDims = visitor.getLegendDrawer().computeDimensions(axes, legend);
+ if (legDims != null) {
+ LegendLocation legLoc = legend.getLegendLocationAsEnum();
+ double C;
+ /*
+ * Legends dimension are linearly dependent of margins... so we need to solve an equation
+ * to find a good value for margins.
+ * For example:
+ * legend.w = texture.w + 3/8 * line.w + line.w
+ * where line.w = LINE_WIDTH * ab[2] * (1 - m[0] - m[1]) * size[0];
+ * the minimal value for m[1] is the solution of the equation (where unknown is m[1]):
+ * legend.w = ab[2] * m[1] * size[0].
+ */
+ switch (legLoc) {
+ case OUT_UPPER_RIGHT:
+ case OUT_LOWER_RIGHT:
+ // 1/8 of LINE_WIDTH is xOffset
+ // see legendDims[0] = ... in LegendDrawer::draw
+ // we add 2*xoffset to have a little space around the box
+ C = legend.getLineWidth() + LegendDrawer.LINE_WIDTH * (3. / 8. + 2. / 8.);
+ m[0] = Math.max(ma[0] + mt[0], DEFAULT_MARGIN);
+ m[1] = Math.max(((legDims.width + 2) / (axesBounds[2] * size[0]) + C * (1 - m[0])) / (1 + C) + ma[1] + mt[1], DEFAULT_MARGIN);
+ break;
+ case OUT_UPPER_LEFT:
+ case OUT_LOWER_LEFT:
+ C = legend.getLineWidth() + LegendDrawer.LINE_WIDTH * (3. / 8. + 2. / 8.);
+ m[1] = Math.max(ma[1] + mt[1], DEFAULT_MARGIN);
+ m[0] = Math.max(((legDims.width + 2) / (axesBounds[2] * size[0]) + C * (1 - m[1])) / (1 + C) + ma[0] + mt[0], DEFAULT_MARGIN);
+ break;
+ case UPPER_CAPTION:
+ C = LegendDrawer.Y_OFFSET * (3. + 2.);
+ m[3] = Math.max(ma[3] + mt[3], DEFAULT_MARGIN);
+ m[2] = Math.max(Math.max(((legDims.height + 2) / (axesBounds[3] * size[1]) + C * (1 - m[3])) / (1 + C), mt[2]) + ma[2], DEFAULT_MARGIN);
+ break;
+ case LOWER_CAPTION:
+ C = LegendDrawer.Y_OFFSET * (3. + 2.);
+ m[2] = Math.max(ma[2] + mt[2], DEFAULT_MARGIN);
+ m[3] = Math.max(Math.max(((legDims.height + 2) / (axesBounds[3] * size[1]) + C * (1 - m[2])) / (1 + C), mt[3]) + ma[3], DEFAULT_MARGIN);
+ break;
+ default:
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < m.length; i++) {
+ if (m[i] == 0) {
+ m[i] = Math.max(ma[i] + mt[i], DEFAULT_MARGIN);
+ }
+ }
+
+ if (!m[0].equals(margins[0]) || !m[1].equals(margins[1]) || !m[2].equals(margins[2]) || !m[3].equals(margins[3])) {
+ axes.setMargins(m);
+ //computeRulers(axes);
+ }
+ }
+ }
+
+ /**
+ * Draw the given {@see Axes}.
+ * @param axes {@see Axes} to draw.
+ * @throws org.scilab.forge.scirenderer.SciRendererException if the draw fail.
+ */
+ public void draw(Axes axes) throws SciRendererException {
+ DrawingTools drawingTools = visitor.getDrawingTools();
+ //Integer[] size = visitor.getFigure().getAxesSize();
+ //Dimension canvasDimension = new Dimension(size[0], size[1]);
+ Dimension canvasDimension = visitor.getCanvas().getDimension();
+ ColorMap colorMap = visitor.getColorMap();
+ TransformationStack modelViewStack = drawingTools.getTransformationManager().getModelViewStack();
+ TransformationStack projectionStack = drawingTools.getTransformationManager().getProjectionStack();
+
+ // Set axes zone.
+ Transformation zoneProjection = computeZoneProjection(axes);
+ projectionStack.push(zoneProjection);
+
+ // Set box projection.
+ Transformation transformation = computeBoxTransformation(axes, canvasDimension, false);
+ modelViewStack.pushRightMultiply(transformation);
+
+ /* Compute the data scale and translate transformation. */
+ Transformation dataTransformation = computeDataTransformation(axes);
+
+ currentDataTransformation = dataTransformation;
+
+ /* Compute the object to window coordinates projection. */
+ currentProjection = zoneProjection.rightTimes(transformation);
+ currentProjection = currentProjection.rightTimes(dataTransformation);
+
+ sceneProjectionMap.put(axes.getIdentifier(), currentProjection);
+
+ Transformation windowTrans = drawingTools.getTransformationManager().getInverseWindowTransformation();
+ currentProjection = windowTrans.rightTimes(currentProjection);
+
+ /* Update the projection maps with the resulting projections. */
+ addProjection(axes.getIdentifier(), currentProjection);
+
+ /* 2d view projection, to do: optimize computation */
+ if ((axes.getRotationAngles()[0] != 0 || axes.getRotationAngles()[1] != DEFAULT_THETA)) {
+ Transformation transformation2dView = computeBoxTransformation(axes, canvasDimension, true);
+ currentProjection = zoneProjection.rightTimes(transformation2dView);
+ currentProjection = currentProjection.rightTimes(dataTransformation);
+ currentProjection = windowTrans.rightTimes(currentProjection);
+ }
+
+ addProjection2dView(axes.getIdentifier(), currentProjection);
+
+ /**
+ * Draw the axes background.
+ */
+ drawBackground(axes, drawingTools, colorMap);
+
+ /**
+ * Mirror the transformation such that the corner with the maximum Z value was (-1, -1, -1).
+ * And draw the box.
+ */
+ Transformation cubeOrientation = computeCubeMirroring(transformation);
+ modelViewStack.pushRightMultiply(cubeOrientation);
+ drawBox(axes, drawingTools, colorMap);
+ modelViewStack.pop();
+
+ // Ruler are drawn in box coordinate.
+ rulerDrawer.drawRuler(axes, this, colorMap, drawingTools);
+
+ /* Compute reversed bounds. */
+ computeReversedBounds(axes);
+
+ /**
+ * Scale and translate for data fitting.
+ * And draw data.
+ */
+ modelViewStack.pushRightMultiply(dataTransformation);
+
+ /* Compute the front and back culling modes */
+ computeFaceCullingModes(axes);
+
+ visitor.askAcceptVisitor(axes.getChildren());
+ modelViewStack.pop();
+
+ // Reset transformation stacks.
+ modelViewStack.pop();
+ projectionStack.pop();
+ }
+
+ /**
+ * Draw the axes background.
+ * @param axes the {@see Axes}
+ * @param drawingTools the {@see DrawingTools} to use.
+ * @param colorMap the current {@see ColorMap}
+ * @throws org.scilab.forge.scirenderer.SciRendererException if the draw fail.
+ */
+ private void drawBackground(Axes axes, DrawingTools drawingTools, ColorMap colorMap) throws SciRendererException {
+ if (axes.getFilled()) {
+ Appearance appearance = new Appearance();
+ appearance.setFillColor(ColorFactory.createColor(colorMap, axes.getBackground()));
+ drawingTools.draw(geometries.getCubeGeometry(), appearance);
+ drawingTools.clearDepthBuffer();
+ }
+ }
+
+ /**
+ * Draw the box of the given {@see Axes}
+ * @param axes the given {@see Axes}.
+ * @param drawingTools the {@see DrawingTools} to use.
+ * @param colorMap the current {@see ColorMap}.
+ * @throws org.scilab.forge.scirenderer.SciRendererException if the draw fail.
+ */
+ private void drawBox(Axes axes, DrawingTools drawingTools, ColorMap colorMap) throws SciRendererException {
+ Box.BoxType boxed = axes.getBox().getBox();
+ if (boxed != Box.BoxType.OFF) {
+ Appearance appearance = new Appearance();
+
+ /**
+ * Draw hidden part of box.
+ */
+ if (axes.getViewAsEnum() != ViewType.VIEW_2D) {
+ appearance.setLineColor(ColorFactory.createColor(colorMap, axes.getHiddenAxisColor()));
+ appearance.setLineWidth(axes.getLineThickness().floatValue());
+ appearance.setLinePattern(HIDDEN_BORDER_PATTERN.asPattern());
+ drawingTools.draw(geometries.getHiddenBoxBorderGeometry(), appearance);
+ }
+
+ if (boxed != Box.BoxType.HIDDEN_AXES) {
+
+ /**
+ * Draw box border.
+ */
+ appearance.setLineColor(ColorFactory.createColor(colorMap, axes.getLineColor()));
+ appearance.setLineWidth(axes.getLineThickness().floatValue());
+ appearance.setLinePattern(axes.getLine().getLineStyle().asPattern());
+ drawingTools.draw(geometries.getBoxBorderGeometry(), appearance);
+
+
+ if (boxed != Box.BoxType.BACK_HALF) {
+ /**
+ * Draw front part of box.
+ */
+ drawingTools.draw(geometries.getFrontBoxBorderGeometry(), appearance);
+ }
+ }
+ }
+ }
+
+ /**
+ * Compute the mirroring matrix needed to have the [-1; -1; -1] point projected with the maximal Z value.
+ * @param transformation the current transformation.
+ * @return the mirroring matrix needed to have the [-1; -1; -1] point projected with the maximal Z value.
+ */
+ private Transformation computeCubeMirroring(Transformation transformation) {
+ double[] matrix = transformation.getMatrix();
+ try {
+ return TransformationFactory.getScaleTransformation(
+ matrix[2] < 0 ? 1 : -1,
+ matrix[6] < 0 ? 1 : -1,
+ matrix[10] < 0 ? 1 : -1
+ );
+ } catch (DegenerateMatrixException e) {
+ // Should never happen.
+ return TransformationFactory.getIdentity();
+ }
+ }
+
+ /**
+ * Compute zone where the axes is draw. In normalized window coordinate.
+ * @param axes the given {@see axes}.
+ * @return the zone where the axes is draw.
+ */
+ private Rectangle2D computeZone(Axes axes) {
+ Double[] axesBounds = axes.getAxesBounds();
+ Double[] margins = axes.getMargins();
+
+ // TODO : zoom box.
+ double x = (axesBounds[0] + axesBounds[2] * margins[0]) * 2 - 1;
+ double y = (1.0 - axesBounds[1] - axesBounds[3] * (1.0 - margins[3])) * 2 - 1;
+ double w = (1 - margins[0] - margins[1]) * axesBounds[2];
+ double h = (1 - margins[2] - margins[3]) * axesBounds[3];
+
+ if (axes.getIsoview()) {
+ double minSize = Math.min(w, h);
+ y += (h - minSize);
+ h = minSize;
+ x += (w - minSize);
+ w = minSize;
+ }
+
+ return new Rectangle2D.Double(x, y, w, h);
+ }
+
+ /**
+ * Compute the projection for the given axes.
+ * @param axes the given axes.
+ * @return the projection matrix.
+ * @throws DegenerateMatrixException if axes represent a nul area.
+ */
+ private Transformation computeZoneProjection(Axes axes) throws DegenerateMatrixException {
+ Rectangle2D zone = computeZone(axes);
+ Transformation zoneTranslation = TransformationFactory.getTranslateTransformation(zone.getMaxX(), zone.getMaxY(), 0);
+
+ // We scale by 0.5 in Z to allow ruler to be drawn.
+ Transformation zoneScale = TransformationFactory.getScaleTransformation(zone.getWidth(), zone.getHeight(), .5);
+
+ return zoneTranslation.rightTimes(zoneScale);
+ }
+
+ /**
+ * Compute data transformation for the given {@see Axes}.
+ *
+ * The data transformation is applied to data to fit in axes box.
+ *
+ * @param axes the given {@see Axes}
+ * @return data transformation.
+ * @throws DegenerateMatrixException if data bounds are not corrects.
+ */
+ private Transformation computeDataTransformation(Axes axes) throws DegenerateMatrixException {
+ // Reverse data if needed.
+ Transformation transformation = TransformationFactory.getScaleTransformation(
+ axes.getAxes()[0].getReverse() ? 1 : -1,
+ axes.getAxes()[1].getReverse() ? 1 : -1,
+ axes.getAxes()[2].getReverse() ? 1 : -1
+ );
+
+ if (axes.getZoomEnabled()) {
+ Double[] bounds = axes.getCorrectedBounds();
+
+ // Scale data.
+ Transformation scaleTransformation = TransformationFactory.getScaleTransformation(
+ 2.0 / (bounds[1] - bounds[0]),
+ 2.0 / (bounds[3] - bounds[2]),
+ 2.0 / (bounds[5] - bounds[4])
+ );
+ transformation = transformation.rightTimes(scaleTransformation);
+
+
+ // Translate data.
+ Transformation translateTransformation = TransformationFactory.getTranslateTransformation(
+ -(bounds[0] + bounds[1]) / 2.0,
+ -(bounds[2] + bounds[3]) / 2.0,
+ -(bounds[4] + bounds[5]) / 2.0
+ );
+ transformation = transformation.rightTimes(translateTransformation);
+
+ return transformation;
+ }
+
+ return transformation;
+ }
+
+
+ /**
+ * Compute box transformation for the given axes.
+ *
+ * The box transformation is applied to the axes box to fit in the canvas.
+ *
+ * @param axes the given {@see Axes}.
+ * @param canvasDimension the current canvas {@see Canvas}.
+ * @param use2dView specifies whether the default 2d view rotation angles must be used (true) or the given Axes' ones (false).
+ * @return box transformation for the given axes.
+ * @throws DegenerateMatrixException if data bounds are incorrect or canvas with or length are zero.
+ */
+ private Transformation computeBoxTransformation(Axes axes, Dimension canvasDimension, boolean use2dView) throws DegenerateMatrixException {
+ Double[] bounds = axes.getDisplayedBounds();
+ double theta;
+
+ double tmpX;
+ double tmpY;
+ double tmpZ;
+
+ Transformation transformation;
+
+ // Set zone aspect ratio.
+ Rectangle2D zone = computeZone(axes);
+ double axesRatio = zone.getWidth() / zone.getHeight();
+ transformation = TransformationFactory.getPreferredAspectRatioTransformation(canvasDimension, axesRatio);
+
+ // Rotate.
+ if (use2dView) {
+ theta = 2 * DEFAULT_THETA;
+ } else {
+ double alpha = -axes.getRotationAngles()[0];
+ theta = DEFAULT_THETA + axes.getRotationAngles()[1];
+ if (alpha != 0) {
+ Transformation alphaRotation = TransformationFactory.getRotationTransformation(alpha, 1.0, 0.0, 0.0);
+ transformation = transformation.rightTimes(alphaRotation);
+ }
+ }
+
+ Transformation thetaRotation = TransformationFactory.getRotationTransformation(theta, 0.0, 0.0, 1.0);
+ transformation = transformation.rightTimes(thetaRotation);
+
+ // If there is no cube scaling, we must take into account the distribution of data.
+ if (!axes.getCubeScaling()) {
+ tmpX = (bounds[1] - bounds[0]);
+ tmpY = (bounds[3] - bounds[2]);
+ tmpZ = (bounds[5] - bounds[4]);
+
+ /**
+ * Here, we should divide the values by their maximum.
+ * But the next operation will automatically.
+ */
+ if (tmpX != 1 || tmpY != 1 || tmpZ != 1) {
+ Transformation cubeScale = TransformationFactory.getScaleTransformation(tmpX, tmpY, tmpZ);
+ transformation = transformation.rightTimes(cubeScale);
+ }
+ }
+
+ // Compute bounds of projected data.
+ double[] matrix = transformation.getMatrix();
+ tmpX = 1 / (Math.abs(matrix[0]) + Math.abs(matrix[4]) + Math.abs(matrix[8]));
+ tmpY = 1 / (Math.abs(matrix[1]) + Math.abs(matrix[5]) + Math.abs(matrix[9]));
+ tmpZ = 1 / (Math.abs(matrix[2]) + Math.abs(matrix[6]) + Math.abs(matrix[10]));
+
+ // Scale projected data to fit in the cube.
+ Transformation isoScale;
+ if (axes.getIsoview()) {
+ Double[] axesBounds = axes.getAxesBounds();
+ Double[] margins = axes.getMargins();
+ double w = (1 - margins[0] - margins[1]) * axesBounds[2];
+ double h = (1 - margins[2] - margins[3]) * axesBounds[3];
+ double minScale;
+ if (h > w) {
+ minScale = Math.min(tmpX, tmpY * (h / w));
+ } else {
+ minScale = Math.min(tmpX * (w / h), tmpY);
+ }
+ isoScale = TransformationFactory.getScaleTransformation(minScale, minScale, tmpZ);
+ } else {
+ isoScale = TransformationFactory.getScaleTransformation(tmpX, tmpY, tmpZ);
+ }
+ transformation = transformation.leftTimes(isoScale);
+
+ return transformation;
+ }
+
+ /**
+ * Computes and sets the reversed bounds of the given Axes.
+ * @param axes the given {@see Axes}.
+ */
+ private void computeReversedBounds(Axes axes) {
+ Double[] currentBounds = axes.getCorrectedBounds();
+
+ /* Reverse */
+ if (axes.getAxes()[0].getReverse()) {
+ reversedBounds[0] = currentBounds[1];
+ reversedBounds[1] = currentBounds[0];
+ } else {
+ reversedBounds[0] = currentBounds[0];
+ reversedBounds[1] = currentBounds[1];
+ }
+
+ if (axes.getAxes()[1].getReverse()) {
+ reversedBounds[2] = currentBounds[3];
+ reversedBounds[3] = currentBounds[2];
+ } else {
+ reversedBounds[2] = currentBounds[2];
+ reversedBounds[3] = currentBounds[3];
+ }
+
+ if (axes.getAxes()[2].getReverse()) {
+ reversedBounds[4] = currentBounds[5];
+ reversedBounds[5] = currentBounds[4];
+ } else {
+ reversedBounds[4] = currentBounds[4];
+ reversedBounds[5] = currentBounds[5];
+ }
+
+ /*
+ * Interval values are set to 1 when bounds are equal to avoid divides by 0
+ * in the object to box coordinates conversion function.
+ */
+ if (reversedBounds[1] == reversedBounds[0]) {
+ reversedBoundsIntervals[0] = 1.0;
+ } else {
+ reversedBoundsIntervals[0] = reversedBounds[1] - reversedBounds[0];
+ }
+
+ if (reversedBounds[3] == reversedBounds[2]) {
+ reversedBoundsIntervals[1] = 1.0;
+ } else {
+ reversedBoundsIntervals[1] = reversedBounds[3] - reversedBounds[2];
+ }
+
+ if (reversedBounds[5] == reversedBounds[4]) {
+ reversedBoundsIntervals[2] = 1.0;
+ } else {
+ reversedBoundsIntervals[2] = reversedBounds[5] - reversedBounds[4];
+ }
+
+ }
+
+ /**
+ * Computes the culling modes respectively corresponding to front and back faces
+ * of the given Axes' child objects as a function of its {X,Y,Z} reverse properties.
+ * It must be called by draw prior to rendering any child object.
+ * @param axes the given {@see Axes}.
+ */
+ private void computeFaceCullingModes(Axes axes) {
+ if (axes.getAxes()[0].getReverse() ^ axes.getAxes()[1].getReverse() ^ axes.getAxes()[2].getReverse()) {
+ /* Front: CW */
+ this.frontFaceCullingMode = FaceCullingMode.CW;
+ this.backFaceCullingMode = FaceCullingMode.CCW;
+ } else {
+ /* Front: CCW */
+ this.frontFaceCullingMode = FaceCullingMode.CCW;
+ this.backFaceCullingMode = FaceCullingMode.CW;
+ }
+ }
+
+ /**
+ * Converts a point from object coordinates to box coordinates (used when drawing axis rulers).
+ * @param point the point in object coordinates.
+ * @return the point in box coordinates.
+ */
+ public Vector3d getBoxCoordinates(Vector3d point) {
+ double[] dataCoordinates = new double[3];
+
+ dataCoordinates[0] = 1 - 2.0 * (point.getX() - reversedBounds[0]) / reversedBoundsIntervals[0];
+ dataCoordinates[1] = 1 - 2.0 * (point.getY() - reversedBounds[2]) / reversedBoundsIntervals[1];
+ dataCoordinates[2] = 1 - 2.0 * (point.getZ() - reversedBounds[4]) / reversedBoundsIntervals[2];
+
+ return new Vector3d(dataCoordinates);
+ }
+
+ /**
+ * Converts a point from box coordinates (used when drawing axis rulers) to object coordinates.
+ * @param point the point in box coordinates.
+ * @return the point in object coordinates.
+ */
+ public Vector3d getObjectCoordinates(Vector3d point) {
+ double[] objectCoordinates = new double[3];
+
+ objectCoordinates[0] = 0.5 * (1.0 - point.getX()) * (reversedBounds[1] - reversedBounds[0]) + reversedBounds[0];
+ objectCoordinates[1] = 0.5 * (1.0 - point.getY()) * (reversedBounds[3] - reversedBounds[2]) + reversedBounds[2];
+ objectCoordinates[2] = 0.5 * (1.0 - point.getZ()) * (reversedBounds[5] - reversedBounds[4]) + reversedBounds[4];
+
+ return new Vector3d(objectCoordinates);
+ }
+
+ /**
+ * Computes and return the object to window coordinate projection corresponding to the given Axes object.
+ * @param axes the given Axes.
+ * @param drawingTools the drawing tools.
+ * @param canvasDimension the current canvas dimension.
+ * @param use2dView specifies whether the default 2d view rotation angles must be used (true) or the given Axes' ones (false).
+ * @return the projection
+ */
+ private Transformation computeProjection(Axes axes, DrawingTools drawingTools, Dimension canvasDimension, boolean use2dView) {
+ Transformation projection;
+
+ if (drawingTools == null) {
+ return TransformationFactory.getIdentity();
+ }
+
+ try {
+ /* Compute the zone projection. */
+ Transformation zoneProjection = computeZoneProjection(axes);
+
+ /* Compute the box transformation. */
+ Transformation transformation = computeBoxTransformation(axes, canvasDimension, use2dView);
+
+ /* Compute the data scale and translate transformation. */
+ Transformation dataTransformation = computeDataTransformation(axes);
+
+ /* Compute the object to window coordinates projection. */
+ projection = zoneProjection.rightTimes(transformation);
+ projection = projection.rightTimes(dataTransformation);
+
+ Transformation windowTrans = drawingTools.getTransformationManager().getWindowTransformation().getInverseTransformation();
+ projection = windowTrans.rightTimes(projection);
+ } catch (DegenerateMatrixException e) {
+ return TransformationFactory.getIdentity();
+ }
+
+ return projection;
+ }
+
+ /**
+ * Returns the current projection from object to window coordinates.
+ * @return the projection.
+ */
+ public Transformation getProjection() {
+ return currentProjection;
+ }
+
+ /**
+ * Returns the current data scale and translate transformation.
+ * @return the data transformation.
+ */
+ public Transformation getDataTransformation() {
+ return currentDataTransformation;
+ }
+
+ /**
+ * Adds the projection from object to window coordinates corresponding to a given Axes object
+ * to the projection map.
+ * @param axesId the identifier of the given Axes.
+ * @param projection the corresponding projection.
+ */
+ public synchronized void addProjection(Integer axesId, Transformation projection) {
+ projectionMap.put(axesId, projection);
+ }
+
+ /**
+ * Returns the projection from object to window coordinates corresponding
+ * to a given Axes object.
+ * @param id the identifier of the given Axes.
+ * @return the projection.
+ */
+ public Transformation getProjection(Integer id) {
+ return projectionMap.get(id);
+ }
+
+ /**
+ * Removes the object to window coordinate projection corresponding to a given Axes from
+ * the projection map.
+ * @param axesId the identifier of the given Axes.
+ */
+ public void removeProjection(Integer axesId) {
+ projectionMap.remove(axesId);
+ }
+
+ /**
+ * Adds the projection from object (in 2d view mode) to window coordinates corresponding to a given Axes object
+ * to the projection map.
+ * @param axesId the identifier of the given Axes.
+ * @param projection the corresponding projection.
+ */
+ public synchronized void addProjection2dView(Integer axesId, Transformation projection) {
+ projection2dViewMap.put(axesId, projection);
+ }
+
+ /**
+ * Returns the projection from object (in 2d view mode) to window coordinates corresponding
+ * to a given Axes object.
+ * @param id the identifier of the given Axes.
+ * @return the projection.
+ */
+ public Transformation getProjection2dView(Integer id) {
+ return projection2dViewMap.get(id);
+ }
+
+ public Transformation getSceneProjection(Integer id) {
+ return sceneProjectionMap.get(id);
+ }
+
+ /**
+ * Removes the object (in 2d view mode) to window coordinate projection corresponding to a given Axes from
+ * the projection map.
+ * @param axesId the identifier of the given Axes.
+ */
+ public void removeProjection2dView(Integer axesId) {
+ projection2dViewMap.remove(axesId);
+ }
+
+ /**
+ * Updates both the projection from object to window coordinates and the related
+ * object (in 2d view mode) to window coordinates projection for the given Axes object.
+ * @param axes the given Axes.
+ */
+ public static void updateAxesTransformation(Axes axes) {
+ DrawerVisitor currentVisitor = DrawerVisitor.getVisitor(axes.getParentFrameOrFigure());
+ AxesDrawer axesDrawer = currentVisitor.getAxesDrawer();
+ Dimension canvasDimension = currentVisitor.getCanvas().getDimension();
+
+ Transformation transformation = axesDrawer.getProjection(axes.getIdentifier());
+
+ /* The projection must be updated */
+ if (transformation == null) {
+ Transformation projection = axesDrawer.computeProjection(axes, currentVisitor.getDrawingTools(), canvasDimension, false);
+
+ axesDrawer.addProjection(axes.getIdentifier(), projection);
+ }
+
+ Transformation transformation2dView = axesDrawer.getProjection2dView(axes.getIdentifier());
+
+ /* The projection must be updated */
+ if (transformation2dView == null) {
+ Transformation projection2dView = axesDrawer.computeProjection(axes, currentVisitor.getDrawingTools(), canvasDimension, true);
+
+ axesDrawer.addProjection2dView(axes.getIdentifier(), projection2dView);
+ }
+ }
+
+ /**
+ * Computes and returns the coordinates of a point projected onto the default 2d view plane.
+ * To compute them, the point is projected using the object to window coordinate projection, then
+ * unprojected using the object to window coordinate projection corresponding to the default 2d view
+ * (which uses the default camera rotation angles).
+ * To do: optimize by using the already computed 3d view projection.
+ * @param axes the given Axes.
+ * @param coordinates the object (x,y,z) coordinates to project onto the 2d view plane (3-element array).
+ * @returns the 2d view coordinates (3-element array).
+ */
+ public static double[] compute2dViewCoordinates(Axes axes, double[] coordinates) {
+ // used in geom3d
+
+ DrawerVisitor currentVisitor = DrawerVisitor.getVisitor(axes.getParentFrameOrFigure());
+ AxesDrawer axesDrawer;
+ Transformation projection;
+ Transformation projection2d;
+ double[] coords = coordinates;
+
+ if (currentVisitor != null) {
+ boolean[] logFlags = { axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
+ Dimension canvasDimension = currentVisitor.getCanvas().getDimension();
+ double[][] factors = axes.getScaleTranslateFactors();
+ ScaleUtils.applyLogScale(coords, logFlags);
+
+ axesDrawer = currentVisitor.getAxesDrawer();
+ coords[0] = coords[0] * factors[0][0] + factors[1][0];
+ coords[1] = coords[1] * factors[0][1] + factors[1][1];
+ coords[2] = coords[2] * factors[0][2] + factors[1][2];
+
+ projection = axesDrawer.computeProjection(axes, currentVisitor.getDrawingTools(), canvasDimension, false);
+ projection2d = axesDrawer.computeProjection(axes, currentVisitor.getDrawingTools(), canvasDimension, true);
+ Vector3d point = new Vector3d(coords);
+ point = projection.project(point);
+ point = projection2d.unproject(point);
+
+ coords = point.getData();
+ coords[0] = (coords[0] - factors[1][0]) / factors[0][0];
+ coords[1] = (coords[1] - factors[1][1]) / factors[0][1];
+ coords[2] = (coords[2] - factors[1][2]) / factors[0][2];
+
+ ScaleUtils.applyInverseLogScale(coords, logFlags);
+ }
+
+ return coords;
+ }
+
+ /**
+ * Computes and returns the pixel coordinates from a point's coordinates expressed in the default
+ * 2d view coordinate frame, using the given Axes. The returned pixel coordinates are expressed
+ * in the AWT's 2d coordinate frame.
+ * @param axes the given Axes.
+ * @param coordinates the 2d view coordinates (3-element array: x, y, z).
+ * @returns the pixel coordinates (2-element array: x, y).
+ */
+ public static double[] computePixelFrom2dViewCoordinates(Axes axes, double[] coordinates) {
+ // used by xchange
+
+ DrawerVisitor currentVisitor = DrawerVisitor.getVisitor(axes.getParentFrameOrFigure());
+ AxesDrawer axesDrawer;
+ double[] coords2dView = new double[] {0.0, 0.0, 0.0};
+
+ if (currentVisitor != null) {
+ boolean[] logFlags = { axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
+ double[][] factors = axes.getScaleTranslateFactors();
+ ScaleUtils.applyLogScale(coordinates, logFlags);
+
+ axesDrawer = currentVisitor.getAxesDrawer();
+ coords2dView[0] = coordinates[0] * factors[0][0] + factors[1][0];
+ coords2dView[1] = coordinates[1] * factors[0][1] + factors[1][1];
+ coords2dView[2] = coordinates[2] * factors[0][2] + factors[1][2];
+
+ Transformation projection2d = axesDrawer.getProjection2dView(axes.getIdentifier());
+ if (projection2d == null) {
+ updateAxesTransformation(axes);
+ projection2d = axesDrawer.getProjection2dView(axes.getIdentifier());
+ }
+
+ Vector3d point = new Vector3d(coords2dView);
+ point = projection2d.project(point);
+
+ /* Convert the window coordinates to pixel coordinates, only y changes due to the differing y-axis convention */
+ coords2dView[0] = point.getX();
+ coords2dView[1] = currentVisitor.getCanvas().getHeight() - point.getY();
+ coords2dView[2] = 0;
+ }
+
+ return coords2dView;
+ }
+
+ /**
+ * Computes and returns the pixel coordinates from a point's coordinates expressed in the current
+ * 3d view coordinate frame, using the given Axes. The returned pixel coordinates are expressed
+ * in the AWT's 2d coordinate frame.
+ * @param axes the given Axes.
+ * @param coordinates the 3d view coordinates (3-element array: x, y, z).
+ * @returns the pixel coordinates (2-element array: x, y).
+ */
+ public static double[] computePixelFrom3dCoordinates(Axes axes, double[] coordinates) {
+ DrawerVisitor currentVisitor;
+ AxesDrawer axesDrawer;
+ Transformation projection;
+ Transformation projection2d;
+
+ currentVisitor = DrawerVisitor.getVisitor(axes.getParentFrameOrFigure());
+ boolean[] logFlags = { axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
+ double[][] factors = axes.getScaleTranslateFactors();
+
+ Vector3d point = new Vector3d(coordinates);
+ point = ScaleUtils.applyLogScale(point, logFlags);
+ double[] coords = point.getData();
+
+ if (currentVisitor != null) {
+ axesDrawer = currentVisitor.getAxesDrawer();
+
+ coords[0] = coords[0] * factors[0][0] + factors[1][0];
+ coords[1] = coords[1] * factors[0][1] + factors[1][1];
+ coords[2] = coords[2] * factors[0][2] + factors[1][2];
+
+ projection = axesDrawer.computeProjection(axes, currentVisitor.getDrawingTools(), currentVisitor.getCanvas().getDimension(), false);
+
+ point = new Vector3d(coords);
+ point = projection.project(point);
+ }
+
+ return new double[] {point.getX(), currentVisitor.getCanvas().getHeight() - point.getY(), point.getZ()};
+ }
+
+ /**
+ * Computes and returns the pixel coordinates from a point's coordinates expressed in the current
+ * 3d view coordinate frame, using the given Axes. The returned pixel coordinates are expressed
+ * in the AWT's 2d coordinate frame.
+ * @param axes the given Axes.
+ * @param coordinates the 3d view coordinates (3-element array: x, y, z).
+ * @returns the pixel coordinates (2-element array: x, y).
+ */
+ public static double[][] computePixelFrom3dCoordinates(Axes axes, double[] coordsX, double[] coordsY, double[] coordsZ) {
+ DrawerVisitor currentVisitor = DrawerVisitor.getVisitor(axes.getParentFrameOrFigure());
+
+ if (currentVisitor != null) {
+ AxesDrawer axesDrawer = currentVisitor.getAxesDrawer();
+ Dimension canvasDimension = currentVisitor.getCanvas().getDimension();
+ double height = canvasDimension.getHeight();
+ boolean[] logFlags = { axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
+ double[][] factors = axes.getScaleTranslateFactors();
+ double[] coords = new double[3];
+ double[][] ret = new double[coordsX.length][2];
+ Transformation projection = axesDrawer.computeProjection(axes, currentVisitor.getDrawingTools(), canvasDimension, false);
+
+ for (int i = 0; i < coordsX.length; i++) {
+ coords[0] = coordsX[i];
+ coords[1] = coordsY[i];
+ coords[2] = coordsZ[i];
+ ScaleUtils.applyLogScale(coords, logFlags);
+
+ coords[0] = coords[0] * factors[0][0] + factors[1][0];
+ coords[1] = coords[1] * factors[0][1] + factors[1][1];
+ coords[2] = coords[2] * factors[0][2] + factors[1][2];
+
+ Vector3d point = new Vector3d(coords);
+ point = projection.project(point);
+ ret[i][0] = point.getX();
+ ret[i][1] = height - point.getY();
+ }
+
+ return ret;
+ }
+
+ return null;
+ }
+
+ /**
+ * Computes and returns the coordinates of a point onto the 3d view plane.
+ * To compute them, the point is projected using the object to window coordinate projection, then
+ * unprojected using the object to window coordinate projection corresponding to the 3d view
+ * @param axes the given Axes.
+ * @param coordinates the object (x,y,z) coordinates to project onto the 2d view plane (3-element array).
+ * @returns the 3d view coordinates (3-element array).
+ */
+ public static double[] compute3dViewCoordinates(Axes axes, double[] coordinates) {
+ DrawerVisitor currentVisitor = DrawerVisitor.getVisitor(axes.getParentFrameOrFigure());
+ AxesDrawer axesDrawer;
+ Transformation projection;
+ Transformation projection2d;
+ double[] coords = coordinates;
+
+ if (currentVisitor != null) {
+ if (axes.getViewAsEnum() == ViewType.VIEW_2D) {
+ // No need to projet/unproject since the product is identity
+ return new double[] {coords[0], coords[1], coords[2]};
+ }
+
+ boolean[] logFlags = { axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
+ Dimension canvasDimension = currentVisitor.getCanvas().getDimension();
+ double[][] factors = axes.getScaleTranslateFactors();
+ ScaleUtils.applyLogScale(coords, logFlags);
+
+ axesDrawer = currentVisitor.getAxesDrawer();
+ coords[0] = coords[0] * factors[0][0] + factors[1][0];
+ coords[1] = coords[1] * factors[0][1] + factors[1][1];
+ coords[2] = coords[2] * factors[0][2] + factors[1][2];
+
+ projection = axesDrawer.computeProjection(axes, currentVisitor.getDrawingTools(), canvasDimension, false);
+ projection2d = axesDrawer.computeProjection(axes, currentVisitor.getDrawingTools(), canvasDimension, true);
+
+ Vector3d point = new Vector3d(coords);
+ point = projection2d.project(point);
+ point = projection.unproject(point);
+
+ coords = point.getData();
+ coords[0] = (coords[0] - factors[1][0]) / factors[0][0];
+ coords[1] = (coords[1] - factors[1][1]) / factors[0][1];
+ coords[2] = (coords[2] - factors[1][2]) / factors[0][2];
+
+ ScaleUtils.applyInverseLogScale(coords, logFlags);
+ }
+
+ return coords;
+ }
+
+ /**
+ * Computes and returns the coordinates of a point projected onto the default 2d view plane
+ * from its pixel coordinates, using the given Axes. Pixel coordinates are expressed in
+ * the AWT's 2d coordinate frame.
+ * The returned point's z component is set to 0, as we only have x and y as an input.
+ * @param axes the given Axes.
+ * @param coordinates the pixel coordinates (2-element array: x, y).
+ * @return coordinates the 2d view coordinates (3-element array: x, y, z).
+ */
+ public static double[] compute2dViewFromPixelCoordinates(Axes axes, double[] coordinates) {
+ // used by xgetmouse and by xchange
+
+ DrawerVisitor currentVisitor;
+ AxesDrawer axesDrawer;
+ double[] coords2dView = new double[] {0.0, 0.0, 0.0};
+
+ currentVisitor = DrawerVisitor.getVisitor(axes.getParentFrameOrFigure());
+
+ if (currentVisitor != null) {
+ boolean[] logFlags = { axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
+ double[][] factors = axes.getScaleTranslateFactors();
+
+ axesDrawer = currentVisitor.getAxesDrawer();
+
+ /* Convert the pixel coordinates to window coordinates, only y changes due to the differing y-axis convention */
+ Vector3d point = new Vector3d(coordinates[0], currentVisitor.getCanvas().getHeight() - coordinates[1], 0.0);
+
+ Transformation projection2d = axesDrawer.getProjection2dView(axes.getIdentifier());
+ if (projection2d == null) {
+ updateAxesTransformation(axes);
+ projection2d = axesDrawer.getProjection2dView(axes.getIdentifier());
+ }
+
+ point = projection2d.unproject(point);
+ coords2dView = point.getData();
+
+ coords2dView[0] = (coords2dView[0] - factors[1][0]) / factors[0][0];
+ coords2dView[1] = (coords2dView[1] - factors[1][1]) / factors[0][1];
+ coords2dView[2] = (coords2dView[2] - factors[1][2]) / factors[0][2];
+
+ ScaleUtils.applyInverseLogScale(coords2dView, logFlags);
+ }
+
+ return coords2dView;
+ }
+
+ /**
+ * Un-project the given point from AWT coordinate to given axes coordinate.
+ * @param axes returned coordinate are relative to this axes.
+ * @param point un-projected point.
+ * @return The un-projected point.
+ */
+ public static Vector3d unProject(Axes axes, Vector3d point) {
+ DrawerVisitor currentVisitor = DrawerVisitor.getVisitor(axes.getParentFrameOrFigure());
+
+ if (currentVisitor != null) {
+ AxesDrawer axesDrawer = currentVisitor.getAxesDrawer();
+ double height = currentVisitor.getCanvas().getHeight() - 1;
+
+ Transformation projection2d = axesDrawer.getProjection(axes.getIdentifier());
+ return projection2d.unproject(new Vector3d(point.getX(), height - point.getY(), point.getZ()));
+ } else {
+ return new Vector3d(0, 0, 0);
+ }
+ }
+
+ /**
+ * Computes and returns the viewing area corresponding to the given Axes object.
+ * The viewing area is described by the (x, y) coordinates of the Axes box's upper-left corner
+ * and the Axes box's dimensions (width and height), all values are in pixel.
+ * The 2d coordinate frame in which the area is expressed uses the AWT convention:
+ * upper-left window corner at (0, 0), y-axis pointing downwards).
+ * @param axes the given Axes.
+ * @return the Axes' viewing area (4-element array: x, y, width, height).
+ */
+ public static double[] getViewingArea(Axes axes) {
+ DrawerVisitor currentVisitor;
+
+ double[] viewingArea = new double[] {0.0, 0.0, 0.0, 0.0};
+
+ currentVisitor = DrawerVisitor.getVisitor(axes.getParentFrameOrFigure());
+
+ if (currentVisitor != null) {
+ double width = currentVisitor.getCanvas().getDimension().getWidth();
+ double height = currentVisitor.getCanvas().getDimension().getHeight();
+ double upperLeftY;
+ AxesDrawer axesDrawer = currentVisitor.getAxesDrawer();
+ Rectangle2D axesZone = axesDrawer.computeZone(axes);
+
+ /* Compute the upper-left point's y coordinate */
+ upperLeftY = axesZone.getY() + axesZone.getHeight() * 2.0;
+
+ /* Convert from normalized coordinates to 2D pixel coordinates */
+ viewingArea[0] = (axesZone.getX() + 1.0) * 0.5 * width;
+ viewingArea[1] = (1.0 - upperLeftY) * 0.5 * height;
+ viewingArea[2] = axesZone.getWidth() * width;
+ viewingArea[3] = axesZone.getHeight() * height;
+ }
+
+ return viewingArea;
+ }
+
+ /**
+ * Returns the culling mode corresponding to front faces.
+ * @return the front face culling mode.
+ */
+ public FaceCullingMode getFrontFaceCullingMode() {
+ return this.frontFaceCullingMode;
+ }
+
+ /**
+ * Returns the culling mode corresponding to back faces.
+ * @return the back face culling mode.
+ */
+ public FaceCullingMode getBackFaceCullingMode() {
+ return this.backFaceCullingMode;
+ }
+
+ /**
+ * Enables clipping for the given {@link ClippableProperty}, which describes
+ * the clipping state of a clippable graphic object.
+ * Depending on the object's clip state property, clipping can be either
+ * disabled (OFF), performed against the parent Axes' box planes (CLIPGRF),
+ * or performed against the planes defined by the object's clip box.
+ * To do: find a better way to compute the clipping planes' offsets as the current one
+ * may lead to problems when the interval between the min and max bounds is too small.
+ * @param parentAxes the clipped object's parent Axes.
+ * @param clipProperty the clipping property of a clippable object.
+ */
+ public void enableClipping(Axes parentAxes, ClippableProperty clipProperty) {
+ DrawingTools drawingTools = visitor.getDrawingTools();
+
+ if (clipProperty.getClipState() != ClipStateType.OFF) {
+ int numPlanes = 0;
+ Vector4d[] equations = null;
+
+ /* Stores the (xmin,xmax) ,(ymin,ymax) and (zmin,zmax) clipping bounds */
+ double[] clipBounds = new double[6];
+
+ /* The offsets used for the x, y and z planes in order to avoid strict clipping */
+ double[] offsets = new double[3];
+
+ if (clipProperty.getClipState() == ClipStateType.CLIPGRF) {
+ /*
+ * All the clipping planes are set as clipping is performed
+ * against the Axes box planes.
+ */
+ numPlanes = 6;
+ Double[] bounds = parentAxes.getCorrectedBounds();
+
+ for (int i = 0; i < numPlanes; i++) {
+ clipBounds[i] = bounds[i];
+ }
+
+ offsets[0] = CLIPPING_EPSILON * (bounds[1] - bounds[0]);
+ offsets[1] = CLIPPING_EPSILON * (bounds[3] - bounds[2]);
+ offsets[2] = CLIPPING_EPSILON * (bounds[5] - bounds[4]);
+ } else if (clipProperty.getClipState() == ClipStateType.ON) {
+ /*
+ * The clip box property defines values only for the x and y axes,
+ * we therefore set only the x and y clipping planes.
+ */
+ numPlanes = 4;
+ Double[] clipBox = clipProperty.getClipBox();
+
+ /* The clip box stores the upper-left point coordinates. */
+ clipBounds[0] = clipBox[0];
+ clipBounds[1] = clipBox[0] + clipBox[2];
+ clipBounds[2] = clipBox[1] - clipBox[3];
+ clipBounds[3] = clipBox[1];
+
+ double[][] factors = parentAxes.getScaleTranslateFactors();
+ Double[] bounds = parentAxes.getMaximalDisplayedBounds();
+
+ /*
+ * The logarithmic scale must be applied to clip bounds values.
+ * If any of them are invalid, we set them to the displayed
+ * left bounds (xmin or ymin).
+ */
+ if (parentAxes.getXAxisLogFlag()) {
+ if (clipBounds[0] <= 0.0) {
+ clipBounds[0] = bounds[0];
+ } else {
+ clipBounds[0] = Math.log10(clipBounds[0]);
+ }
+
+ if (clipBounds[1] <= 0.0) {
+ clipBounds[1] = bounds[0];
+ } else {
+ clipBounds[1] = Math.log10(clipBounds[1]);
+ }
+ }
+
+ if (parentAxes.getYAxisLogFlag()) {
+ if (clipBounds[2] <= 0.0) {
+ clipBounds[2] = bounds[2];
+ } else {
+ clipBounds[2] = Math.log10(clipBounds[2]);
+ }
+
+ if (clipBounds[3] <= 0.0) {
+ clipBounds[3] = bounds[2];
+ } else {
+ clipBounds[3] = Math.log10(clipBounds[3]);
+ }
+ }
+
+ clipBounds[0] = clipBounds[0] * factors[0][0] + factors[1][0];
+ clipBounds[1] = clipBounds[1] * factors[0][0] + factors[1][0];
+ clipBounds[2] = clipBounds[2] * factors[0][1] + factors[1][1];
+ clipBounds[3] = clipBounds[3] * factors[0][1] + factors[1][1];
+
+ offsets[0] = CLIPPING_EPSILON * (clipBounds[1] - clipBounds[0]);
+ offsets[1] = CLIPPING_EPSILON * (clipBounds[3] - clipBounds[2]);
+ }
+
+ equations = new Vector4d[numPlanes];
+
+ equations[0] = new Vector4d(+1, 0, 0, -clipBounds[0] + offsets[0]);
+ equations[1] = new Vector4d(-1, 0, 0, +clipBounds[1] + offsets[0]);
+ equations[2] = new Vector4d(0, +1, 0, -clipBounds[2] + offsets[1]);
+ equations[3] = new Vector4d(0, -1, 0, +clipBounds[3] + offsets[1]);
+
+ /* If clipping is performed against the Axes box, the z plane equations must be initialized. */
+ if (numPlanes == 6) {
+ equations[4] = new Vector4d(0, 0, +1, -clipBounds[4] + offsets[2]);
+ equations[5] = new Vector4d(0, 0, -1, +clipBounds[5] + offsets[2]);
+ }
+
+ Transformation currentTransformation = drawingTools.getTransformationManager().getTransformation();
+
+ for (int i = 0 ; i < numPlanes; i++) {
+ ClippingPlane plane = drawingTools.getClippingManager().getClippingPlane(i);
+ plane.setTransformation(currentTransformation);
+ plane.setEquation(equations[i]);
+ plane.setEnable(true);
+ }
+ }
+ }
+
+ /**
+ * Disables clipping for the given {@link ClippableProperty}.
+ * @param clipProperty the clip property for which clipping is disabled.
+ */
+ public void disableClipping(ClippableProperty clipProperty) {
+ int numPlanes = 0;
+
+ if (clipProperty.getClipState() == ClipStateType.CLIPGRF) {
+ numPlanes = 6;
+ } else if (clipProperty.getClipState() == ClipStateType.ON) {
+ numPlanes = 4;
+ }
+
+ for (int i = 0 ; i < numPlanes; i++) {
+ ClippingPlane plane = visitor.getDrawingTools().getClippingManager().getClippingPlane(i);
+ plane.setEnable(false);
+ }
+
+ visitor.getDrawingTools().getClippingManager().disableClipping();
+ }
+
+ /**
+ * Returns the x-axis label positioner.
+ * @return the x-axis label positioner.
+ */
+ public AxisLabelPositioner getXAxisLabelPositioner(Axes axes) {
+ AxisLabelPositioner positioner = this.xAxisLabelPositioner.get(axes.getIdentifier());
+ if (positioner == null) {
+ positioner = new AxisLabelPositioner();
+ this.xAxisLabelPositioner.put(axes.getIdentifier(), positioner);
+ }
+
+ return positioner;
+ }
+
+ /**
+ * Returns the y-axis label positioner.
+ * @return the y-axis label positioner.
+ */
+ public AxisLabelPositioner getYAxisLabelPositioner(Axes axes) {
+ AxisLabelPositioner positioner = this.yAxisLabelPositioner.get(axes.getIdentifier());
+ if (positioner == null) {
+ positioner = new YAxisLabelPositioner();
+ this.yAxisLabelPositioner.put(axes.getIdentifier(), positioner);
+ }
+
+ return positioner;
+ }
+
+ /**
+ * Returns the z-axis label positioner.
+ * @return the z-axis label positioner.
+ */
+ public AxisLabelPositioner getZAxisLabelPositioner(Axes axes) {
+ AxisLabelPositioner positioner = this.zAxisLabelPositioner.get(axes.getIdentifier());
+ if (positioner == null) {
+ positioner = new AxisLabelPositioner();
+ this.zAxisLabelPositioner.put(axes.getIdentifier(), positioner);
+ }
+
+ return positioner;
+ }
+
+ /**
+ * Returns the title positioner.
+ * @return the title positioner.
+ */
+ public TitlePositioner getTitlePositioner(Axes axes) {
+ TitlePositioner positioner = this.titlePositioner.get(axes.getIdentifier());
+ if (positioner == null) {
+ positioner = new TitlePositioner();
+ this.titlePositioner.put(axes.getIdentifier(), positioner);
+ }
+
+ return positioner;
+ }
+
+ public void disposeAll() {
+ this.rulerDrawer.disposeAll();
+ this.projectionMap.clear();
+ this.projection2dViewMap.clear();
+ this.sceneProjectionMap.clear();
+ this.xAxisLabelPositioner.clear();
+ this.yAxisLabelPositioner.clear();
+ this.zAxisLabelPositioner.clear();
+ this.titlePositioner.clear();
+ }
+
+ public void update(Integer id, int property) {
+ if (this.rulerDrawer.update(id, property)) {
+ GraphicObject object = GraphicController.getController().getObjectFromId(id);
+ if (object instanceof Axes) {
+ computeRulers((Axes) object);
+ }
+ }
+ }
+
+ public void dispose(Integer id) {
+ this.rulerDrawer.dispose(id);
+ projectionMap.remove(id);
+ projection2dViewMap.remove(id);
+ sceneProjectionMap.remove(id);
+ this.xAxisLabelPositioner.remove(id);
+ this.yAxisLabelPositioner.remove(id);
+ this.zAxisLabelPositioner.remove(id);
+ this.titlePositioner.remove(id);
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/Geometries.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/Geometries.java
new file mode 100755
index 000000000..e60e9b13c
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/Geometries.java
@@ -0,0 +1,113 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.axes;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.utils.shapes.geometry.CubeFactory;
+
+/**
+ * @author Pierre Lando
+ */
+class Geometries {
+ private static final int ELEMENT_SIZE = 4;
+
+ private final Geometry cubeGeometry;
+ private final DefaultGeometry boxBorderGeometry;
+ private final DefaultGeometry frontBoxBorderGeometry;
+ private final DefaultGeometry hiddenBoxBorderGeometry;
+
+ private final ElementsBuffer boxBorderVertices;
+ private static final float[] boxBorderVerticesData = new float[] {
+ -1, -1, +1, +1,
+ -1, +1, +1, +1,
+ -1, +1, -1, +1,
+ +1, +1, -1, +1,
+ +1, -1, -1, +1,
+ +1, -1, +1, +1
+ };
+
+ private final ElementsBuffer hiddenBoxBorderVertices;
+ private static final float[] hiddenBoxBorderVerticesData = new float[] {
+ -1, -1, -1, +1,
+ +1, -1, -1, +1,
+ -1, -1, -1, +1,
+ -1, +1, -1, +1,
+ -1, -1, -1, +1,
+ -1, -1, +1, +1
+ };
+
+ private final ElementsBuffer frontBoxBorderVertices;
+ private static final float[] frontBoxBorderVerticesData = new float[] {
+ +1, +1, +1, +1,
+ -1, +1, +1, +1,
+ +1, +1, +1, +1,
+ +1, -1, +1, +1,
+ +1, +1, +1, +1,
+ +1, +1, -1, +1
+ };
+
+ public Geometries(Canvas canvas) {
+
+ boxBorderVertices = canvas.getBuffersManager().createElementsBuffer();
+ boxBorderVertices.setData(boxBorderVerticesData, ELEMENT_SIZE);
+
+ hiddenBoxBorderVertices = canvas.getBuffersManager().createElementsBuffer();
+ hiddenBoxBorderVertices.setData(hiddenBoxBorderVerticesData, ELEMENT_SIZE);
+
+ frontBoxBorderVertices = canvas.getBuffersManager().createElementsBuffer();
+ frontBoxBorderVertices.setData(frontBoxBorderVerticesData, ELEMENT_SIZE);
+
+ cubeGeometry = CubeFactory.createCube(canvas);
+
+ hiddenBoxBorderGeometry = new DefaultGeometry();
+ hiddenBoxBorderGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ hiddenBoxBorderGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ hiddenBoxBorderGeometry.setVertices(hiddenBoxBorderVertices);
+
+ frontBoxBorderGeometry = new DefaultGeometry();
+ frontBoxBorderGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ frontBoxBorderGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ frontBoxBorderGeometry.setVertices(frontBoxBorderVertices);
+
+ boxBorderGeometry = new DefaultGeometry();
+ boxBorderGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ boxBorderGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS_LOOP);
+ boxBorderGeometry.setVertices(boxBorderVertices);
+ }
+
+ /* TODO !
+ canvas.getBuffersManager().dispose(boxBorderVertices);
+ canvas.getBuffersManager().dispose(hiddenBoxBorderVertices);
+ canvas.getBuffersManager().dispose(frontBoxBorderVertices);
+ canvas.getBuffersManager().dispose(cubeGeometry);
+ */
+
+
+ public Geometry getCubeGeometry() {
+ return cubeGeometry;
+ }
+
+ public Geometry getBoxBorderGeometry() {
+ return boxBorderGeometry;
+ }
+
+ public Geometry getFrontBoxBorderGeometry() {
+ return frontBoxBorderGeometry;
+ }
+
+ public Geometry getHiddenBoxBorderGeometry() {
+ return hiddenBoxBorderGeometry;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/AxesRulerDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/AxesRulerDrawer.java
new file mode 100755
index 000000000..8d3c43a28
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/AxesRulerDrawer.java
@@ -0,0 +1,696 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ * Copyright (C) 2011 - DIGITEO - Manuel Juliachs
+ * Copyright (C) 2013-2014 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.axes.ruler;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.ruler.DefaultRulerModel;
+import org.scilab.forge.scirenderer.ruler.RulerDrawer;
+import org.scilab.forge.scirenderer.ruler.RulerDrawingResult;
+import org.scilab.forge.scirenderer.ruler.RulerModel;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.tranformations.DegenerateMatrixException;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.axes.AxisProperty;
+import org.scilab.modules.graphic_objects.axes.Camera;
+import org.scilab.modules.graphic_objects.contouredObject.Line;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+import org.scilab.modules.renderer.JoGLView.axes.AxesDrawer;
+import org.scilab.modules.renderer.JoGLView.label.AxisLabelPositioner;
+import org.scilab.modules.renderer.JoGLView.label.TitlePositioner;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+
+import java.awt.Dimension;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Pierre Lando
+ */
+public class AxesRulerDrawer {
+
+ private static final double LINEAR_MINIMAL_SUB_TICKS_DISTANCE = 8;
+ private static final double LOG_MINIMAL_SUB_TICKS_DISTANCE = 2;
+
+ /** Ticks length in pixels. */
+ public static final int TICKS_LENGTH = 6;
+
+ /** Sub-ticks length in pixels. */
+ private static final int SUB_TICKS_LENGTH = 3;
+
+ /**Ticks sprites distance in pixels. */
+ private static final int SPRITE_DISTANCE = 12;
+
+
+ private final RulerDrawerManager rulerDrawerManager;
+
+ public AxesRulerDrawer(Canvas canvas) {
+ this.rulerDrawerManager = new RulerDrawerManager(canvas.getTextureManager());
+ }
+
+ public RulerDrawer getRulerDrawer(Axes axes, int axis) {
+ return rulerDrawerManager.get(axes)[axis];
+ }
+
+ /**
+ * Get default ruler model
+ * @param axes the axes
+ * @param colorMap the colorMap
+ * @return a DefaultRulerModel
+ */
+ private final DefaultRulerModel getDefaultRulerModel(Axes axes, ColorMap colorMap) {
+ DefaultRulerModel rulerModel = new DefaultRulerModel();
+ rulerModel.setTicksLength(TICKS_LENGTH);
+ rulerModel.setSubTicksLength(SUB_TICKS_LENGTH);
+ rulerModel.setLineWidth(axes.getLineThickness());
+ rulerModel.setSpriteDistance(SPRITE_DISTANCE);
+ rulerModel.setColor(ColorFactory.createColor(colorMap, axes.getLineColor()));
+
+ return rulerModel;
+ }
+
+ /**
+ * Compute ticks and subticks on the rulers
+ * @param axes the current {@see Axes}
+ * @param axesDrawer the drawer used to draw the current {@see Axes}
+ * @param colorMap current {@see ColorMap}
+ * @param transformation the current modelView projection
+ * @param canvasProjection the canvas projection
+ * @throws org.scilab.forge.scirenderer.SciRendererException if draw fail.
+ */
+ public void computeRulers(Axes axes, AxesDrawer axesDrawer, ColorMap colorMap, Transformation transformation, Transformation canvasProjection) {
+ Double[] bounds = axes.getDisplayedBounds();
+ double[] matrix = transformation.getMatrix();
+
+ RulerDrawingResult rulerDrawingResult;
+ double[] values;
+
+ RulerDrawer[] rulerDrawers = rulerDrawerManager.get(axes);
+ DefaultRulerModel rulerModel = getDefaultRulerModel(axes, colorMap);
+
+ Vector3d xAxisPosition = computeXAxisPosition(matrix, bounds, axes.getXAxis().getAxisLocation(), axes.getYAxis().getReverse());
+ Vector3d yAxisPosition = computeYAxisPosition(matrix, bounds, axes.getYAxis().getAxisLocation(), axes.getXAxis().getReverse());
+
+ Vector3d px = canvasProjection.projectDirection(new Vector3d(1, 0, 0)).setZ(0);
+ Vector3d py = canvasProjection.projectDirection(new Vector3d(0, 1, 0)).setZ(0);
+ Vector3d pz = canvasProjection.projectDirection(new Vector3d(0, 0, 1)).setZ(0);
+
+ Vector3d xTicksDirection, yTicksDirection;
+ if (py.getNorm2() > pz.getNorm2()) {
+ xTicksDirection = new Vector3d(0, getNonZeroSignum(xAxisPosition.getY()), 0);
+ } else {
+ xTicksDirection = new Vector3d(0, 0, getNonZeroSignum(xAxisPosition.getZ()));
+ }
+
+ if (px.getNorm2() > pz.getNorm2()) {
+ yTicksDirection = new Vector3d(getNonZeroSignum(yAxisPosition.getX()), 0, 0);
+ } else {
+ yTicksDirection = new Vector3d(0, 0, getNonZeroSignum(yAxisPosition.getZ()));
+ }
+
+ // Draw X ruler
+ rulerModel.setTicksDirection(xTicksDirection);
+ rulerModel.setFirstPoint(xAxisPosition.setX(-1));
+ rulerModel.setSecondPoint(xAxisPosition.setX(1));
+ if (!axes.getAutoSubticks()) {
+ rulerModel.setSubticksNumber(axes.getXAxisSubticks());
+ }
+
+ setRulerBounds(axes.getXAxis(), rulerModel, bounds[0], bounds[1]);
+
+ rulerModel.setFormat(axes.getXAxisFormat());
+ rulerModel.setSTFactors(axes.getXAxisSTFactors());
+ rulerModel.setLogarithmic(axes.getXAxis().getLogFlag());
+ rulerModel.setMinimalSubTicksDistance(axes.getXAxis().getLogFlag() ? LOG_MINIMAL_SUB_TICKS_DISTANCE : LINEAR_MINIMAL_SUB_TICKS_DISTANCE);
+
+ if (!axes.getXAxis().getAutoTicks()) {
+ rulerModel.setUserGraduation(new UserDefineGraduation(axes.getXAxis(), bounds[0], bounds[1]));
+ if (axes.getAutoSubticks()) {
+ rulerModel.setSubticksNumber(axes.getXAxisSubticks());
+ }
+ rulerModel.setAutoTicks(false);
+ } else {
+ rulerModel.setAutoTicks(true);
+ }
+
+ double distanceRatio;
+ AxisLabelPositioner xAxisLabelPositioner = axesDrawer.getXAxisLabelPositioner(axes);
+ xAxisLabelPositioner.setLabelPosition(xAxisPosition);
+
+ if (axes.getXAxisVisible()) {
+ rulerDrawingResult = rulerDrawers[0].computeRuler(rulerModel, canvasProjection);
+ values = rulerDrawingResult.getTicksValues();
+
+ if (axes.getXAxisAutoTicks()) {
+ Arrays.sort(values);
+ GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_X_AXIS_TICKS_LOCATIONS__, toDoubleArray(values));
+ GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_X_AXIS_TICKS_LABELS__, toStringArray(values, rulerDrawingResult.getFormat()));
+ if (axes.getAutoSubticks()) {
+ //GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_X_AXIS_SUBTICKS__, rulerDrawingResult.getSubTicksDensity());
+ axes.setXAxisSubticks(rulerDrawingResult.getSubTicksDensity());
+ }
+ }
+
+ distanceRatio = rulerDrawingResult.getMaxDistToTicksDirNorm();
+
+ xAxisLabelPositioner.setTicksDirection(xTicksDirection);
+ xAxisLabelPositioner.setDistanceRatio(distanceRatio);
+ xAxisLabelPositioner.setProjectedTicksDirection(rulerDrawingResult.getNormalizedTicksDirection().setZ(0));
+ } else {
+ xAxisLabelPositioner.setTicksDirection(xTicksDirection);
+ Vector3d projTicksDir = canvasProjection.projectDirection(xTicksDirection);
+ xAxisLabelPositioner.setDistanceRatio((double) TICKS_LENGTH / projTicksDir.getNorm());
+ xAxisLabelPositioner.setProjectedTicksDirection(projTicksDir.getNormalized().setZ(0));
+ }
+
+ TitlePositioner titlePositioner = axesDrawer.getTitlePositioner(axes);
+ Dimension xdim = axesDrawer.getLabelManager().getXLabelSize(colorMap, axes, axesDrawer);
+ titlePositioner.setXLabelHeight(xdim.height);
+ titlePositioner.setDistanceRatio(xAxisLabelPositioner.getDistanceRatio());
+
+ // Draw Y ruler
+ rulerModel = getDefaultRulerModel(axes, colorMap);
+ rulerModel.setTicksDirection(yTicksDirection);
+ rulerModel.setFirstPoint(yAxisPosition.setY(-1));
+ rulerModel.setSecondPoint(yAxisPosition.setY(1));
+ if (!axes.getAutoSubticks()) {
+ rulerModel.setSubticksNumber(axes.getYAxisSubticks());
+ }
+
+ setRulerBounds(axes.getYAxis(), rulerModel, bounds[2], bounds[3]);
+ rulerModel.setFormat(axes.getYAxisFormat());
+ rulerModel.setSTFactors(axes.getYAxisSTFactors());
+ rulerModel.setLogarithmic(axes.getYAxis().getLogFlag());
+ rulerModel.setMinimalSubTicksDistance(axes.getYAxis().getLogFlag() ? LOG_MINIMAL_SUB_TICKS_DISTANCE : LINEAR_MINIMAL_SUB_TICKS_DISTANCE);
+
+ if (!axes.getYAxis().getAutoTicks()) {
+ rulerModel.setUserGraduation(new UserDefineGraduation(axes.getYAxis(), bounds[2], bounds[3]));
+ if (axes.getAutoSubticks()) {
+ rulerModel.setSubticksNumber(axes.getYAxisSubticks());
+ }
+ rulerModel.setAutoTicks(false);
+ } else {
+ rulerModel.setAutoTicks(true);
+ }
+
+ AxisLabelPositioner yAxisLabelPositioner = axesDrawer.getYAxisLabelPositioner(axes);
+ yAxisLabelPositioner.setLabelPosition(yAxisPosition);
+
+ if (axes.getYAxisVisible()) {
+ rulerDrawingResult = rulerDrawers[1].computeRuler(rulerModel, canvasProjection);
+ values = rulerDrawingResult.getTicksValues();
+ if (axes.getYAxisAutoTicks()) {
+ Arrays.sort(values);
+ GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Y_AXIS_TICKS_LOCATIONS__, toDoubleArray(values));
+ GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Y_AXIS_TICKS_LABELS__, toStringArray(values, rulerDrawingResult.getFormat()));
+ if (axes.getAutoSubticks()) {
+ //GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Y_AXIS_SUBTICKS__, rulerDrawingResult.getSubTicksDensity());
+ axes.setYAxisSubticks(rulerDrawingResult.getSubTicksDensity());
+ }
+ }
+
+ distanceRatio = rulerDrawingResult.getMaxDistToTicksDirNorm();
+
+ yAxisLabelPositioner.setTicksDirection(yTicksDirection);
+ yAxisLabelPositioner.setDistanceRatio(distanceRatio);
+ yAxisLabelPositioner.setProjectedTicksDirection(rulerDrawingResult.getNormalizedTicksDirection().setZ(0));
+ } else {
+ /* y-axis not visible: compute the projected ticks direction and distance ratio (see the x-axis case). */
+ yAxisLabelPositioner.setTicksDirection(yTicksDirection);
+ Vector3d projTicksDir = canvasProjection.projectDirection(yTicksDirection);
+ yAxisLabelPositioner.setDistanceRatio((double) TICKS_LENGTH / projTicksDir.getNorm());
+ yAxisLabelPositioner.setProjectedTicksDirection(projTicksDir.getNormalized().setZ(0));
+ }
+
+ // Draw Z ruler
+ if (axes.getViewAsEnum() == Camera.ViewType.VIEW_3D) {
+ double txs, tys, xs, ys;
+ if (Math.abs(matrix[2]) < Math.abs(matrix[6])) {
+ xs = matrix[2] > 0 ? 1 : -1;
+ ys = matrix[6] > 0 ? -1 : 1;
+ txs = xs;
+ tys = 0;
+ } else {
+ xs = matrix[2] > 0 ? -1 : 1;
+ ys = matrix[6] > 0 ? 1 : -1;
+ txs = 0;
+ tys = ys;
+ }
+
+ rulerModel = getDefaultRulerModel(axes, colorMap);
+ rulerModel.setFirstPoint(new Vector3d(xs, ys, -1));
+ rulerModel.setSecondPoint(new Vector3d(xs, ys, 1));
+ rulerModel.setTicksDirection(new Vector3d(txs, tys, 0));
+ if (!axes.getAutoSubticks()) {
+ rulerModel.setSubticksNumber(axes.getZAxisSubticks());
+ }
+
+ setRulerBounds(axes.getZAxis(), rulerModel, bounds[4], bounds[5]);
+ rulerModel.setFormat(axes.getZAxisFormat());
+ rulerModel.setSTFactors(axes.getZAxisSTFactors());
+ rulerModel.setLogarithmic(axes.getZAxis().getLogFlag());
+ rulerModel.setMinimalSubTicksDistance(axes.getZAxis().getLogFlag() ? LOG_MINIMAL_SUB_TICKS_DISTANCE : LINEAR_MINIMAL_SUB_TICKS_DISTANCE);
+
+ if (!axes.getZAxis().getAutoTicks()) {
+ rulerModel.setUserGraduation(new UserDefineGraduation(axes.getZAxis(), bounds[4], bounds[5]));
+ if (axes.getAutoSubticks()) {
+ rulerModel.setSubticksNumber(axes.getZAxisSubticks());
+ }
+ rulerModel.setAutoTicks(false);
+ } else {
+ rulerModel.setAutoTicks(true);
+ }
+
+ AxisLabelPositioner zAxisLabelPositioner = axesDrawer.getZAxisLabelPositioner(axes);
+ zAxisLabelPositioner.setLabelPosition(new Vector3d(xs, ys, 0));
+
+ if (axes.getZAxisVisible()) {
+ rulerDrawingResult = rulerDrawers[2].computeRuler(rulerModel, canvasProjection);
+ values = rulerDrawingResult.getTicksValues();
+ if (axes.getZAxisAutoTicks()) {
+ Arrays.sort(values);
+ GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Z_AXIS_TICKS_LOCATIONS__, toDoubleArray(values));
+ GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Z_AXIS_TICKS_LABELS__, toStringArray(values, rulerDrawingResult.getFormat()));
+ if (axes.getAutoSubticks()) {
+ //GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_Z_AXIS_SUBTICKS__, rulerDrawingResult.getSubTicksDensity());
+ axes.setZAxisSubticks(rulerDrawingResult.getSubTicksDensity());
+ }
+ }
+
+ distanceRatio = rulerDrawingResult.getMaxDistToTicksDirNorm();
+
+ zAxisLabelPositioner.setTicksDirection(new Vector3d(txs, tys, 0.0));
+ zAxisLabelPositioner.setDistanceRatio(distanceRatio);
+ zAxisLabelPositioner.setProjectedTicksDirection(rulerDrawingResult.getNormalizedTicksDirection().setZ(0).setY(1e-7));
+ } else {
+ /* z-axis not visible: compute the projected ticks direction and distance ratio (see the x-axis case). */
+ Vector3d zTicksDirection = new Vector3d(txs, tys, 0);
+
+ zAxisLabelPositioner.setTicksDirection(zTicksDirection);
+ Vector3d projTicksDir = canvasProjection.projectDirection(zTicksDirection);
+ zAxisLabelPositioner.setDistanceRatio((double) TICKS_LENGTH / projTicksDir.getNorm());
+ zAxisLabelPositioner.setProjectedTicksDirection(projTicksDir.getNormalized().setZ(0));
+ }
+ }
+ }
+
+ /**
+ * Draw the ruler.
+ * @param axes the current {@see Axes}
+ * @param axesDrawer the drawer used to draw the current {@see Axes}
+ * @param colorMap current {@see ColorMap}
+ * @param drawingTools the used {@see DrawingTools}
+ * @throws org.scilab.forge.scirenderer.SciRendererException if draw fail.
+ */
+ public void drawRuler(Axes axes, AxesDrawer axesDrawer, ColorMap colorMap, DrawingTools drawingTools) throws SciRendererException {
+ Appearance gridAppearance = new Appearance();
+
+ Double[] bounds = axes.getDisplayedBounds();
+ double[] matrix = drawingTools.getTransformationManager().getModelViewStack().peek().getMatrix();
+
+ RulerDrawer[] rulerDrawers = rulerDrawerManager.get(axes);
+ ElementsBuffer vertexBuffer = drawingTools.getCanvas().getBuffersManager().createElementsBuffer();
+ final boolean is3D = axes.getViewAsEnum() == Camera.ViewType.VIEW_3D;// && axes.getRotationAngles()[1] != 90.0;
+
+ if (rulerDrawers[0].getModel() == null || rulerDrawers[1].getModel() == null || (is3D && rulerDrawers[2].getModel() == null)) {
+ computeRulers(axes, axesDrawer, colorMap, drawingTools.getTransformationManager().getModelViewStack().peek(), drawingTools.getTransformationManager().getCanvasProjection());
+ }
+
+ int gridPosition;
+ if (axes.getGridPositionAsEnum().equals(Axes.GridPosition.FOREGROUND)) {
+ gridPosition = 1;
+ } else {
+ gridPosition = -1;
+ }
+
+ // Draw X ruler
+ if (axes.getXAxisVisible()) {
+ rulerDrawers[0].draw(drawingTools);
+
+ if (axes.getXAxisGridColor() != -1) {
+ FloatBuffer vertexData;
+ if (axes.getXAxisLogFlag()) {
+ List<Double> values = rulerDrawers[0].getSubTicksValue();
+ if (values == null || values.isEmpty()) {
+ vertexData = getXGridData(rulerDrawers[0].getTicksValue(), rulerDrawers[0].getModel());
+ } else {
+ vertexData = getXGridData(values, rulerDrawers[0].getModel());
+ }
+ } else {
+ vertexData = getXGridData(rulerDrawers[0].getTicksValue(), rulerDrawers[0].getModel());
+ }
+ vertexBuffer.setData(vertexData, 4);
+
+ Transformation mirror;
+ try {
+ mirror = TransformationFactory.getScaleTransformation(
+ 1,
+ matrix[6] < 0 ? gridPosition : -gridPosition,
+ matrix[10] < 0 ? gridPosition : -gridPosition
+ );
+ } catch (DegenerateMatrixException ignored) {
+ // Should never happens as long as gridPosition the value 1 or -1
+ mirror = TransformationFactory.getIdentity();
+ }
+
+ gridAppearance.setLineColor(ColorFactory.createColor(colorMap, axes.getXAxisGridColor()));
+ gridAppearance.setLineWidth(axes.getXAxisGridThickness().floatValue());
+ gridAppearance.setLinePattern(Line.LineType.fromScilabIndex(axes.getXAxisGridStyle()).asPattern());
+ drawingTools.getTransformationManager().getModelViewStack().pushRightMultiply(mirror);
+ DefaultGeometry gridGeometry = new DefaultGeometry();
+ gridGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ gridGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ gridGeometry.setVertices(vertexBuffer);
+ drawingTools.draw(gridGeometry, gridAppearance);
+ drawingTools.getTransformationManager().getModelViewStack().pop();
+ }
+ }
+
+ // Draw Y ruler
+ if (axes.getYAxisVisible()) {
+ rulerDrawers[1].draw(drawingTools);
+
+ if (axes.getYAxisGridColor() != -1) {
+ FloatBuffer vertexData;
+ if (axes.getYAxisLogFlag()) {
+ List<Double> values = rulerDrawers[1].getSubTicksValue();
+ if (values == null || values.isEmpty()) {
+ vertexData = getYGridData(rulerDrawers[1].getTicksValue(), rulerDrawers[1].getModel());
+ } else {
+ vertexData = getYGridData(values, rulerDrawers[1].getModel());
+ }
+ } else {
+ vertexData = getYGridData(rulerDrawers[1].getTicksValue(), rulerDrawers[1].getModel());
+ }
+ vertexBuffer.setData(vertexData, 4);
+
+ Transformation mirror;
+ try {
+ mirror = TransformationFactory.getScaleTransformation(
+ matrix[2] < 0 ? gridPosition : -gridPosition,
+ 1,
+ matrix[10] < 0 ? gridPosition : -gridPosition
+ );
+ } catch (DegenerateMatrixException ignored) {
+ // Should never happens as long as gridPosition the value 1 or -1
+ mirror = TransformationFactory.getIdentity();
+ }
+
+ gridAppearance.setLineColor(ColorFactory.createColor(colorMap, axes.getYAxisGridColor()));
+ gridAppearance.setLineWidth(axes.getYAxisGridThickness().floatValue());
+ gridAppearance.setLinePattern(Line.LineType.fromScilabIndex(axes.getYAxisGridStyle()).asPattern());
+ drawingTools.getTransformationManager().getModelViewStack().pushRightMultiply(mirror);
+ DefaultGeometry gridGeometry = new DefaultGeometry();
+ gridGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ gridGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ gridGeometry.setVertices(vertexBuffer);
+ drawingTools.draw(gridGeometry, gridAppearance);
+ drawingTools.getTransformationManager().getModelViewStack().pop();
+ }
+ }
+
+ // Draw Z ruler
+ if (is3D) {
+ if (axes.getZAxisVisible()) {
+ rulerDrawers[2].draw(drawingTools);
+
+ if (axes.getZAxisGridColor() != -1) {
+ FloatBuffer vertexData;
+ if (axes.getZAxisLogFlag()) {
+ List<Double> values = rulerDrawers[2].getSubTicksValue();
+ if (values == null || values.isEmpty()) {
+ vertexData = getZGridData(rulerDrawers[2].getTicksValue(), rulerDrawers[2].getModel());
+ } else {
+ vertexData = getZGridData(values, rulerDrawers[2].getModel());
+ }
+ } else {
+ vertexData = getZGridData(rulerDrawers[2].getTicksValue(), rulerDrawers[2].getModel());
+ }
+ vertexBuffer.setData(vertexData, 4);
+
+ Transformation mirror;
+ try {
+ mirror = TransformationFactory.getScaleTransformation(
+ matrix[2] < 0 ? gridPosition : -gridPosition,
+ matrix[6] < 0 ? gridPosition : -gridPosition,
+ 1
+ );
+ } catch (DegenerateMatrixException ignored) {
+ // Should never happens as long as gridPosition the value 1 or -1
+ mirror = TransformationFactory.getIdentity();
+ }
+
+ gridAppearance.setLineColor(ColorFactory.createColor(colorMap, axes.getZAxisGridColor()));
+ gridAppearance.setLineWidth(axes.getZAxisGridThickness().floatValue());
+ gridAppearance.setLinePattern(Line.LineType.fromScilabIndex(axes.getZAxisGridStyle()).asPattern());
+ drawingTools.getTransformationManager().getModelViewStack().pushRightMultiply(mirror);
+ DefaultGeometry gridGeometry = new DefaultGeometry();
+ gridGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ gridGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ gridGeometry.setVertices(vertexBuffer);
+ drawingTools.draw(gridGeometry, gridAppearance);
+ drawingTools.getTransformationManager().getModelViewStack().pop();
+ }
+ }
+ }
+
+ drawingTools.getCanvas().getBuffersManager().dispose(vertexBuffer);
+ }
+
+ private static final double getNonZeroSignum(double value) {
+ if (value < 0) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+
+ private void setRulerBounds(AxisProperty axis, DefaultRulerModel rulerModel, double axisMin, double axisMax) {
+ double min, max;
+ if (axis.getReverse()) {
+ min = axisMin;
+ max = axisMax;
+ } else {
+ min = axisMax;
+ max = axisMin;
+ }
+
+ if (axis.getLogFlag()) {
+ min = Math.pow(10, min);
+ max = Math.pow(10, max);
+ }
+ rulerModel.setValues(min, max);
+ }
+
+ private Vector3d computeXAxisPosition(double[] projectionMatrix, Double[] bounds, AxisProperty.AxisLocation axisLocation, boolean reverse) {
+ double y, z;
+ switch (axisLocation) {
+ default:
+ case BOTTOM:
+ z = -Math.signum(projectionMatrix[9]); // First : switch Z such that Y was minimal.
+ y = -Math.signum(projectionMatrix[6]) * z * Math.signum(projectionMatrix[10]);
+ if (y == 0) {
+ y = +1;
+ }
+ break;
+ case MIDDLE:
+ z = Math.signum(projectionMatrix[9]); // First : switch Z such that Y was maximal.
+ y = 0;
+ break;
+ case TOP:
+ z = Math.signum(projectionMatrix[9]); // First : switch Z such that Y was maximal.
+ y = -Math.signum(projectionMatrix[6]) * z * Math.signum(projectionMatrix[10]);
+ if (y == 0) {
+ y = -1;
+ }
+ break;
+ case ORIGIN:
+ z = Math.signum(projectionMatrix[9]); // First : switch Z such that Y was maximal.
+ y = (reverse ? -1 : 1) * (bounds[3] + bounds[2]) / (bounds[3] - bounds[2]);
+ if (Math.abs(y) > 1) {
+ y = Math.signum(y);
+ }
+ break;
+ }
+ return new Vector3d(0, y, z);
+ }
+
+ private Vector3d computeYAxisPosition(double[] matrix, Double[] bounds, AxisProperty.AxisLocation axisLocation, boolean reverse) {
+ double x, z;
+ switch (axisLocation) {
+ default:
+ case LEFT:
+ z = -Math.signum(matrix[9]); // First : switch Z such that Y was minimal.
+ x = -Math.signum(matrix[2]) * z * Math.signum(matrix[10]);
+ if (x == 0) {
+ x = +1;
+ }
+ break;
+ case MIDDLE:
+ z = Math.signum(matrix[9]); // First : switch Z such that Y was minimal.
+ x = 0;
+ break;
+ case RIGHT:
+ z = Math.signum(matrix[9]); // First : switch Z such that Y was minimal.
+ x = -Math.signum(matrix[2]) * z * Math.signum(matrix[10]); // Then switch X such that Z max but not in the middle.
+ if (x == 0) {
+ x = -1;
+ }
+ break;
+ case ORIGIN:
+ z = Math.signum(matrix[9]); // First : switch Z such that Y was minimal.
+ x = (reverse ? -1 : 1) * (bounds[1] + bounds[0]) / (bounds[1] - bounds[0]);
+ if (Math.abs(x) > 1) {
+ x = Math.signum(x);
+ }
+ break;
+ }
+ return new Vector3d(x, 0, z);
+ }
+
+ private String[] toStringArray(double[] values, DecimalFormat format) {
+ AxesRulerSpriteFactory.setScilabStyle(format);
+ String[] r = new String[values.length];
+ for (int i = 0; i < values.length; i++) {
+ r[i] = format.format(values[i]);
+ }
+ return r;
+ }
+
+ private Double[] toDoubleArray(double[] values) {
+ Double[] r = new Double[values.length];
+ for (int i = 0; i < values.length; i++) {
+ r[i] = values[i];
+ }
+ return r;
+ }
+
+ /**
+ * Build X grid data.
+ * @param values X values where grid is drawn.
+ * @param rulerModel used rulerModel to compute grid world position.
+ * @return X grid data.
+ */
+ private FloatBuffer getXGridData(List<Double> values, RulerModel rulerModel) {
+ FloatBuffer vertexData = FloatBuffer.allocate(values.size() * 16);
+ for (double value : values) {
+ float p = (float) rulerModel.getPosition(value).getX();
+ vertexData.put(p);
+ vertexData.put(+1);
+ vertexData.put(+1);
+ vertexData.put(1);
+ vertexData.put(p);
+ vertexData.put(-1);
+ vertexData.put(+1);
+ vertexData.put(1);
+ vertexData.put(p);
+ vertexData.put(+1);
+ vertexData.put(+1);
+ vertexData.put(1);
+ vertexData.put(p);
+ vertexData.put(+1);
+ vertexData.put(-1);
+ vertexData.put(1);
+ }
+ vertexData.rewind();
+ return vertexData;
+ }
+
+ /**
+ * Build Y grid data.
+ * @param values Y values where grid is drawn.
+ * @param rulerModel used rulerModel to compute grid world position.
+ * @return Y grid data.
+ */
+ private FloatBuffer getYGridData(List<Double> values, RulerModel rulerModel) {
+ FloatBuffer vertexData = FloatBuffer.allocate(values.size() * 16);
+ for (double value : values) {
+ float p = (float) rulerModel.getPosition(value).getY();
+ vertexData.put(+1);
+ vertexData.put(p);
+ vertexData.put(+1);
+ vertexData.put(1);
+ vertexData.put(-1);
+ vertexData.put(p);
+ vertexData.put(+1);
+ vertexData.put(1);
+ vertexData.put(+1);
+ vertexData.put(p);
+ vertexData.put(+1);
+ vertexData.put(1);
+ vertexData.put(+1);
+ vertexData.put(p);
+ vertexData.put(-1);
+ vertexData.put(1);
+ }
+ vertexData.rewind();
+ return vertexData;
+ }
+
+ /**
+ * Build Z grid data.
+ * @param values Z values where grid is drawn.
+ * @param rulerModel used rulerModel to compute grid world position.
+ * @return Z grid data.
+ */
+ private FloatBuffer getZGridData(List<Double> values, RulerModel rulerModel) {
+ FloatBuffer vertexData = FloatBuffer.allocate(values.size() * 16);
+ int limit = 0;
+ for (double value : values) {
+ float p = (float) rulerModel.getPosition(value).getZ();
+ vertexData.put(+1);
+ vertexData.put(+1);
+ vertexData.put(p);
+ vertexData.put(1);
+ vertexData.put(-1);
+ vertexData.put(+1);
+ vertexData.put(p);
+ vertexData.put(1);
+ vertexData.put(+1);
+ vertexData.put(+1);
+ vertexData.put(p);
+ vertexData.put(1);
+ vertexData.put(+1);
+ vertexData.put(-1);
+ vertexData.put(p);
+ vertexData.put(1);
+ limit += 16;
+ }
+ vertexData.limit(limit);
+ return vertexData;
+ }
+
+ public void disposeAll() {
+ this.rulerDrawerManager.disposeAll();
+ }
+
+ public boolean update(Integer id, int property) {
+ return this.rulerDrawerManager.update(id, property);
+ }
+
+ public void dispose(Integer id) {
+ this.rulerDrawerManager.dispose(id);
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/AxesRulerSpriteFactory.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/AxesRulerSpriteFactory.java
new file mode 100755
index 000000000..60de95703
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/AxesRulerSpriteFactory.java
@@ -0,0 +1,256 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.axes.ruler;
+
+import org.scilab.forge.scirenderer.ruler.RulerSpriteFactory;
+import org.scilab.forge.scirenderer.texture.TextEntity;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureDrawer;
+import org.scilab.forge.scirenderer.texture.TextureDrawingTools;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.axes.AxesContainer;
+import org.scilab.modules.graphic_objects.axes.AxisProperty;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.figure.Figure;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.textObject.FormattedText;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+import org.scilab.modules.renderer.JoGLView.util.FormattedTextSpriteDrawer;
+import org.scilab.modules.renderer.utils.textRendering.FontManager;
+
+import java.awt.Dimension;
+import java.awt.Font;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+
+/**
+ * This implementation of {@see RulerSpriteFactory} create ruler labels for the given {@see Axes}.
+ *
+ * @author Pierre Lando
+ */
+public class AxesRulerSpriteFactory implements RulerSpriteFactory {
+ /**
+ * The symbol used for ticks label in log and auto ticks mode.
+ */
+ private static final String MULTIPLICATION_SYMBOL = "x";
+
+ /**
+ * The exponent size is smaller than the mantissa size.
+ */
+ private static final float EXPONENT_SIZE_RATIO = 0.4f;
+
+ /**
+ * This factory create ruler label for this {@see Axis}.
+ */
+ private final AxisProperty axisProperty;
+
+ /**
+ * The current colormap.
+ */
+ private final ColorMap colorMap;
+
+ /**
+ * Default constructor.
+ * @param axes This factory create ruler label for one axis of this given {@see Axes}.
+ * @param axisId the id of the managed axis.
+ */
+ public AxesRulerSpriteFactory(Axes axes, int axisId) {
+ this.axisProperty = axes.getAxes()[axisId];
+ ColorMap figureColorMap;
+ try {
+ GraphicController controller = GraphicController.getController();
+ AxesContainer parentFigure = (AxesContainer) controller.getObjectFromId(axes.getParentFigure());
+ figureColorMap = parentFigure.getColorMap();
+ } catch (NullPointerException e) {
+ figureColorMap = null;
+ }
+ this.colorMap = figureColorMap;
+ }
+
+ @Override
+ public Texture create(double value, DecimalFormat adaptedFormat, TextureManager textureManager) {
+ // Simple ack to avoid ticks with "-0" as label.
+ if (value == -0) {
+ value = 0;
+ }
+
+ if (axisProperty.getAutoTicks()) {
+ setScilabStyle(adaptedFormat);
+ if (axisProperty.getLogFlag()) {
+ return createScientificStyleSprite(value, textureManager);
+ } else {
+ return createSimpleSprite(adaptedFormat.format(value), textureManager);
+ }
+ } else {
+ FormattedText formattedText = getTextAtValue(value);
+ if (formattedText != null && formattedText.getText() != null && !formattedText.getText().isEmpty()) {
+ FormattedTextSpriteDrawer textObjectSpriteDrawer = new FormattedTextSpriteDrawer(colorMap, formattedText);
+ Texture texture = textureManager.createTexture();
+ texture.setMagnificationFilter(Texture.Filter.LINEAR);
+ texture.setMinifyingFilter(Texture.Filter.LINEAR);
+ texture.setDrawer(textObjectSpriteDrawer);
+
+ return texture;
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * Set the given {@see DecimalFormat} to scilab style.
+ * @param format the given {@see DecimalFormat}.
+ */
+ public static void setScilabStyle(DecimalFormat format) {
+ DecimalFormatSymbols decimalFormatSymbols = format.getDecimalFormatSymbols();
+ decimalFormatSymbols.setDecimalSeparator('.');
+ decimalFormatSymbols.setExponentSeparator("e");
+ decimalFormatSymbols.setGroupingSeparator('\u00A0');
+ format.setDecimalFormatSymbols(decimalFormatSymbols);
+ }
+
+ /**
+ * Create and return a texture representing the given value.|| index >= axisProperty.getTicksLabels().size()
+ * The returned sprites will look like "5x10^2"
+ * @param value, the given value.
+ * @param textureManager used texture manager.
+ * @return a simple texture representing the given value with the adapted format.
+ */
+ private Texture createScientificStyleSprite(double value, TextureManager textureManager) {
+ Integer exponent = (int) Math.floor(Math.log10(value));
+ Double mantissa = value / Math.pow(10, exponent);
+ mantissa = Math.round(mantissa * 1e6) * 1e-6;
+
+ /**
+ * Create mantissa.
+ */
+ final TextEntity mantissaTextEntity;
+ if (mantissa != 1) {
+ mantissaTextEntity = new TextEntity(mantissa.toString() + MULTIPLICATION_SYMBOL + "10");
+ } else {
+ mantissaTextEntity = new TextEntity("10");
+ }
+
+ Font mantissaFont = FontManager.getSciFontManager().getFontFromIndex(axisProperty.getFontStyle(), axisProperty.getFontSize());
+ mantissaTextEntity.setTextAntiAliased(true);
+ mantissaTextEntity.setTextUseFractionalMetrics(axisProperty.getFontFractional());
+ mantissaTextEntity.setTextColor(ColorFactory.createColor(colorMap, axisProperty.getFontColor()));
+ mantissaTextEntity.setFont(mantissaFont);
+ final Dimension mantissaSize = mantissaTextEntity.getSize();
+
+ /**
+ * Create exponent.
+ */
+ final TextEntity exponentTextEntity = new TextEntity(exponent.toString());
+ Font exponentFont = FontManager.getSciFontManager().getFontFromIndex(axisProperty.getFontStyle(), axisProperty.getFontSize() * EXPONENT_SIZE_RATIO);
+ exponentTextEntity.setTextAntiAliased(true);
+ exponentTextEntity.setTextUseFractionalMetrics(axisProperty.getFontFractional());
+ exponentTextEntity.setTextColor(ColorFactory.createColor(colorMap, axisProperty.getFontColor()));
+ exponentTextEntity.setFont(exponentFont);
+ final int exponentHeight = (int) exponentTextEntity.getLayout().getBounds().getHeight();
+ final Dimension exponentSize = exponentTextEntity.getSize();
+
+ Texture texture = textureManager.createTexture();
+
+ texture.setDrawer(new TextureDrawer() {
+
+ @Override
+ public void draw(TextureDrawingTools drawingTools) {
+ drawingTools.draw(mantissaTextEntity, 0, exponentHeight);
+ drawingTools.draw(exponentTextEntity, mantissaSize.width, 0);
+ }
+
+ @Override
+ public Dimension getTextureSize() {
+ return new Dimension(
+ exponentSize.width + mantissaSize.width,
+ exponentHeight + mantissaSize.height
+ );
+ }
+
+ @Override
+ public TextureDrawer.OriginPosition getOriginPosition() {
+ return TextureDrawer.OriginPosition.UPPER_LEFT;
+ }
+ });
+
+ return texture;
+ }
+
+ /**
+ * Create and return a simple texture representing the given value.
+ * @param text the formatted string representing the value.
+ * @param textureManager used texture manager.
+ * @return a simple texture representing the given value with the adapted format.
+ */
+ private Texture createSimpleSprite(String text, TextureManager textureManager) {
+ if (FormattedTextSpriteDrawer.isLatex(text) || FormattedTextSpriteDrawer.isMathML(text)) {
+ FormattedTextSpriteDrawer textObjectSpriteDrawer = new FormattedTextSpriteDrawer(colorMap, text, axisProperty.getTicks().getDefaultFont());
+ Texture texture = textureManager.createTexture();
+ texture.setMagnificationFilter(Texture.Filter.LINEAR);
+ texture.setMinifyingFilter(Texture.Filter.LINEAR);
+ texture.setDrawer(textObjectSpriteDrawer);
+
+ return texture;
+ }
+
+ Font font = FontManager.getSciFontManager().getFontFromIndex(axisProperty.getFontStyle(), axisProperty.getFontSize());
+ final TextEntity textEntity = new TextEntity(text);
+ textEntity.setTextAntiAliased(true);
+ textEntity.setTextUseFractionalMetrics(axisProperty.getFontFractional());
+ textEntity.setTextColor(ColorFactory.createColor(colorMap, axisProperty.getFontColor()));
+ textEntity.setFont(font);
+
+ Texture texture = textureManager.createTexture();
+ texture.setDrawer(new TextureDrawer() {
+
+ @Override
+ public void draw(TextureDrawingTools drawingTools) {
+ drawingTools.draw(textEntity, 0, 0);
+ }
+
+ @Override
+ public Dimension getTextureSize() {
+ return textEntity.getSize();
+ }
+
+ @Override
+ public TextureDrawer.OriginPosition getOriginPosition() {
+ return TextureDrawer.OriginPosition.UPPER_LEFT;
+ }
+ });
+
+ return texture;
+ }
+
+ /**
+ * Return the user defined {@see FormattedText} ticks label corresponding to the given value.
+ * @param value the given value.
+ * @return the user defined {@see FormattedText} ticks label corresponding to the given value.
+ */
+ private FormattedText getTextAtValue(double value) {
+ Double[] locations = axisProperty.getTicksLocations();
+ int index = -1;
+ for (int i = 0 ; i < locations.length ; i++) {
+ if (locations[i] == value) {
+ index = i;
+ break;
+ }
+ }
+ if (index == -1 || index >= axisProperty.getTicksLabels().size()) {
+ return null;
+ } else {
+ return axisProperty.getTicksLabels().get(index);
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/RulerDrawerManager.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/RulerDrawerManager.java
new file mode 100755
index 000000000..4b8924d0d
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/RulerDrawerManager.java
@@ -0,0 +1,160 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.axes.ruler;
+
+import org.scilab.forge.scirenderer.ruler.RulerDrawer;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This class maintain a set of {@see RulerSpriteManager} for all the {@see Axes} create in the {@see GraphicController}
+ * This {@see RulerSpriteManager} are used to draw the rulers of all {@see Axes}.
+ *
+ * @author Pierre Lando
+ */
+class RulerDrawerManager {
+
+ /**
+ * Set of properties that affect ruler sprites.
+ */
+ private static final Set<Integer> SPRITE_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_FONT_SIZE__,
+ GraphicObjectProperties.__GO_FONT_COLOR__,
+ GraphicObjectProperties.__GO_FONT_STYLE__,
+ GraphicObjectProperties.__GO_FONT_FRACTIONAL__,
+ GraphicObjectProperties.__GO_X_AXIS_AUTO_TICKS__,
+ GraphicObjectProperties.__GO_Y_AXIS_AUTO_TICKS__,
+ GraphicObjectProperties.__GO_Z_AXIS_AUTO_TICKS__,
+ GraphicObjectProperties.__GO_X_AXIS_FORMAT__,
+ GraphicObjectProperties.__GO_Y_AXIS_FORMAT__,
+ GraphicObjectProperties.__GO_Z_AXIS_FORMAT__,
+ GraphicObjectProperties.__GO_X_AXIS_ST_FACTORS__,
+ GraphicObjectProperties.__GO_Y_AXIS_ST_FACTORS__,
+ GraphicObjectProperties.__GO_Z_AXIS_ST_FACTORS__,
+ GraphicObjectProperties.__GO_X_AXIS_LOG_FLAG__,
+ GraphicObjectProperties.__GO_Y_AXIS_LOG_FLAG__,
+ GraphicObjectProperties.__GO_Z_AXIS_LOG_FLAG__,
+ GraphicObjectProperties.__GO_DATA_BOUNDS__
+ ));
+
+ /**
+ * Map of up to date {@see RulerSpriteManager}
+ * The key are the {@see Axes} id.
+ */
+ private final Map<Integer, RulerDrawer[]> rulerSpriteManagerMap = new HashMap<Integer, RulerDrawer[]>();
+
+ /** The {@see TextureManager} of the current {@see Canvas}. */
+ private final TextureManager textureManager;
+
+ /**
+ * Default constructor.
+ * @param textureManager the {@see TextureManager} of the current {@see Canvas}.
+ */
+ public RulerDrawerManager(TextureManager textureManager) {
+ this.textureManager = textureManager;
+ }
+
+ /**
+ * Return the {@see RulerDrawer} for the rulers of the given {@see Axes}.
+ * @param axes the given {@see Axes}
+ * @return the {@see RulerSpriteManager} for the rulers of the given {@see Axes}.
+ */
+ public RulerDrawer[] get(Axes axes) {
+ RulerDrawer[] rulerSpriteManager = rulerSpriteManagerMap.get(axes.getIdentifier());
+ if (rulerSpriteManager == null) {
+ rulerSpriteManager = new RulerDrawer[] {new RulerDrawer(textureManager), new RulerDrawer(textureManager), new RulerDrawer(textureManager)};
+ rulerSpriteManager[0].setSpriteFactory(new AxesRulerSpriteFactory(axes, 0));
+ rulerSpriteManager[1].setSpriteFactory(new AxesRulerSpriteFactory(axes, 1));
+ rulerSpriteManager[2].setSpriteFactory(new AxesRulerSpriteFactory(axes, 2));
+ rulerSpriteManagerMap.put(axes.getIdentifier(), rulerSpriteManager);
+ }
+ return rulerSpriteManager;
+ }
+
+
+ /**
+ * Update the data if needed.
+ * @param id the modified object.
+ * @param property the changed property.
+ * @return true if it is really updated
+ */
+ public boolean update(Integer id, int property) {
+
+ /**
+ * If update affect {@see Axes} ruler sprites, we clear the corresponding {@see RulerSpriteManager}.
+ * TODO : optimize by an X, Y, Z auto ticks differentiation.
+ */
+ if (SPRITE_PROPERTIES.contains(property)) {
+ dispose(id);
+ return true;
+ }
+
+ if (property == GraphicObjectProperties.__GO_X_AXIS_TICKS_LABELS__) {
+ RulerDrawer[] rulerSpriteManager = rulerSpriteManagerMap.get(id);
+ if (rulerSpriteManager != null) {
+ rulerSpriteManager[0].disposeResources();
+ }
+ } else if (property == GraphicObjectProperties.__GO_Y_AXIS_TICKS_LABELS__) {
+ RulerDrawer[] rulerSpriteManager = rulerSpriteManagerMap.get(id);
+ if (rulerSpriteManager != null) {
+ rulerSpriteManager[1].disposeResources();
+ }
+ } else if (property == GraphicObjectProperties.__GO_Z_AXIS_TICKS_LABELS__) {
+ RulerDrawer[] rulerSpriteManager = rulerSpriteManagerMap.get(id);
+ if (rulerSpriteManager != null) {
+ rulerSpriteManager[2].disposeResources();
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Dispose the {@see RulerSpriteManager} of the given axes.
+ * @param id the {@see Axes} id.
+ */
+ public void dispose(Integer id) {
+ RulerDrawer[] rulerDrawers = rulerSpriteManagerMap.get(id);
+ if (rulerDrawers != null) {
+ for (RulerDrawer rulerDrawer : rulerDrawers) {
+ if (rulerDrawer != null) {
+ rulerDrawer.disposeResources();
+ }
+ }
+ }
+ rulerSpriteManagerMap.remove(id);
+ }
+
+ /**
+ * Dispose all the {@see RulerSpriteManager}.
+ */
+ public void disposeAll() {
+ for (RulerDrawer[] rulerDrawers : rulerSpriteManagerMap.values()) {
+ if (rulerDrawers != null) {
+ for (RulerDrawer rulerDrawer : rulerDrawers) {
+ if (rulerDrawer != null) {
+ rulerDrawer.disposeResources();
+ }
+ }
+ }
+ }
+ rulerSpriteManagerMap.clear();
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/UserDefineGraduation.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/UserDefineGraduation.java
new file mode 100755
index 000000000..df779034a
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/axes/ruler/UserDefineGraduation.java
@@ -0,0 +1,167 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.axes.ruler;
+
+import org.scilab.forge.scirenderer.ruler.graduations.Graduations;
+import org.scilab.modules.graphic_objects.axes.AxisProperty;
+
+import java.text.DecimalFormat;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author Pierre Lando
+ */
+class UserDefineGraduation implements Graduations {
+ private final AxisProperty axisProperty;
+ private final double lowerBound;
+ private final double upperBound;
+
+ private List<Double> allValues;
+ private List<Double> subValues;
+
+ public UserDefineGraduation(AxisProperty axisProperty, double lowerBound, double upperBound) {
+ this.axisProperty = axisProperty;
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ }
+
+ @Override
+ public double getLowerBound() {
+ return lowerBound;
+ }
+
+ @Override
+ public boolean isLowerBoundIncluded() {
+ return true;
+ }
+
+ @Override
+ public double getUpperBound() {
+ return upperBound;
+ }
+
+ @Override
+ public boolean isUpperBoundIncluded() {
+ return true;
+ }
+
+ @Override
+ public boolean contain(double value) {
+ return (getLowerBound() <= value) && (value <= getUpperBound());
+ }
+
+ @Override
+ public DecimalFormat getFormat() {
+ /**
+ * Will never be used. The label was defined by the user too.
+ */
+ return new DecimalFormat();
+ }
+
+ @Override
+ public List<Double> getAllValues() {
+ if (allValues == null) {
+ Double[] locs = axisProperty.getTicksLocations();
+ final boolean log = axisProperty.getLogFlag();
+ allValues = new LinkedList<Double>();
+ for (Double d : locs) {
+ final double v = log ? Math.log10(d) : d;
+ if (contain(v)) {
+ allValues.add(d);
+ }
+ }
+ }
+ return allValues;
+ }
+
+ @Override
+ public List<Double> getNewValues() {
+ return getAllValues();
+ }
+
+ @Override
+ public Graduations getParentGraduations() {
+ return null;
+ }
+
+ @Override
+ public Graduations getMore() {
+ return null;
+ }
+
+ @Override
+ public Graduations getAlternative() {
+ return null;
+ }
+
+ @Override
+ public Graduations getSubGraduations() {
+ // TODO
+ return null;
+ }
+
+ @Override
+ public List<Double> getSubGraduations(final int N) {
+ if (subValues == null) {
+ if (N == 0) {
+ subValues = new LinkedList<Double>();
+ return subValues;
+ }
+
+ final boolean log = axisProperty.getLogFlag();
+ List<Double> ticksValue = getAllValues();
+ if (ticksValue.isEmpty()) {
+ Double[] locs = axisProperty.getTicksLocations();
+ ticksValue = new LinkedList<Double>();
+ for (Double d : locs) {
+ ticksValue.add(d);
+ }
+ }
+
+ Collections.sort(ticksValue);
+ subValues = new LinkedList<Double>();
+
+ if (!ticksValue.isEmpty()) {
+ for (int i = 0; i < ticksValue.size() - 1; i++) {
+ final double first = ticksValue.get(i);
+ final double second = ticksValue.get(i + 1);
+ final double step = (second - first) / (N + 1);
+ double v = first;
+ for (int j = 0; j <= N; j++) {
+ final double d = log ? Math.log10(v) : v;
+ if (contain(d)) {
+ subValues.add(v);
+ }
+
+ v += step;
+ }
+ }
+
+ double v = ticksValue.get(ticksValue.size() - 1);
+ final double d = log ? Math.log10(v) : v;
+ if (contain(d)) {
+ subValues.add(v);
+ }
+ }
+ }
+
+ return subValues;
+ }
+
+ @Override
+ public int getSubDensity() {
+ return axisProperty.getSubticks() + 1;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/contouredObject/ContouredObjectDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/contouredObject/ContouredObjectDrawer.java
new file mode 100755
index 000000000..1b7705c0c
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/contouredObject/ContouredObjectDrawer.java
@@ -0,0 +1,109 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2011 - DIGITEO - Manuel Juliachs
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.contouredObject;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.modules.graphic_objects.ObjectRemovedException;
+import org.scilab.modules.graphic_objects.contouredObject.ContouredObject;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.renderer.JoGLView.DataManager;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.mark.MarkSpriteManager;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+import org.scilab.modules.renderer.JoGLView.util.OutOfMemoryException;
+
+/**
+ * ContouredObjectDrawer class.
+ * Utility class used by DrawerVisitor to draw ContouredObjects objects.
+ *
+ * @author Manuel JULIACHS
+ */
+public class ContouredObjectDrawer {
+ /** The DrawerVisitor used */
+ private final DrawerVisitor visitor;
+
+ /** The DataManager used */
+ private final DataManager dataManager;
+
+ /** The MarkSpriteManager used */
+ private final MarkSpriteManager markManager;
+
+ /**
+ * Constructor.
+ * @param visitor the DrawerVisitor {@see DrawerVisitor}.
+ * @param dataManagerIn the DataManager {@see DataManager}.
+ * @param markManagerIn the MarkSpriteManager {@see MarkSpriteManager}.
+ */
+ public ContouredObjectDrawer(DrawerVisitor visitor, DataManager dataManagerIn, MarkSpriteManager markManagerIn) {
+ this.visitor = visitor;
+ this.dataManager = dataManagerIn;
+ this.markManager = markManagerIn;
+ }
+
+ /**
+ * Draws the given ContouredObject.
+ * @param contouredObject the ContouredObject to draw.
+ * @param use2dView a boolean specifying whether the 2D view mode is used or not.
+ * @throws org.scilab.forge.scirenderer.SciRendererException if the draw fail.
+ * @throws ObjectRemovedException
+ */
+ public void draw(ContouredObject contouredObject, boolean use2dView) throws SciRendererException, ObjectRemovedException, OutOfMemoryException {
+ DrawingTools drawingTools = visitor.getDrawingTools();
+ ColorMap colorMap = visitor.getColorMap();
+
+ /* Sets the drawn object's identifier as the current one */
+ Integer drawnObjectID = contouredObject.getIdentifier();
+
+ DefaultGeometry geometry = new DefaultGeometry();
+ geometry.setVertices(dataManager.getVertexBuffer(drawnObjectID));
+ geometry.setIndices(dataManager.getIndexBuffer(drawnObjectID));
+ geometry.setWireIndices(dataManager.getWireIndexBuffer(drawnObjectID));
+ geometry.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+
+ Appearance appearance = new Appearance();
+
+ if (contouredObject.getFillMode()) {
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ appearance.setFillColor(ColorFactory.createColor(colorMap, contouredObject.getBackground()));
+ } else {
+ geometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ }
+
+ if (contouredObject.getLineMode()) {
+ geometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ appearance.setLineColor(ColorFactory.createColor(colorMap, contouredObject.getLineColor()));
+ appearance.setLinePattern(contouredObject.getLineStyleAsEnum().asPattern());
+ appearance.setLineWidth(contouredObject.getLineThickness().floatValue());
+ } else {
+ geometry.setLineDrawingMode(Geometry.LineDrawingMode.NONE);
+ }
+
+ if (!use2dView) {
+ geometry.setPolygonOffsetMode(true);
+ }
+
+ drawingTools.draw(geometry, appearance);
+
+ if (contouredObject.getMarkMode()) {
+ Texture texture = markManager.getMarkSprite(contouredObject, colorMap, appearance);
+ ElementsBuffer positions = dataManager.getVertexBuffer(contouredObject.getIdentifier());
+ drawingTools.draw(texture, AnchorPosition.CENTER, positions);
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/datatip/DatatipTextDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/datatip/DatatipTextDrawer.java
new file mode 100755
index 000000000..bc7854390
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/datatip/DatatipTextDrawer.java
@@ -0,0 +1,366 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Pedro Arthur dos S. Souza
+ * Copyright (C) 2012 - Caio Lucas dos S. Souza
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.renderer.JoGLView.datatip;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.forge.scirenderer.tranformations.DegenerateMatrixException;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.PolylineData;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.datatip.Datatip;
+import org.scilab.modules.renderer.CallRenderer;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
+import java.awt.Dimension;
+import org.scilab.modules.renderer.JoGLView.text.TextManager;
+
+/**
+ * Datatip text drawer
+ *
+ * Draw the datatip text according to its orientation and mark properties
+ */
+
+public class DatatipTextDrawer extends TextManager {
+
+ public DatatipTextDrawer(TextureManager textureManager) {
+ super(textureManager);
+ }
+
+ /**
+ * Draw the given Scilab {@see Datatip} with the given {@see DrawingTools}.
+ * @param drawingTools the given {@see DrawingTools}.
+ * @param colorMap the current {@see ColorMap}
+ * @param text the given Scilab {@see Datatip}
+ * @throws SciRendererException if the draw fails.
+ */
+ public final void draw(final DrawingTools drawingTools, final ColorMap colorMap, final Datatip datatip) throws SciRendererException {
+ Texture texture = getTexture(colorMap, datatip);
+
+ /* The unscaled texture's dimensions */
+ Dimension spriteDims = getSpriteDims(colorMap, datatip);
+
+ Transformation projection = drawingTools.getTransformationManager().getCanvasProjection();
+
+ Integer parentAxesId = datatip.getParentAxes();
+ Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentAxesId);
+
+ /* Compute the text box vectors and the text box to texture dimension ratios */
+ Vector3d[] textBoxVectors = computeTextBoxVectors(projection, datatip, texture.getDataProvider().getTextureSize(), parentAxes);
+
+ double[] ratios = computeRatios(projection, datatip, textBoxVectors, texture.getDataProvider().getTextureSize(), spriteDims);
+
+ /* If text box mode is equal to filled, the texture must be updated */
+ if (datatip.getTextBoxMode() == 2 && ratios[0] != 1.0) {
+ texture = updateSprite(colorMap, datatip, ratios[0], ratios[1]);
+ }
+
+ /* Compute the text texture's actual position, which depends on the object's text box mode property */
+ Vector3d[] cornerPositions = computeTextPosition(projection, datatip, textBoxVectors, texture.getDataProvider().getTextureSize());
+
+ /* Draw in window coordinates */
+ drawingTools.getTransformationManager().useWindowCoordinate();
+
+ Integer size = datatip.getMarkSize();
+ Integer unit = datatip.getMarkSizeUnit();
+
+ /* calculate the size of the mark to dont draw the text over the mark*/
+ double finalSize = (unit == 1) ? (8.0 + 2.0 * size) : size;
+ finalSize /= 2.0;
+ double r = datatip.getMarkStyle() == 11 ? 1.0 : 2.0;
+ finalSize -= (finalSize >= 2.0) ? r : 0.0;
+
+ Vector3d delta = new Vector3d(finalSize, finalSize, 0);
+ /* set up the text position according to the datatip orientation*/
+ if (datatip.isAutoOrientationEnabled()) {
+ int autopos = getAutoOrientation(datatip);
+ if (autopos != -1) {
+ Vector3d cp = cornerPositions[0], d = delta, p;
+ if (autopos == 2 || autopos == 3) {
+ cp = cp.minus(textBoxVectors[1]);
+ d = d.setY(-finalSize);
+ }
+ if (autopos == 0 || autopos == 2) {
+ cp = cp.minus(textBoxVectors[0]);
+ d = d.setX(-finalSize);
+ }
+
+ p = projection.unproject(cp.plus(textBoxVectors[0]).plus(textBoxVectors[1]));
+ Vector3d ucp = projection.unproject(cp);
+ if (p.getX() < -1 || p.getX() > 1 || p.getY() < -1 || p.getY() > 1 || ucp.getX() < -1 || ucp.getX() > 1 || ucp.getY() < -1 || ucp.getY() > 1) {
+ autopos = -1;
+ } else {
+ cornerPositions[0] = cp;
+ delta = d;
+ }
+ }
+
+ if (autopos == -1) {
+ Vector3d position = projection.unproject(cornerPositions[0].minus(textBoxVectors[0]).plus(textBoxVectors[1]));
+ if (position.getX() >= -1 && position.getX() <= 1 && position.getY() >= -1 && position.getY() <= 1) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
+ delta = delta.setX(-finalSize);
+ } else {
+ position = projection.unproject(cornerPositions[0].plus(textBoxVectors[0]).minus(textBoxVectors[1]));
+ if (position.getX() >= -1 && position.getX() <= 1 && position.getY() >= -1 && position.getY() <= 1) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
+ delta = delta.setY(-finalSize);
+ } else {
+ position = projection.unproject(cornerPositions[0].minus(textBoxVectors[0]).minus(textBoxVectors[1]));
+ if (position.getX() >= -1 && position.getX() <= 1 && position.getY() >= -1 && position.getY() <= 1) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
+ delta = delta.setX(-finalSize);
+ delta = delta.setY(-finalSize);
+ }
+ }
+ }
+ }
+ } else {
+ if (datatip.getOrientation() == 2 || datatip.getOrientation() == 3) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
+ delta = delta.setY(-finalSize);
+ }
+ if (datatip.getOrientation() == 0 || datatip.getOrientation() == 2) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
+ delta = delta.setX(-finalSize);
+ }
+ if (datatip.getOrientation() == 4) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1].times(0.5));
+ delta = delta.setY(0);
+ delta = delta.setX(Math.sqrt(2)*(-finalSize));
+ }
+ if (datatip.getOrientation() == 5) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1].times(0.5));
+ delta = delta.setY(0);
+ delta = delta.setX(Math.sqrt(2)*finalSize);
+ }
+ if (datatip.getOrientation() == 6) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0].times(0.5));
+ delta = delta.setX(0);
+ delta = delta.setY(Math.sqrt(2)*finalSize);
+ }
+ if (datatip.getOrientation() == 7) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0].times(0.5));
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
+ delta = delta.setX(0);
+ delta = delta.setY(Math.sqrt(2)*(-finalSize));
+ }
+ }
+
+ cornerPositions[0] = cornerPositions[0].plus(delta);
+ cornerPositions[1] = cornerPositions[1].plus(delta);
+
+ /* The Text object's rotation direction convention is opposite to the standard one, its angle is expressed in radians. */
+ drawingTools.draw(texture, AnchorPosition.LOWER_LEFT, cornerPositions[0], -180.0 * datatip.getFontAngle() / Math.PI);
+
+ drawingTools.getTransformationManager().useSceneCoordinate();
+
+ /* Compute the corners of the text's bounding box in window coordinates */
+ Vector3d[] projCorners;
+ if (datatip.getTextBoxMode() == 2) {
+ projCorners = computeProjTextBoxCorners(cornerPositions[1], datatip.getFontAngle(), textBoxVectors);
+ } else {
+ projCorners = computeProjCorners(cornerPositions[0], datatip.getFontAngle(), texture.getDataProvider().getTextureSize());
+ }
+
+ Vector3d[] corners = computeCorners(projection, projCorners, parentAxes);
+ Double[] coordinates = cornersToCoordinateArray(corners);
+
+ /* Set the computed coordinates */
+ datatip.setCorners(coordinates);
+ }
+
+ /**
+ * Update the given datatip text corners
+ * @param datatip the given datatip
+ */
+ public static void updateTextCorners(Datatip datatip) {
+ Vector3d[] projCorners = null;
+ DrawerVisitor currentVisitor = DrawerVisitor.getVisitor(datatip.getParentFrameOrFigure());
+ Transformation currentProj = currentVisitor.getAxesDrawer().getProjection(datatip.getParentAxes());
+ Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(datatip.getParentAxes());
+ Dimension spriteDim = currentVisitor.getDatatipTextDrawer().getSpriteDims(currentVisitor.getColorMap(), datatip);
+
+ /* Compute the corners */
+ try {
+ Vector3d[] textBoxVectors = currentVisitor.getDatatipTextDrawer().computeTextBoxVectors(currentProj, datatip, spriteDim, parentAxes);
+ Vector3d[] cornerPositions = currentVisitor.getDatatipTextDrawer().computeTextPosition(currentProj, datatip, textBoxVectors, spriteDim);
+
+ Integer size = datatip.getMarkSize();
+ Integer unit = datatip.getMarkSizeUnit();
+
+ /* calculate the size of the mark to dont position the text over the mark*/
+ double finalSize = (unit == 1) ? (8.0 + 2.0 * size) : size;
+ finalSize /= 2.0;
+ double r = datatip.getMarkStyle() == 11 ? 1.0 : 2.0;
+ finalSize -= (finalSize >= 2.0) ? r : 0.0;
+
+ Vector3d delta = new Vector3d(finalSize, finalSize, 0);
+ /* set up the text position according to the datatip orientation*/
+ if (datatip.getOrientation() == 2 || datatip.getOrientation() == 3) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
+ delta = delta.setY(-finalSize);
+ }
+ if (datatip.getOrientation() == 0 || datatip.getOrientation() == 2) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
+ delta = delta.setX(-finalSize);
+ }
+ if (datatip.getOrientation() == 4) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1].times(0.5));
+ delta = delta.setY(0);
+ delta = delta.setX(Math.sqrt(2)*(-finalSize));
+ }
+ if (datatip.getOrientation() == 5) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1].times(0.5));
+ delta = delta.setY(0);
+ delta = delta.setX(Math.sqrt(2)*finalSize);
+ }
+ if (datatip.getOrientation() == 6) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0].times(0.5));
+ delta = delta.setX(0);
+ delta = delta.setY(Math.sqrt(2)*finalSize);
+ }
+ if (datatip.getOrientation() == 7) {
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0].times(0.5));
+ cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
+ delta = delta.setX(0);
+ delta = delta.setY(Math.sqrt(2)*(-finalSize));
+ }
+
+ cornerPositions[0] = cornerPositions[0].plus(delta);
+ cornerPositions[1] = cornerPositions[1].plus(delta);
+
+ if (datatip.getTextBoxMode() == 2) {
+ projCorners = currentVisitor.getDatatipTextDrawer().computeProjTextBoxCorners(cornerPositions[1], datatip.getFontAngle(), textBoxVectors);
+ } else {
+ projCorners = currentVisitor.getDatatipTextDrawer().computeProjCorners(cornerPositions[0], datatip.getFontAngle(), spriteDim);
+ }
+ } catch (DegenerateMatrixException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ Vector3d[] corners = currentVisitor.getDatatipTextDrawer().computeCorners(currentProj, projCorners, parentAxes);
+ Double[] coordinates = currentVisitor.getDatatipTextDrawer().cornersToCoordinateArray(corners);
+
+ /* Set the computed coordinates */
+ datatip.setCorners(coordinates);
+ }
+
+ /**
+ * Calculates the anchor point from datatip (Used to draw the datatip mark)
+ * @param datatip the given datatip
+ * @return Vector3d the anchor point position
+ */
+ public static Vector3d calculateAnchorPoint(Datatip datatip) {
+ Axes axes = (Axes) GraphicController.getController().getObjectFromId(datatip.getParentAxes());
+ double[][] factors = axes.getScaleTranslateFactors();
+ boolean[] logFlags = new boolean[] {axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
+ Vector3d v = ScaleUtils.applyLogScale(new Vector3d(datatip.getTipData()), logFlags);
+
+ return new Vector3d(v.getX() * factors[0][0] + factors[1][0], v.getY() * factors[0][1] + factors[1][1], v.getZ() * factors[0][2] + factors[1][2]);
+ }
+
+ private static int getAutoOrientation(Datatip datatip) {
+ final double[] dataX = (double[]) PolylineData.getDataX(datatip.getParent());
+ int index = datatip.getIndexes();
+ if (index == 0 || index >= dataX.length - 1) {
+ return -1;
+ }
+
+ final double[] dataY = (double[]) PolylineData.getDataY(datatip.getParent());
+ final double[] first, second, third;
+ Integer axes = datatip.getParentAxes();
+
+ if (datatip.isUsing3Component()) {
+ final double[] dataZ = (double[]) PolylineData.getDataZ(datatip.getParent());
+ first = CallRenderer.getPixelFrom3dCoordinates(axes, new double[] {dataX[index - 1], dataY[index - 1], dataZ[index - 1]});
+ second = CallRenderer.getPixelFrom3dCoordinates(axes, new double[] {dataX[index], dataY[index], dataZ[index]});
+ third = CallRenderer.getPixelFrom3dCoordinates(axes, new double[] {dataX[index + 1], dataY[index + 1], dataZ[index + 1]});
+ } else {
+ first = CallRenderer.getPixelFrom3dCoordinates(axes, new double[] {dataX[index - 1], dataY[index - 1], 0});
+ second = CallRenderer.getPixelFrom3dCoordinates(axes, new double[] {dataX[index], dataY[index], 0});
+ third = CallRenderer.getPixelFrom3dCoordinates(axes, new double[] {dataX[index + 1], dataY[index + 1], 0});
+ }
+
+ final double a = Math.atan2(second[1] - first[1], first[0] - second[0]);
+ final double b = Math.atan2(second[1] - third[1], third[0] - second[0]);
+
+ final int quadA = getQuad(a);
+ final int quadB = getQuad(b);
+ final int quadDatatip;
+
+ // UL quadrant is 1, UR quadrant is 0
+ // LL quadrant is 2, LR quadrant is 3
+
+ if (quadA == quadB) {
+ quadDatatip = (quadA + 2) % 4;
+ } else {
+ final int sum = quadA + quadB;
+ if (sum == 3) {
+ quadDatatip = (quadA * quadB + 1) % 3;
+ } else if (sum == 1 || sum == 5) {
+ quadDatatip = (sum + 3) % 8;
+ } else {
+ final double M = Math.max(a, b);
+ final double m = Math.min(a, b);
+ if (sum == 4) {
+ if (M - m <= Math.PI) {
+ quadDatatip = 2;
+ } else {
+ quadDatatip = 0;
+ }
+ } else {
+ if (M - m <= Math.PI) {
+ quadDatatip = 1;
+ } else {
+ quadDatatip = 3;
+ }
+ }
+ }
+ }
+
+ if (quadDatatip <= 1) {
+ return 1 - quadDatatip;
+ }
+
+ return quadDatatip;
+ }
+
+ private static int getQuad(final double a) {
+ if (a >= 0) {
+ if (a <= Math.PI / 2) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ if (a <= -Math.PI / 2) {
+ return 2;
+ } else {
+ return 3;
+ }
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/editor/FigureFrame.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/editor/FigureFrame.java
new file mode 100755
index 000000000..3da77036f
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/editor/FigureFrame.java
@@ -0,0 +1,49 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.editor;
+
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.TreeCellRenderer;
+import javax.swing.tree.TreeModel;
+import java.awt.*;
+
+/**
+ * @author Pierre Lando
+ */
+@SuppressWarnings(value = { "serial" })
+public class FigureFrame extends JFrame {
+ private final TreeModel treeModel;
+ public FigureFrame(Integer id) {
+ treeModel = new SciTreeModel(id);
+ initialize();
+ }
+
+ private void initialize() {
+ JTree tree = new JTree(treeModel);
+
+ tree.setCellRenderer(new TreeCellRenderer() {
+ private final TreeCellRenderer renderer = new DefaultTreeCellRenderer();
+ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+ Object type = GraphicController.getController().getProperty((Integer)value, GraphicObjectProperties.__GO_TYPE__);
+ return renderer.getTreeCellRendererComponent(tree, type, selected, expanded, leaf, row, hasFocus);
+ }
+ });
+
+ add(tree);
+ setSize(400, 500);
+ setVisible(true);
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/editor/SciTreeModel.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/editor/SciTreeModel.java
new file mode 100755
index 000000000..15c8b270b
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/editor/SciTreeModel.java
@@ -0,0 +1,156 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.editor;
+
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicView.GraphicView;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+
+import javax.swing.event.EventListenerList;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+import java.util.Vector;
+
+/**
+ * @author Pierre Lando
+ */
+public class SciTreeModel implements TreeModel, GraphicView {
+ private final Integer rootId;
+ private final EventListenerList listeners = new EventListenerList();
+
+ public SciTreeModel(Integer id) {
+ this.rootId = id;
+ GraphicController.getController().register(this);
+ }
+
+ public Object getRoot() {
+ return rootId;
+ }
+
+ public Object getChild(Object parent, int index) {
+ if (parent instanceof Integer) {
+ Integer id = (Integer) parent;
+ Object children = GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_CHILDREN__);
+ if (children instanceof Integer[]) {
+ if (index >= 0 && index < ((Integer[]) children).length) {
+ return ((Integer[]) children)[index];
+ }
+ }
+ }
+ return null;
+ }
+
+ public int getChildCount(Object parent) {
+ if (parent instanceof Integer) {
+ Integer id = (Integer) parent;
+ Object children = GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_CHILDREN__);
+ if (children instanceof Integer[]) {
+ return ((Integer[]) children).length;
+ }
+ }
+ return 0;
+ }
+
+ public boolean isLeaf(Object node) {
+ return getChildCount(node) == 0;
+ }
+
+ public void valueForPathChanged(TreePath path, Object newValue) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ public int getIndexOfChild(Object parent, Object child) {
+ Integer childId;
+ if (child instanceof Integer) {
+ childId = (Integer) child;
+ if (parent instanceof Integer) {
+ Integer id = (Integer) parent;
+ Object children = GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_CHILDREN__);
+ if (children instanceof Integer[]) {
+ for (int i = 0 ; i < ((Integer[]) children).length ; i++) {
+ if (((Integer[]) children)[i] == childId) {
+ return i;
+ }
+ }
+ }
+ }
+ }
+ return -1;
+ }
+
+ public void addTreeModelListener(TreeModelListener l) {
+ listeners.add(TreeModelListener.class, l);
+ }
+
+ public void removeTreeModelListener(TreeModelListener l) {
+ listeners.remove(TreeModelListener.class, l);
+ }
+
+ public void updateObject(Integer id, int property) {
+ System.out.println("SciTreeModel");
+ Vector<Integer> path = getPath(id);
+ if (path != null) {
+ for (TreeModelListener listener : listeners.getListeners(TreeModelListener.class)) {
+ TreeModelEvent e = new TreeModelEvent(id, path.toArray(), new int[] {0}, new Object[] {id});
+ listener.treeStructureChanged(e);
+ }
+ }
+ }
+
+ public void createObject(Integer id) {
+ Vector<Integer> path = getPath(id);
+ if (path != null) {
+ for (TreeModelListener listener : listeners.getListeners(TreeModelListener.class)) {
+ TreeModelEvent e = new TreeModelEvent(id, path.toArray(), new int[] {0}, new Object[] {id});
+ listener.treeNodesInserted(e);
+ }
+ }
+ }
+
+ public void deleteObject(Integer id) {
+ Vector<Integer> path = getPath(id);
+ if (path != null) {
+ for (TreeModelListener listener : listeners.getListeners(TreeModelListener.class)) {
+ TreeModelEvent e = new TreeModelEvent(id, path.toArray(), new int[] {0}, new Object[] {id});
+ listener.treeNodesRemoved(e);
+ }
+ }
+ }
+
+ private Vector<Integer> getPath(Integer id) {
+ Integer parentId = getParent(id);
+ // TODO : remove parentId.equals("")
+ if (parentId == null || parentId.equals("")) {
+ return null;
+ } else if (parentId.equals(rootId)) {
+ Vector<Integer> v = new Vector<Integer>();
+ v.add(rootId);
+ return v;
+ } else {
+ Vector<Integer> v = getPath(parentId);
+ if (v != null) {
+ v.add(parentId);
+ }
+ return v;
+ }
+ }
+
+ private Integer getParent(Integer id) {
+ Object parent = GraphicController.getController().getProperty(id, GraphicObjectProperties.__GO_PARENT__);
+ if (parent instanceof Integer) {
+ return (Integer) parent;
+ }
+ return null;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/DragPointRubberBox.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/DragPointRubberBox.java
new file mode 100755
index 000000000..790bc3696
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/DragPointRubberBox.java
@@ -0,0 +1,135 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction;
+
+import java.awt.event.MouseEvent;
+
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+
+/**
+ * @author Bruno JOFRET
+ */
+public class DragPointRubberBox extends TwoPointsRubberBox {
+
+ /**
+ * Default constructor.
+ *
+ * @param drawerVisitor parent drawer visitor.
+ */
+ public DragPointRubberBox(DrawerVisitor drawerVisitor) {
+ super(drawerVisitor);
+ }
+
+ @Override
+ public final void mouseClicked(MouseEvent e) {
+
+ }
+ @Override
+ public void mousePressed(MouseEvent e) {
+ mouseButton = e.getButton();
+ switch (status) {
+ case WAIT_POINT_A:
+ if (setPointA(e.getPoint())) {
+ status = Status.WAIT_POINT_B;
+ } else {
+ setEnable(false);
+ fireRubberBoxEnd();
+ }
+ break;
+ case WAIT_POINT_B:
+ setPointB(e.getPoint());
+ if (pointBComputer.is2D()) {
+ process();
+ setEnable(false);
+ fireRubberBoxEnd();
+ } else {
+ status = Status.WAIT_POINT_C;
+ }
+ break;
+ case WAIT_POINT_C:
+ setPointC(e.getPoint());
+ status = Status.WAIT_POINT_D;
+ break;
+ case WAIT_POINT_D:
+ setPointD(e.getPoint());
+ process();
+ setEnable(false);
+ fireRubberBoxEnd();
+ break;
+ default:
+ }
+ updateInfoMessage();
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ mouseButton = e.getButton();
+ switch (status) {
+ case WAIT_POINT_A:
+ if (setPointA(e.getPoint())) {
+ status = Status.WAIT_POINT_B;
+ } else {
+ setEnable(false);
+ fireRubberBoxEnd();
+ }
+ break;
+ case WAIT_POINT_B:
+ setPointB(e.getPoint());
+ if (pointBComputer.is2D()) {
+ process();
+ setEnable(false);
+ fireRubberBoxEnd();
+ } else {
+ status = Status.WAIT_POINT_C;
+ }
+ break;
+ case WAIT_POINT_C:
+ setPointC(e.getPoint());
+ status = Status.WAIT_POINT_D;
+ break;
+ case WAIT_POINT_D:
+ setPointD(e.getPoint());
+ process();
+ setEnable(false);
+ fireRubberBoxEnd();
+ break;
+ default:
+ }
+ updateInfoMessage();
+ }
+
+ @Override
+ public final void mouseDragged(MouseEvent e) {
+ switch (status) {
+ case WAIT_POINT_A:
+ setPointA(e.getPoint());
+ getDrawerVisitor().getCanvas().redraw();
+ break;
+ case WAIT_POINT_B:
+ setPointB(e.getPoint());
+ getDrawerVisitor().getCanvas().redraw();
+ break;
+ case WAIT_POINT_C:
+ setPointC(e.getPoint());
+ getDrawerVisitor().getCanvas().redraw();
+ break;
+ case WAIT_POINT_D:
+ setPointD(e.getPoint());
+ getDrawerVisitor().getCanvas().redraw();
+ break;
+ default:
+ }
+ updateInfoMessage();
+ }
+
+
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/DragZoomRotateInteraction.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/DragZoomRotateInteraction.java
new file mode 100755
index 000000000..a1a741364
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/DragZoomRotateInteraction.java
@@ -0,0 +1,373 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+package org.scilab.modules.renderer.JoGLView.interaction;
+
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionAdapter;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+
+import org.scilab.modules.commons.OS;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
+
+/**
+ * This class manage figure interaction.
+ *
+ * @author Pierre Lando
+ */
+public class DragZoomRotateInteraction extends FigureInteraction {
+
+ private static final int XY_TRANSLATION_MODIFIER = MouseEvent.BUTTON1_MASK;
+ private static final int Z_TRANSLATION_MODIFIER = MouseEvent.BUTTON1_MASK | MouseEvent.ALT_MASK;
+ private static final int ROTATION_MODIFIER = MouseEvent.BUTTON3_MASK;
+ private static final int MACOSX_ROTATION_MODIFIER = MouseEvent.BUTTON1_MASK | MouseEvent.CTRL_MASK;
+
+ /**
+ * The box size is multiply by this value.
+ */
+ private static final double ZOOM_FACTOR = 1.02;
+
+ private final MouseListener mouseListener;
+ private final MouseWheelListener mouseWheelListener;
+ private final MouseMotionListener mouseMotionListener;
+
+ /**
+ * Last important mouse event.
+ */
+ private MouseEvent previousEvent;
+ private Axes currentAxes;
+
+
+ /**
+ * Default constructor.
+ * @param drawerVisitor parent drawer visitor.
+ */
+ public DragZoomRotateInteraction(DrawerVisitor drawerVisitor) {
+ super(drawerVisitor);
+ mouseMotionListener = new FigureMouseMotionListener();
+ mouseWheelListener = new FigureMouseWheelListener();
+ mouseListener = new FigureMouseListener();
+ }
+
+ @Override
+ protected void changeEnable(boolean isEnable) {
+ Component component = getDrawerVisitor().getComponent();
+ if (component != null) {
+ if (isEnable) {
+ component.addMouseListener(mouseListener);
+ component.addMouseWheelListener(mouseWheelListener);
+ } else {
+ component.removeMouseListener(mouseListener);
+ component.removeMouseMotionListener(mouseMotionListener);
+ component.removeMouseWheelListener(mouseWheelListener);
+ }
+ }
+ }
+
+ public void setTranslationEnable(boolean status) {
+ ((FigureMouseMotionListener)mouseMotionListener).setTranslateEnable(status);
+ }
+
+ /**
+ * This {@see MouseListner} activate the {@see MouseMotionListener} when at least
+ * one button is pressed.
+ * The event is saved in {@see previousEvent}
+ */
+ private class FigureMouseListener extends MouseAdapter implements MouseListener {
+
+ private int pressedButtons = 0;
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if (pressedButtons == 0) {
+ previousEvent = e;
+ if (currentAxes == null) {
+ currentAxes = getUnderlyingAxes(e.getPoint());
+ if (currentAxes != null) {
+ getDrawerVisitor().getComponent().addMouseMotionListener(mouseMotionListener);
+ switch (e.getButton()) {
+ case MouseEvent.BUTTON1 :
+ Cursor cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
+ e.getComponent().setCursor(cursor);
+ break;
+ case MouseEvent.BUTTON3 :
+ // FIXME: add rotation cursor here
+ break;
+ }
+ }
+ }
+ }
+ pressedButtons++;
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ if (pressedButtons > 0) {
+ pressedButtons--;
+ }
+
+ if (pressedButtons == 0) {
+ getDrawerVisitor().getComponent().removeMouseMotionListener(mouseMotionListener);
+ currentAxes = null;
+ }
+ e.getComponent().setCursor(Cursor.getDefaultCursor());
+ }
+ }
+
+ /**
+ * This {@see MouseWheelListener} manage zoom/un-zoom on the figure.
+ */
+ private class FigureMouseWheelListener implements MouseWheelListener {
+
+ @Override
+ public void mouseWheelMoved(MouseWheelEvent e) {
+ Axes axes = getUnderlyingAxes(e.getPoint());
+ if (axes != null) {
+ double scale = Math.pow(ZOOM_FACTOR, e.getUnitsToScroll());
+ Double[] bounds = axes.getDisplayedBounds();
+ double[][] factors = axes.getScaleTranslateFactors();
+
+ double xDelta = (bounds[1] - bounds[0]) / 2;
+ double xMiddle = (bounds[1] + bounds[0]) / 2;
+ bounds[0] = xMiddle - xDelta * scale;
+ bounds[1] = xMiddle + xDelta * scale;
+
+ double yDelta = (bounds[3] - bounds[2]) / 2;
+ double yMiddle = (bounds[3] + bounds[2]) / 2;
+ bounds[2] = yMiddle - yDelta * scale;
+ bounds[3] = yMiddle + yDelta * scale;
+
+ double zDelta = (bounds[5] - bounds[4]) / 2;
+ double zMiddle = (bounds[5] + bounds[4]) / 2;
+ bounds[4] = zMiddle - zDelta * scale;
+ bounds[5] = zMiddle + zDelta * scale;
+
+ bounds[0] = bounds[0] * factors[0][0] + factors[1][0];
+ bounds[1] = bounds[1] * factors[0][0] + factors[1][0];
+ bounds[2] = bounds[2] * factors[0][1] + factors[1][1];
+ bounds[3] = bounds[3] * factors[0][1] + factors[1][1];
+ bounds[4] = bounds[4] * factors[0][2] + factors[1][2];
+ bounds[5] = bounds[5] * factors[0][2] + factors[1][2];
+
+ Boolean zoomed = tightZoomBounds(axes, bounds);
+
+ bounds[0] = (bounds[0] - factors[1][0]) / factors[0][0];
+ bounds[1] = (bounds[1] - factors[1][0]) / factors[0][0];
+ bounds[2] = (bounds[2] - factors[1][1]) / factors[0][1];
+ bounds[3] = (bounds[3] - factors[1][1]) / factors[0][1];
+ bounds[4] = (bounds[4] - factors[1][2]) / factors[0][2];
+ bounds[5] = (bounds[5] - factors[1][2]) / factors[0][2];
+
+ boolean[] logFlags = { axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
+ ScaleUtils.applyInverseLogScaleToBounds(bounds, logFlags);
+
+ GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
+ GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
+
+ }
+ }
+ }
+
+ private static void applyUnlog(Double[] bounds, Axes axes) {
+ if (axes.getXAxisLogFlag()) {
+ bounds[0] = Math.pow(10, bounds[0]);
+ bounds[1] = Math.pow(10, bounds[1]);
+ }
+
+ if (axes.getYAxisLogFlag()) {
+ bounds[2] = Math.pow(10, bounds[2]);
+ bounds[3] = Math.pow(10, bounds[3]);
+ }
+
+ if (axes.getZAxisLogFlag()) {
+ bounds[4] = Math.pow(10, bounds[4]);
+ bounds[5] = Math.pow(10, bounds[5]);
+ }
+ }
+
+ /**
+ * This {@see MouseMotionListener} manage rotation and translation on the figure.
+ */
+ private class FigureMouseMotionListener extends MouseMotionAdapter implements MouseMotionListener {
+
+ private boolean translateEnabled = true;
+
+ public void setTranslateEnable(boolean status) {
+ translateEnabled = status;
+ }
+
+ @Override
+ public void mouseMoved(MouseEvent e) {
+ /*
+ * Mac OS X specific case: the users first presses CTRL and then left-clic.
+ */
+ if (OS.get() == OS.MAC && e.isControlDown() && e.getButton() == 0) {
+ doRotation(e);
+ }
+ }
+ public void mouseDragged(MouseEvent e) {
+ switch (e.getModifiers()) {
+ case MACOSX_ROTATION_MODIFIER:
+ /*
+ * Mac OS X specific case: the users first left-clic and then presses CTRL
+ */
+ if (OS.get() == OS.MAC && e.isControlDown()) {
+ doRotation(e);
+ break;
+ }
+ break;
+ case XY_TRANSLATION_MODIFIER:
+ if (translateEnabled) {
+ doXYTranslation(e);
+ }
+ break;
+ case Z_TRANSLATION_MODIFIER:
+ doZTranslation(e);
+ break;
+ case ROTATION_MODIFIER:
+ doRotation(e);
+ break;
+ }
+ previousEvent = e;
+ }
+
+ private void doRotation(MouseEvent e) {
+ int dx = e.getX() - previousEvent.getX();
+ int dy = e.getY() - previousEvent.getY();
+
+ if (currentAxes != null) {
+ Double[] angles = currentAxes.getRotationAngles();
+ angles[0] -= dy / 4.0;
+ angles[1] -= Math.signum(Math.sin(Math.toRadians(angles[0]))) * (dx / 4.0);
+ GraphicController.getController().setProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_ROTATION_ANGLES__, angles);
+ }
+ }
+
+ private void doXYTranslation(MouseEvent e) {
+ int dx = e.getX() - previousEvent.getX();
+ int dy = e.getY() - previousEvent.getY();
+
+ if (currentAxes != null) {
+ if (currentAxes.getZoomEnabled()) {
+ Double[] bounds = currentAxes.getDisplayedBounds();
+
+ Integer[] winSize = (Integer[]) GraphicController.getController().getProperty(currentAxes.getParent(), GraphicObjectProperties.__GO_AXES_SIZE__);
+ if (winSize == null) {
+ // We are in a Frame
+ Double[] position = (Double[]) GraphicController.getController().getProperty(currentAxes.getParent(), GraphicObjectProperties.__GO_POSITION__);
+ winSize = new Integer[2];
+ winSize[0] = position[2].intValue();
+ winSize[1] = position[3].intValue();
+ }
+ Double[] axesBounds = (Double[]) GraphicController.getController().getProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_AXES_BOUNDS__);
+ Double[] axesMargins = (Double[]) GraphicController.getController().getProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_MARGINS__);
+ Integer view = (Integer) GraphicController.getController().getProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_VIEW__);
+
+ // Compute ratio from pixel move to user displayed data bounds
+ double xDelta = Math.abs(bounds[0] - bounds[1]) / (winSize[0] * axesBounds[2] * (1 - axesMargins[0] - axesMargins[1]));
+ double yDelta = Math.abs(bounds[2] - bounds[3]) / (winSize[1] * axesBounds[3] * (1 - axesMargins[2] - axesMargins[3]));
+
+ if (view == 0) {
+ // 2D View
+ bounds[0] -= xDelta * dx;
+ bounds[1] -= xDelta * dx;
+
+ bounds[2] += yDelta * dy;
+ bounds[3] += yDelta * dy;
+ } else {
+ // 3D view
+ double orientation = - Math.signum(Math.cos(Math.toRadians(currentAxes.getRotationAngles()[0])));
+ double angle = - orientation * Math.toRadians(currentAxes.getRotationAngles()[1]);
+
+ double rotatedDX = dx * Math.sin(angle) + dy * Math.cos(angle);
+ double rotatedDY = dx * Math.cos(angle) - dy * Math.sin(angle);
+
+ bounds[0] -= xDelta * rotatedDX * orientation;
+ bounds[1] -= xDelta * rotatedDX * orientation;
+
+ bounds[2] += yDelta * rotatedDY;
+ bounds[3] += yDelta * rotatedDY;
+ }
+
+ Boolean zoomed = tightZoomBoxToDataBounds(currentAxes, bounds);
+ boolean[] logFlags = { currentAxes.getXAxisLogFlag(), currentAxes.getYAxisLogFlag(), currentAxes.getZAxisLogFlag()};
+ ScaleUtils.applyInverseLogScaleToBounds(bounds, logFlags);
+
+ GraphicController.getController().setProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
+ GraphicController.getController().setProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
+ }
+ }
+ }
+
+ private void doZTranslation(MouseEvent e) {
+ int dy = e.getY() - previousEvent.getY();
+
+ if (currentAxes != null) {
+ Double[] bounds = currentAxes.getDisplayedBounds();
+
+ double zDelta = (bounds[5] - bounds[4]) / 100;
+
+ bounds[4] += zDelta * dy;
+ bounds[5] += zDelta * dy;
+
+ Boolean zoomed = tightZoomBoxToDataBounds(currentAxes, bounds);
+ boolean[] logFlags = { currentAxes.getXAxisLogFlag(), currentAxes.getYAxisLogFlag(), currentAxes.getZAxisLogFlag()};
+ ScaleUtils.applyInverseLogScaleToBounds(bounds, logFlags);
+
+ GraphicController.getController().setProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
+ GraphicController.getController().setProperty(currentAxes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
+ }
+ }
+
+ /**
+ * Tight given bounds to axes data bounds.
+ * Bounds length along axes are conserved.
+ * @param axes the given axes.
+ * @param zoomBounds the zoomBounds.
+ * @return true if actually there is a zoom.
+ */
+ private boolean tightZoomBoxToDataBounds(Axes axes, Double[] zoomBounds) {
+ boolean zoomed = false;
+ Double[] dataBounds = axes.getMaximalDisplayedBounds();
+ for (int i : new int[] {0, 2, 4}) {
+ if (zoomBounds[i] < dataBounds[i]) {
+ double delta = dataBounds[i] - zoomBounds[i];
+ zoomBounds[i] = dataBounds[i]; // zoomBounds[i] += delta;
+ zoomBounds[i + 1] += delta;
+ } else {
+ zoomed = true;
+ }
+ }
+
+ for (int i : new int[] {1, 3, 5}) {
+ if (zoomBounds[i] > dataBounds[i]) {
+ double delta = dataBounds[i] - zoomBounds[i];
+ zoomBounds[i] = dataBounds[i]; // zoomBounds[i] += delta;
+ zoomBounds[i - 1] += delta;
+ } else {
+ zoomed = true;
+ }
+ }
+
+ return zoomed;
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/FigureInteraction.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/FigureInteraction.java
new file mode 100755
index 000000000..b96d514d4
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/FigureInteraction.java
@@ -0,0 +1,140 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction;
+
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObject;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+
+import java.awt.Dimension;
+import java.awt.Point;
+
+/**
+ * @author Pierre Lando
+ */
+public abstract class FigureInteraction {
+
+ /** parent figure drawer */
+ private DrawerVisitor drawerVisitor;
+
+ /** Enable status */
+ private boolean isEnable;
+
+ /**
+ * Default constructor.
+ * @param drawerVisitor parent figure drawer.
+ */
+ public FigureInteraction(DrawerVisitor drawerVisitor) {
+ this.drawerVisitor = drawerVisitor;
+ isEnable = false;
+ }
+
+ /**
+ * Drawer visitor getter.
+ * @return the parent figure drawer.
+ */
+ protected DrawerVisitor getDrawerVisitor() {
+ return drawerVisitor;
+ }
+
+ /**
+ * Compute the underlying {@link org.scilab.modules.graphic_objects.axes.Axes} for the given point in figure coordinates.
+ * @param point given point in figure coordinates.
+ * @return the underlying {@link org.scilab.modules.graphic_objects.axes.Axes} for the given point in figure coordinates.
+ */
+ protected Axes getUnderlyingAxes(Point point) {
+ Axes underlyingAxes = null;
+ Dimension size = drawerVisitor.getCanvas().getDimension();
+ double x = point.getX() / size.getWidth();
+ double y = point.getY() / size.getHeight();
+ for (Integer childId : drawerVisitor.getFigure().getChildren()) {
+ GraphicObject child = GraphicController.getController().getObjectFromId(childId);
+ if (child instanceof Axes) {
+ if (child.getVisible()) {
+ Double[] axesBounds = ((Axes) child).getAxesBounds(); // x y w h
+ if ((x >= axesBounds[0]) && (x <= axesBounds[0] + axesBounds[2]) && (y >= axesBounds[1]) && (y <= axesBounds[1] + axesBounds[3])) {
+ underlyingAxes = (Axes) child;
+ return underlyingAxes;
+ }
+ }
+ }
+ }
+ return underlyingAxes;
+ }
+
+ /**
+ * Enable status getter.
+ * @return the enable status.
+ */
+ public boolean isEnable() {
+ return isEnable;
+ }
+
+ /**
+ * Enable status setter.
+ * @param isEnable the new enable status setter.
+ */
+ public void setEnable(boolean isEnable) {
+ if (this.isEnable != isEnable) {
+ this.isEnable = isEnable;
+ changeEnable(isEnable);
+ }
+ }
+
+ /**
+ * Called when the enable status have changed.
+ * @param isEnable the new enable status.
+ */
+ protected abstract void changeEnable(boolean isEnable);
+
+ /**
+ * Tight given bounds to axes data bounds.
+ * @param axes the given axes.
+ * @param zoomBounds the zoomBounds.
+ * @return true if actually there is a zoom.
+ */
+ protected boolean tightZoomBounds(Axes axes, Double[] zoomBounds) {
+ boolean zoomed = false;
+ Double[] dataBounds = new Double[] { -1., 1., -1., 1., -1., 1.};
+ for (int i : new int[] {0, 2, 4}) {
+ if (zoomBounds[i] < dataBounds[i]) {
+ zoomBounds[i] = dataBounds[i];
+ } else {
+ zoomed = true;
+ }
+ }
+
+ for (int i : new int[] {1, 3, 5}) {
+ if (zoomBounds[i] > dataBounds[i]) {
+ zoomBounds[i] = dataBounds[i];
+ } else {
+ zoomed = true;
+ }
+ }
+
+ return zoomed;
+ }
+
+ /**
+ * bound the given point to canvas.
+ * @param point the given point.
+ * @return a point bounded in the canvas.
+ */
+ protected Point bound(Point point) {
+ Dimension dimension = getDrawerVisitor().getCanvas().getDimension();
+ return new Point(
+ Math.max(1, Math.min(point.x, dimension.width)),
+ Math.max(1, Math.min(point.y, dimension.height))
+ );
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/InteractionManager.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/InteractionManager.java
new file mode 100755
index 000000000..50bfe03dc
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/InteractionManager.java
@@ -0,0 +1,124 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction;
+
+import org.scilab.modules.commons.utils.BlockingResult;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+
+/**
+ * @author Pierre Lando
+ */
+public class InteractionManager implements RubberBoxListener {
+
+ /** The rubber box */
+ private RubberBox rubberBox;
+
+ /** The drag, zoom, rotate interaction manager */
+ private final DragZoomRotateInteraction dragZoomRotateInteraction;
+
+ /** Parent drawer visitor */
+ private DrawerVisitor drawerVisitor;
+
+ /**
+ * Default constructor.
+ * @param drawerVisitor parent drawer visitor.
+ */
+ public InteractionManager(DrawerVisitor drawerVisitor) {
+ this.drawerVisitor = drawerVisitor;
+ dragZoomRotateInteraction = new DragZoomRotateInteraction(drawerVisitor);
+ dragZoomRotateInteraction.setEnable(true);
+ }
+
+ /**
+ * Finalize method.
+ * @exception Throwable the <code>Exception</code> raised by this method
+ */
+ public void finalize() throws Throwable {
+ if (rubberBox != null) {
+ rubberBox.removeListener(this);
+ }
+ super.finalize();
+ }
+
+ /**
+ * Called to start zooming.
+ */
+ public void startInteractiveZoom() {
+ final ZoomRubberBox rubberBox = new ZoomRubberBox(drawerVisitor);
+ dragZoomRotateInteraction.setEnable(false);
+
+ rubberBox.addListener(new RubberBoxListener() {
+ public void rubberBoxEnd() {
+ dragZoomRotateInteraction.setEnable(true);
+ drawerVisitor.removePostRendering(rubberBox);
+ }
+ });
+ drawerVisitor.addPostRendering(rubberBox);
+ rubberBox.setEnable(true);
+ }
+
+ public double[] startClickRubberBox(double initialRect[]) {
+ final BlockingResult<double []> result = new BlockingResult<double[]>();
+ final PointRubberBox rubberBox;
+ if (initialRect.length == 0) {
+ rubberBox = new TwoPointsRubberBox(drawerVisitor);
+ } else {
+ rubberBox = new OnePointRubberBox(drawerVisitor, initialRect);
+ }
+
+ dragZoomRotateInteraction.setEnable(false);
+ rubberBox.addListener(new RubberBoxListener() {
+ @Override
+ public void rubberBoxEnd() {
+ result.setResult(rubberBox.getResults());
+ dragZoomRotateInteraction.setEnable(true);
+ drawerVisitor.removePostRendering(rubberBox);
+ }
+ });
+ drawerVisitor.addPostRendering(rubberBox);
+ rubberBox.setEnable(true);
+ return result.getResult();
+ }
+
+ public double[] startDragRubberBox() {
+ final BlockingResult<double []> result = new BlockingResult<double []>();
+ final DragPointRubberBox rubberBox = new DragPointRubberBox(drawerVisitor);
+
+ dragZoomRotateInteraction.setEnable(false);
+ rubberBox.addListener(new RubberBoxListener() {
+ @Override
+ public void rubberBoxEnd() {
+ result.setResult(rubberBox.getResults());
+ dragZoomRotateInteraction.setEnable(true);
+ drawerVisitor.removePostRendering(rubberBox);
+ }
+ });
+ drawerVisitor.addPostRendering(rubberBox);
+ rubberBox.setEnable(true);
+ return result.getResult();
+ }
+
+ @Override
+ public void rubberBoxEnd() {
+ dragZoomRotateInteraction.setEnable(true);
+ rubberBox = null;
+ }
+
+ public boolean isInteractiveZoom() {
+ return !dragZoomRotateInteraction.isEnable();
+ }
+
+ public void setTranslationEnable(boolean b) {
+ dragZoomRotateInteraction.setTranslationEnable(b);
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/OnePointRubberBox.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/OnePointRubberBox.java
new file mode 100755
index 000000000..cc2d9c10f
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/OnePointRubberBox.java
@@ -0,0 +1,72 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction;
+
+import java.awt.Point;
+import java.awt.event.MouseEvent;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.interaction.util.PointAComputer;
+
+/**
+ * @author Bruno JOFRET
+ */
+public class OnePointRubberBox extends RubberBox implements PointRubberBox {
+
+ /**
+ * Default constructor.
+ *
+ * @param drawerVisitor parent drawer visitor.
+ */
+ public OnePointRubberBox(DrawerVisitor drawerVisitor) {
+ super(drawerVisitor);
+ }
+
+ public OnePointRubberBox(DrawerVisitor drawerVisitor, double initialRect[]) {
+ super(drawerVisitor);
+ double[][] factors = axes.getScaleTranslateFactors();
+ firstPoint = new Vector3d(initialRect[0] * factors[0][0] + factors[1][0],
+ initialRect[1] * factors[0][1] + factors[1][1],
+ 0);
+ secondPoint = firstPoint;
+ status = Status.WAIT_POINT_B;
+ setEnable(true);
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ mouseButton = e.getButton();
+ setPointB(e.getPoint());
+ process();
+ setEnable(false);
+ fireRubberBoxEnd();
+ }
+
+ /**
+ * Set the first point.
+ * @param point first point AWT coordinate.
+ * @return true if the first point is valid.
+ */
+ protected boolean setPointB(Point point) {
+ axes = getUnderlyingAxes(point);
+ if (axes != null) {
+ PointAComputer pointComputer = new PointAComputer(axes, point);
+ if (pointComputer.isValid()) {
+ pointBComputer = pointComputer;
+ secondPoint = pointComputer.getPosition();
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/PointRubberBox.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/PointRubberBox.java
new file mode 100755
index 000000000..803ffd997
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/PointRubberBox.java
@@ -0,0 +1,24 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction;
+
+import org.scilab.modules.renderer.JoGLView.postRendering.PostRendered;
+
+public interface PointRubberBox extends PostRendered {
+
+ public double[] getResults();
+
+ public void addListener(RubberBoxListener listener);
+
+ public void setEnable(boolean enabled);
+
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/RubberBox.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/RubberBox.java
new file mode 100755
index 000000000..d62bf4753
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/RubberBox.java
@@ -0,0 +1,539 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction;
+
+import java.awt.Component;
+import java.awt.Point;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.text.DecimalFormat;
+
+import javax.swing.event.EventListenerList;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.buffers.BuffersManager;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.axes.ruler.AxesRulerSpriteFactory;
+import org.scilab.modules.renderer.JoGLView.interaction.util.HelpersGeometry;
+import org.scilab.modules.renderer.JoGLView.interaction.util.PointAComputer;
+import org.scilab.modules.renderer.JoGLView.interaction.util.PointBComputer;
+import org.scilab.modules.renderer.JoGLView.interaction.util.PointCComputer;
+import org.scilab.modules.renderer.JoGLView.interaction.util.PointComputer;
+import org.scilab.modules.renderer.JoGLView.interaction.util.PointDComputer;
+import org.scilab.modules.renderer.JoGLView.postRendering.PostRendered;
+import org.scilab.modules.localization.Messages;
+
+/**
+ * @author Pierre Lando
+ */
+public class RubberBox extends FigureInteraction implements PostRendered, MouseListener, MouseMotionListener, KeyListener {
+
+ /** Decimal format used to show info messages */
+ private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.###E0");
+
+ static {
+ AxesRulerSpriteFactory.setScilabStyle(DECIMAL_FORMAT);
+ }
+
+ /** Axes name used to show info messages */
+ private static final String[] AXES_NAMES = new String[] {"X", "Y", "Z"};
+
+ /** The cube indices */
+ private static final int[] CUBE_INDICES = {
+ 0, 1, 3, 2, 4, 5, 7, 6,
+ 0, 3, 1, 2, 4, 7, 5, 6,
+ 0, 4, 1, 5, 3, 7, 2, 6
+ };
+
+ /** Rubber box status */
+ public static enum Status {
+ WAIT_POINT_A,
+ WAIT_POINT_B,
+ WAIT_POINT_C,
+ WAIT_POINT_D,
+ }
+
+ /** Rubber box color */
+ private static final Color RUBBER_BOX_COLOR = new Color(.2f, .3f, .4f);
+
+ /** Rubber box thickness */
+ private static final float RUBBER_BOX_THICKNESS = 2;
+
+ /** Rubber box pattern */
+ private static final short RUBBER_BOX_PATTERN = (short) 0xFAFA;
+
+ /** Helpers appearance */
+ private static Appearance helpersAppearance;
+
+ /** Rubber box cube appearance */
+ private static Appearance cubeAppearance;
+
+ /** The event listener list */
+ private final EventListenerList listenerList = new EventListenerList();
+
+ /** Helpers geometry */
+ private HelpersGeometry helpersGeometry;
+
+ /** Rubber box cube geometry */
+ private DefaultGeometry cubeGeometry;
+
+ /** Current status */
+ protected Status status;
+
+ protected Axes axes;
+
+ private PointComputer pointAComputer;
+ protected PointComputer pointBComputer;
+ private PointComputer pointCComputer;
+ private PointComputer pointDComputer;
+ protected Vector3d firstPoint;
+ protected Vector3d secondPoint;
+
+ protected int mouseButton;
+
+ /**
+ * Default constructor.
+ *
+ * @param drawerVisitor parent drawer visitor.
+ */
+ protected RubberBox(DrawerVisitor drawerVisitor) {
+ super(drawerVisitor);
+ axes = drawerVisitor.getAxes();
+ status = Status.WAIT_POINT_A;
+ }
+
+ /**
+ * Add a rubber box listener.
+ * The listener will be notified when a rubber box end.
+ * @param rubberBoxListener the new listener.
+ */
+ public final void addListener(RubberBoxListener rubberBoxListener) {
+ listenerList.add(RubberBoxListener.class, rubberBoxListener);
+ }
+
+ /**
+ * Remove a rubber box listener.
+ * The listener will no long be notified on events.
+ * @param rubberBoxListener the removed listener.
+ */
+ public final void removeListener(RubberBoxListener rubberBoxListener) {
+ listenerList.remove(RubberBoxListener.class, rubberBoxListener);
+ }
+
+ /**
+ * Notify all listener that the rubber box have ended
+ */
+ protected void fireRubberBoxEnd() {
+ for (RubberBoxListener rubberBoxListener : listenerList.getListeners(RubberBoxListener.class)) {
+ rubberBoxListener.rubberBoxEnd();
+ }
+ }
+
+ @Override
+ public final void draw(DrawingTools drawingTools) throws SciRendererException {
+ if (isEnable() && (axes != null)) {
+ drawingTools.getTransformationManager().useSceneCoordinate();
+ drawingTools.getTransformationManager().getModelViewStack().push(
+ getDrawerVisitor().getAxesDrawer().getSceneProjection(axes.getIdentifier())
+ );
+
+ if (status != Status.WAIT_POINT_A) {
+ drawingTools.draw(getCubeGeometry(drawingTools), getCubeAppearance());
+ }
+
+ if (secondPoint != null) {
+ drawingTools.draw(getHelpersGeometry(drawingTools), getHelpersAppearance());
+ }
+
+ drawingTools.getTransformationManager().getModelViewStack().pop();
+ }
+ }
+
+ @Override
+ public final void changeEnable(boolean isEnable) {
+ Component component = getDrawerVisitor().getComponent();
+ if (isEnable) {
+ //status = Status.WAIT_POINT_A;
+ pointAComputer = null;
+ component.addMouseListener(this);
+ component.addMouseMotionListener(this);
+ component.addKeyListener(this);
+ component.setFocusTraversalKeysEnabled(false);
+ component.setFocusable(true);
+ component.requestFocus();
+ } else {
+ component.removeMouseListener(this);
+ component.removeMouseMotionListener(this);
+ component.removeKeyListener(this);
+ }
+ updateInfoMessage();
+ getDrawerVisitor().getCanvas().redraw();
+ }
+
+ @Override
+ public final void keyTyped(KeyEvent e) {
+ if (e.getKeyChar() == KeyEvent.VK_ESCAPE) {
+ mouseButton = -1;
+ setEnable(false);
+ fireRubberBoxEnd();
+ }
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ mouseButton = e.getButton();
+ switch (status) {
+ case WAIT_POINT_A:
+ if (setPointA(e.getPoint())) {
+ status = Status.WAIT_POINT_B;
+ } else {
+ setEnable(false);
+ fireRubberBoxEnd();
+ }
+ break;
+ case WAIT_POINT_B:
+ setPointB(e.getPoint());
+ if (pointBComputer.is2D()) {
+ process();
+ setEnable(false);
+ fireRubberBoxEnd();
+ } else {
+ status = Status.WAIT_POINT_C;
+ }
+ break;
+ case WAIT_POINT_C:
+ setPointC(e.getPoint());
+ status = Status.WAIT_POINT_D;
+ break;
+ case WAIT_POINT_D:
+ setPointD(e.getPoint());
+ process();
+ setEnable(false);
+ fireRubberBoxEnd();
+ break;
+ default:
+ }
+ updateInfoMessage();
+
+
+ }
+
+ @Override
+ public final void mouseMoved(MouseEvent e) {
+ switch (status) {
+ case WAIT_POINT_A:
+ setPointA(e.getPoint());
+ getDrawerVisitor().getCanvas().redraw();
+ break;
+ case WAIT_POINT_B:
+ setPointB(e.getPoint());
+ getDrawerVisitor().getCanvas().redraw();
+ break;
+ case WAIT_POINT_C:
+ setPointC(e.getPoint());
+ getDrawerVisitor().getCanvas().redraw();
+ break;
+ case WAIT_POINT_D:
+ setPointD(e.getPoint());
+ getDrawerVisitor().getCanvas().redraw();
+ break;
+ default:
+ }
+ updateInfoMessage();
+ }
+
+ /**
+ * Update displayed info message.
+ */
+ protected void updateInfoMessage() {
+ if (isEnable()) {
+ switch (status) {
+ case WAIT_POINT_A:
+ setInfoMessage(Messages.gettext("Click to set first bounds"), pointAComputer, false);
+ break;
+ case WAIT_POINT_B:
+ setInfoMessage(Messages.gettext("Click to set second bounds"), pointBComputer, false);
+ break;
+ case WAIT_POINT_C:
+ setInfoMessage(Messages.gettext("Click to set first"), pointCComputer, true);
+ break;
+ case WAIT_POINT_D:
+ setInfoMessage(Messages.gettext("Click to set second"), pointDComputer, true);
+ break;
+ default:
+ }
+ } else {
+ GraphicController.getController().setProperty(
+ getDrawerVisitor().getFigure().getIdentifier(),
+ GraphicObjectProperties.__GO_INFO_MESSAGE__,
+ ""
+ );
+ }
+ }
+
+ /**
+ * Set the info message.
+ * @param baseMessage the base of the message.
+ * @param pointComputer current used point computer.
+ * @param oneAxis true if only one coordinate is currently set.
+ */
+ private void setInfoMessage(String baseMessage, PointComputer pointComputer, boolean oneAxis) {
+ if ((pointComputer != null) && (pointComputer.isValid())) {
+ String message = baseMessage + " ";
+ double[] data = pointComputer.getSecondPosition().getData();
+ double[][] factors = axes.getScaleTranslateFactors();
+ data[0] = (data[0] - factors[1][0]) / factors[0][0];
+ data[1] = (data[1] - factors[1][1]) / factors[0][1];
+ data[2] = (data[2] - factors[1][2]) / factors[0][2];
+
+ String comma;
+ if (oneAxis) {
+ comma = "";
+ } else {
+ comma = ", ";
+ }
+
+ for (int i = 0; i < PointComputer.AXIS_NUMBER; i++) {
+ if ((i != pointComputer.getFirstAxisIndex()) ^ oneAxis) {
+ message += AXES_NAMES[i] + " = " + DECIMAL_FORMAT.format(data[i]) + comma;
+ comma = "";
+ }
+ }
+ GraphicController.getController().setProperty(
+ getDrawerVisitor().getFigure().getIdentifier(),
+ GraphicObjectProperties.__GO_INFO_MESSAGE__,
+ message
+ );
+ } else {
+ String message = Messages.gettext("Move your mouse on an axes box.");
+ GraphicController.getController().setProperty(
+ getDrawerVisitor().getFigure().getIdentifier(),
+ GraphicObjectProperties.__GO_INFO_MESSAGE__,
+ message
+ );
+ }
+ }
+
+ /**
+ * Process action on RupperBox
+ * Do nothing by default
+ */
+ protected void process() {
+ // Do nothing
+ }
+
+ /**
+ * Set the first point.
+ * @param point first point AWT coordinate.
+ * @return true if the first point is valid.
+ */
+ protected boolean setPointA(Point point) {
+ axes = getUnderlyingAxes(point);
+ if (axes != null) {
+ PointAComputer pointComputer = new PointAComputer(axes, point);
+ if (pointComputer.isValid()) {
+ this.pointAComputer = pointComputer;
+ firstPoint = pointComputer.getPosition();
+ secondPoint = firstPoint;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Set second point in 3D zoom.
+ * @param point second point.
+ * @return true if the point is valid.
+ */
+ protected boolean setPointB(Point point) {
+ PointBComputer pointComputer = new PointBComputer(axes, pointAComputer, point);
+ if (pointComputer.isValid()) {
+ this.pointBComputer = pointComputer;
+ firstPoint = pointComputer.getFirstPosition();
+ secondPoint = pointComputer.getSecondPosition();
+ getDrawerVisitor().getCanvas().redraw();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Set zoom box position in 3D zoom.
+ * @param point mouse position.
+ * @return true if the point is valid.
+ */
+ protected boolean setPointC(Point point) {
+ PointCComputer pointComputer = new PointCComputer(axes, pointBComputer, point);
+ if (pointComputer.isValid()) {
+ this.pointCComputer = pointComputer;
+ firstPoint = pointComputer.getFirstPosition();
+ secondPoint = pointComputer.getSecondPosition();
+ getDrawerVisitor().getCanvas().redraw();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Set zoom box position in 3D zoom.
+ * @param point mouse position.
+ * @return true if the point is valid.
+ */
+ protected boolean setPointD(Point point) {
+ PointDComputer pointComputer = new PointDComputer(axes, pointCComputer, point);
+ if (pointComputer.isValid()) {
+ this.pointDComputer = pointComputer;
+ firstPoint = pointComputer.getFirstPosition();
+ secondPoint = pointComputer.getSecondPosition();
+ getDrawerVisitor().getCanvas().redraw();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Initialise or update the helpers geometry.
+ * @param drawingTools the drawing tools used to draw the helpers.
+ * @return updated helpers geometry.
+ */
+ private Geometry getHelpersGeometry(DrawingTools drawingTools) {
+ if (helpersGeometry == null) {
+ helpersGeometry = new HelpersGeometry(drawingTools);
+ }
+ helpersGeometry.updateVertex(axes, pointAComputer, secondPoint, status);
+ return helpersGeometry;
+ }
+
+ /**
+ * Helpers appearance getter.
+ * First initialise the helpers appearance.
+ * @return the helpers appearance.
+ */
+ public final Appearance getHelpersAppearance() {
+ if (helpersAppearance == null) {
+ helpersAppearance = new Appearance();
+ helpersAppearance.setLineColor(new Color(1, 0, 0));
+ helpersAppearance.setLineWidth(2);
+ }
+ return helpersAppearance;
+ }
+
+ /**
+ * Rubber box cube geometry getter.
+ * @param drawingTools the drawing tools.
+ * @return the rubber box cubeGeometry.
+ */
+ private Geometry getCubeGeometry(DrawingTools drawingTools) {
+ if (cubeGeometry == null) {
+ cubeGeometry = new DefaultGeometry();
+
+ BuffersManager bufferManager = drawingTools.getCanvas().getBuffersManager();
+ ElementsBuffer vertexBuffer = bufferManager.createElementsBuffer();
+ IndicesBuffer indicesBuffer = bufferManager.createIndicesBuffer();
+ indicesBuffer.setData(CUBE_INDICES);
+
+ cubeGeometry.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ cubeGeometry.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ cubeGeometry.setVertices(vertexBuffer);
+ cubeGeometry.setWireIndices(indicesBuffer);
+ }
+
+ cubeGeometry.getVertices().setData(new float[] {
+ (float) firstPoint.getX(), (float) firstPoint.getY(), (float) firstPoint.getZ(), 1,
+ (float) firstPoint.getX(), (float) firstPoint.getY(), (float) secondPoint.getZ(), 1,
+ (float) firstPoint.getX(), (float) secondPoint.getY(), (float) secondPoint.getZ(), 1,
+ (float) firstPoint.getX(), (float) secondPoint.getY(), (float) firstPoint.getZ(), 1,
+ (float) secondPoint.getX(), (float) firstPoint.getY(), (float) firstPoint.getZ(), 1,
+ (float) secondPoint.getX(), (float) firstPoint.getY(), (float) secondPoint.getZ(), 1,
+ (float) secondPoint.getX(), (float) secondPoint.getY(), (float) secondPoint.getZ(), 1,
+ (float) secondPoint.getX(), (float) secondPoint.getY(), (float) firstPoint.getZ(), 1
+ }, 4);
+
+ return cubeGeometry;
+ }
+
+ /**
+ * Rubber-box cube appearance getter.
+ * @return the rubber-box cube appearance.
+ */
+ private Appearance getCubeAppearance() {
+ if (cubeAppearance == null) {
+ cubeAppearance = new Appearance();
+ cubeAppearance.setLineColor(RUBBER_BOX_COLOR);
+ cubeAppearance.setLineWidth(RUBBER_BOX_THICKNESS);
+ cubeAppearance.setLinePattern(RUBBER_BOX_PATTERN);
+ }
+ return cubeAppearance;
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseDragged(MouseEvent e) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ public double[] getResults() {
+ double[][] factors = axes.getScaleTranslateFactors();
+ double result[] = {
+ mouseButton - 1,
+ (Math.min(firstPoint.getX(), secondPoint.getX()) - factors[1][0]) / factors[0][0],
+ (Math.max(firstPoint.getY(), secondPoint.getY()) - factors[1][1]) / factors[0][1],
+ (Math.max(firstPoint.getZ(), secondPoint.getZ()) - factors[1][2]) / factors[0][2],
+ (Math.abs(firstPoint.getX() - secondPoint.getX())) / factors[0][0],
+ (Math.abs(firstPoint.getY() - secondPoint.getY())) / factors[0][1],
+ (Math.abs(firstPoint.getZ() - secondPoint.getZ())) / factors[0][2]
+ };
+
+ return result;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/RubberBoxListener.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/RubberBoxListener.java
new file mode 100755
index 000000000..915569282
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/RubberBoxListener.java
@@ -0,0 +1,25 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction;
+
+import java.util.EventListener;
+
+/**
+ * @author Pierre Lando
+ */
+public interface RubberBoxListener extends EventListener {
+
+ /**
+ * Notification for a rubber box end.
+ */
+ void rubberBoxEnd();
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/TwoPointsRubberBox.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/TwoPointsRubberBox.java
new file mode 100755
index 000000000..203146101
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/TwoPointsRubberBox.java
@@ -0,0 +1,30 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction;
+
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+
+/**
+ * @author Bruno JOFRET
+ */
+public class TwoPointsRubberBox extends RubberBox implements PointRubberBox {
+
+ /**
+ * Default constructor.
+ *
+ * @param drawerVisitor parent drawer visitor.
+ */
+ public TwoPointsRubberBox(DrawerVisitor drawerVisitor) {
+ super(drawerVisitor);
+ }
+
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/ZoomRubberBox.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/ZoomRubberBox.java
new file mode 100755
index 000000000..9a653cc5b
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/ZoomRubberBox.java
@@ -0,0 +1,109 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction;
+
+import java.awt.event.MouseEvent;
+
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
+
+/**
+ * @author Bruno JOFRET
+ */
+public class ZoomRubberBox extends RubberBox {
+
+ /**
+ * Default constructor.
+ *
+ * @param drawerVisitor parent drawer visitor.
+ */
+ public ZoomRubberBox(DrawerVisitor drawerVisitor) {
+ super(drawerVisitor);
+ }
+
+ @Override
+ public final void mouseClicked(MouseEvent e) {
+ mouseButton = e.getButton();
+ if (e.getButton() == MouseEvent.BUTTON1) {
+ switch (status) {
+ case WAIT_POINT_A:
+ if (setPointA(e.getPoint())) {
+ status = Status.WAIT_POINT_B;
+ } else {
+ setEnable(false);
+ fireRubberBoxEnd();
+ }
+ break;
+ case WAIT_POINT_B:
+ setPointB(e.getPoint());
+ if (pointBComputer.is2D()) {
+ process();
+ setEnable(false);
+ fireRubberBoxEnd();
+ } else {
+ status = Status.WAIT_POINT_C;
+ }
+ break;
+ case WAIT_POINT_C:
+ setPointC(e.getPoint());
+ status = Status.WAIT_POINT_D;
+ break;
+ case WAIT_POINT_D:
+ setPointD(e.getPoint());
+ process();
+ setEnable(false);
+ fireRubberBoxEnd();
+ break;
+ default:
+ }
+ updateInfoMessage();
+ }
+
+ if (e.getButton() == MouseEvent.BUTTON3) {
+ setEnable(false);
+ fireRubberBoxEnd();
+ }
+ }
+
+ /**
+ * Actually set the zoom box depending on current value of firstPoint and secondPoint.
+ */
+ @Override
+ protected void process() {
+ Double[] bounds = {
+ Math.min(firstPoint.getX(), secondPoint.getX()), Math.max(firstPoint.getX(), secondPoint.getX()),
+ Math.min(firstPoint.getY(), secondPoint.getY()), Math.max(firstPoint.getY(), secondPoint.getY()),
+ Math.min(firstPoint.getZ(), secondPoint.getZ()), Math.max(firstPoint.getZ(), secondPoint.getZ()),
+ };
+
+ if (bounds[0].compareTo(bounds[1]) != 0 && bounds[2].compareTo(bounds[3]) != 0 && bounds[4].compareTo(bounds[5]) != 0) {
+ Boolean zoomed = tightZoomBounds(axes, bounds);
+ double[][] factors = axes.getScaleTranslateFactors();
+ bounds[0] = (bounds[0] - factors[1][0]) / factors[0][0];
+ bounds[1] = (bounds[1] - factors[1][0]) / factors[0][0];
+ bounds[2] = (bounds[2] - factors[1][1]) / factors[0][1];
+ bounds[3] = (bounds[3] - factors[1][1]) / factors[0][1];
+ bounds[4] = (bounds[4] - factors[1][2]) / factors[0][2];
+ bounds[5] = (bounds[5] - factors[1][2]) / factors[0][2];
+
+ boolean[] logFlags = { axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
+ ScaleUtils.applyInverseLogScaleToBounds(bounds, logFlags);
+
+ GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_BOX__, bounds);
+ GraphicController.getController().setProperty(axes.getIdentifier(), GraphicObjectProperties.__GO_ZOOM_ENABLED__, zoomed);
+ getDrawerVisitor().getCanvas().redraw();
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/AbstractPointComputer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/AbstractPointComputer.java
new file mode 100755
index 000000000..8a283d39a
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/AbstractPointComputer.java
@@ -0,0 +1,131 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction.util;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.renderer.JoGLView.axes.AxesDrawer;
+
+import java.awt.Point;
+
+/**
+ * @author Pierre Lando
+ */
+public abstract class AbstractPointComputer implements PointComputer {
+
+ /** Closest projected point */
+ private final Vector3d min;
+
+ /** Far projected point */
+ private final Vector3d max;
+
+ /** Current Axes */
+ private final Axes axes;
+
+ /**
+ * Default constructor.
+ * @param axes current axes.
+ * @param point clicked point in AWT coordinate.
+ */
+ public AbstractPointComputer(Axes axes, Point point) {
+ this.axes = axes;
+ min = AxesDrawer.unProject(axes, new Vector3d(point.x, point.y, -1));
+ max = AxesDrawer.unProject(axes, new Vector3d(point.x, point.y, +1));
+ }
+
+ /**
+ * Axes getter.
+ * @return the current axes.
+ */
+ protected final Axes getAxes() {
+ return axes;
+ }
+
+ /**
+ * Compute lambda such that:
+ * lambda * min[axisIndex] + (1 - lambda) * max[axisIndex] = value.
+ * @param value given value.
+ * @param axisIndex given axisIndex.
+ * @return lambda.
+ */
+ protected final double computeLambda(double value, int axisIndex) {
+ double v1 = min.getData()[axisIndex];
+ double v2 = max.getData()[axisIndex];
+ return (value - v2) / (v1 - v2);
+ }
+
+ /**
+ * Compute v such that:
+ * v = lambda * min + (1 - lambda) * max
+ *
+ * With lambda such that:
+ * v[axisIndex] = value.
+ *
+ * It always true that v[axisIndex] = value.
+ * @param lambda given lambda.
+ * @param value given value.
+ * @param axisIndex given axisIndex.
+ * @return v.
+ */
+ protected final Vector3d computeCoordinate(double lambda, double value, int axisIndex) {
+ double[] data = min.times(lambda).plus(max.times(1 - lambda)).getData();
+ data[axisIndex] = value;
+ return new Vector3d(data);
+ }
+
+ /**
+ * Check that given coordinate vector feet axes bounds.
+ * @param v given vector.
+ * @return true if v feet in the bounds.
+ */
+ protected final boolean inBounds(Vector3d v) {
+ Double[] bounds = axes.getCorrectedBounds();
+ double[] data = v.getData();
+ for (int i = 0; i < AXIS_NUMBER; i++) {
+ if ((bounds[i * 2] > data[i]) || (bounds[i * 2 + 1] < data[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check if the given position feet axes bounds.
+ * @param position the given position.
+ * @return true if it feet.
+ */
+ protected final Vector3d clamp(Vector3d position) {
+ Double[] bounds = axes.getCorrectedBounds();
+ double[] data = position.getData();
+ for (int i = 0; i < AXIS_NUMBER; i++) {
+ if (data[i] < bounds[i * 2]) {
+ data[i] = bounds[i * 2];
+ } else if (data[i] > bounds[i * 2 + 1]) {
+ data[i] = bounds[i * 2 + 1];
+ }
+ }
+ return new Vector3d(data);
+ }
+
+ /**
+ * Compute the first vector with the i-th value set to the one from the second vector.
+ * @param v1 first vector.
+ * @param v2 second vector.
+ * @param i coordinate index.
+ * @return return the {@see clamp} value of computed vector.
+ */
+ protected final Vector3d setCoordinate(Vector3d v1, Vector3d v2, int i) {
+ double[] data = v1.getData();
+ data[i] = v2.getData()[i];
+ return clamp(new Vector3d(data));
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/CubeFacesPointComputer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/CubeFacesPointComputer.java
new file mode 100755
index 000000000..1d623623f
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/CubeFacesPointComputer.java
@@ -0,0 +1,81 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction.util;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+
+import java.awt.Point;
+
+/**
+ * @author Pierre Lando
+ */
+public abstract class CubeFacesPointComputer extends AbstractPointComputer {
+
+ /** Clicked position */
+ private final Vector3d position;
+
+ /** First axis index */
+ private final int axisIndex;
+
+ /**
+ * Constructor.
+ *
+ * @param axes box axes.
+ * @param point screen point.
+ */
+ public CubeFacesPointComputer(final Axes axes, final Point point) {
+ super(axes, point);
+ Double[] bounds = axes.getCorrectedBounds();
+
+ double maxLambda = -Double.MAX_VALUE;
+ Vector3d returnedValue = null;
+
+ int index = -1;
+
+ // axis represent X, Y and Z axis.
+ for (int axis = 0; axis < AXIS_NUMBER; axis++) {
+ for (int boundIndex = 0; boundIndex < 2; boundIndex++) {
+ double bound = bounds[axis * 2 + boundIndex];
+ double lambda = computeLambda(bound, axis);
+ if (lambda > maxLambda) {
+ Vector3d v = computeCoordinate(lambda, bound, axis);
+ if (inBounds(v)) {
+ maxLambda = lambda;
+ returnedValue = v;
+ index = axis;
+ }
+ }
+ }
+ }
+
+ this.axisIndex = index;
+
+ position = returnedValue;
+ }
+
+ /**
+ * Axis index getter.
+ * @return the current axis index.
+ */
+ protected final int getAxisIndex() {
+ return axisIndex;
+ }
+
+ /**
+ * Clicked position getter.
+ * @return the position.
+ */
+ public final Vector3d getPosition() {
+ return position;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/HelpersGeometry.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/HelpersGeometry.java
new file mode 100755
index 000000000..760f51165
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/HelpersGeometry.java
@@ -0,0 +1,112 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction.util;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.buffers.BuffersManager;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.renderer.JoGLView.interaction.RubberBox;
+
+import java.nio.FloatBuffer;
+
+/**
+ * @author Pierre Lando
+ */
+public class HelpersGeometry extends DefaultGeometry {
+
+ /** The helper size */
+ private static final double HELPERS_SIZE = .05;
+
+ /**
+ * There are:
+ * - 4 marks per axis.
+ * - 2 segments per marks.
+ * - 2 vertex per segments.
+ * - 4 coordinate per vertex.
+ */
+ private static final int VERTEX_BUFFER_SIZE = 64;
+
+ private final BuffersManager bufferManager;
+ private final ElementsBuffer vertexBuffer;
+
+ public HelpersGeometry(DrawingTools drawingTools) {
+ bufferManager = drawingTools.getCanvas().getBuffersManager();
+ vertexBuffer = bufferManager.createElementsBuffer();
+
+ setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ setVertices(vertexBuffer);
+ }
+
+ @Override
+ public void finalize() throws Throwable {
+ super.finalize();
+ bufferManager.dispose(vertexBuffer);
+ }
+
+ public void updateVertex(Axes axes, PointComputer pointAComputer, Vector3d secondPoint, RubberBox.Status status) {
+ if ((pointAComputer != null) && (pointAComputer.getFirstAxisIndex() != -1)) {
+ FloatBuffer data;
+ boolean oneAxis;
+ if ((status == RubberBox.Status.WAIT_POINT_A) || (status == RubberBox.Status.WAIT_POINT_B)) {
+ oneAxis = false;
+ data = FloatBuffer.allocate(VERTEX_BUFFER_SIZE * 2);
+ } else {
+ oneAxis = true;
+ data = FloatBuffer.allocate(VERTEX_BUFFER_SIZE);
+ }
+
+ Double[] bounds = axes.getCorrectedBounds();
+ int mainAxisIndex = (pointAComputer.getFirstAxisIndex() + 1) % 3;
+ for (int axisIndex = 0; axisIndex < 3; axisIndex++) {
+ if ((mainAxisIndex != axisIndex) ^ oneAxis) {
+ for (int u = 0; u < 2; u++) {
+ for (int v = 0; v < 2; v++) {
+ double base[] = secondPoint.getData();
+ base[axisIndex] = bounds[axisIndex * 2 + u];
+ int nextAxisIndex = (axisIndex + 1) % 3;
+ base[nextAxisIndex] = bounds[nextAxisIndex * 2 + v];
+ float[] buffer = asFloatArray(base);
+ data.put(buffer);
+
+ buffer[axisIndex] = buffer[axisIndex] + (float) (HELPERS_SIZE * (bounds[axisIndex * 2 + (1 - u)] - bounds[axisIndex * 2 + u]));
+ data.put(buffer);
+
+ buffer[axisIndex] = bounds[axisIndex * 2 + u].floatValue();
+ data.put(buffer);
+
+ buffer[nextAxisIndex] = buffer[nextAxisIndex] + (float) (HELPERS_SIZE * (bounds[nextAxisIndex * 2 + (1 - v)] - bounds[nextAxisIndex * 2 + v]));
+ data.put(buffer);
+ }
+ }
+ }
+ }
+
+ data.rewind();
+ getVertices().setData(data, 3);
+ } else {
+ getVertices().setData(new Float[0], 4);
+ }
+ }
+
+ private float[] asFloatArray(double[] base) {
+ float data[] = new float[base.length];
+ for (int i = 0; i < base.length; i++) {
+ data[i] = (float) base[i];
+ }
+ return data;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointAComputer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointAComputer.java
new file mode 100755
index 000000000..131792a2d
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointAComputer.java
@@ -0,0 +1,60 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction.util;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+
+import java.awt.Point;
+
+/**
+ * This class compute the coordinate of a point on the box surface.
+ * The point correspond to a mouse coordinate.
+ * @author Pierre Lando
+ */
+public class PointAComputer extends CubeFacesPointComputer implements PointComputer {
+
+ /**
+ * Constructor.
+ *
+ * @param axes box axes.
+ * @param point screen point.
+ */
+ public PointAComputer(final Axes axes, final Point point) {
+ super(axes, point);
+ }
+
+ @Override
+ public final boolean isValid() {
+ return getPosition() != null;
+ }
+
+ @Override
+ public final int getFirstAxisIndex() {
+ return getAxisIndex();
+ }
+
+ @Override
+ public final Vector3d getFirstPosition() {
+ return getPosition();
+ }
+
+ @Override
+ public final Vector3d getSecondPosition() {
+ return getPosition();
+ }
+
+ @Override
+ public boolean is2D() {
+ return false;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointBComputer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointBComputer.java
new file mode 100755
index 000000000..6d800b66c
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointBComputer.java
@@ -0,0 +1,122 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction.util;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+
+import java.awt.Point;
+
+/**
+ * @author Pierre Lando
+ */
+public class PointBComputer extends AbstractPointComputer implements PointComputer {
+
+ /** First axis index */
+ private final int firstAxisIndex;
+
+ private final boolean is2D;
+
+ private Vector3d firstPosition;
+ private Vector3d secondPosition;
+
+ /**
+ * Constructor.
+ *
+ * @param axes current Axes.
+ * @param pointAComputer the first point computer.
+ * @param point the clicked point in AWT coordinate.
+ */
+ public PointBComputer(Axes axes, PointComputer pointAComputer, Point point) {
+ super(axes, point);
+
+ firstAxisIndex = pointAComputer.getFirstAxisIndex();
+ if (firstAxisIndex != -1) {
+ double value = pointAComputer.getFirstPosition().getData()[firstAxisIndex];
+ double lambda = computeLambda(value, firstAxisIndex);
+ Vector3d coordinate = computeCoordinate(lambda, value, firstAxisIndex);
+
+ firstPosition = pointAComputer.getFirstPosition();
+ secondPosition = clamp(coordinate);
+
+ if (check2D()) {
+ double[] data = firstPosition.getData();
+ data[firstAxisIndex] = -Double.MAX_VALUE;
+ firstPosition = clamp(new Vector3d(data));
+
+ data = secondPosition.getData();
+ data[firstAxisIndex] = Double.MAX_VALUE;
+ secondPosition = clamp(new Vector3d(data));
+
+ is2D = true;
+ } else {
+ is2D = false;
+ }
+
+ } else {
+ is2D = false;
+ firstPosition = null;
+ secondPosition = null;
+ }
+ }
+
+ /**
+ * Check if the current axes disposition lead to a 2D zoom.
+ * @return true if the current axes disposition lead to a 2D zoom.
+ */
+ private boolean check2D() {
+ boolean r = true;
+ Double[] bounds = getAxes().getDataBounds();
+ float[] middle = new float[] {
+ (float) (bounds[0] + bounds[1]) / 2f,
+ (float) (bounds[2] + bounds[3]) / 2f,
+ (float) (bounds[4] + bounds[5]) / 2f
+ };
+
+ for (int i = 0; i < AXIS_NUMBER; i++) {
+ if (i != firstAxisIndex) {
+ double lambda = computeLambda(middle[i], i);
+ r &= !((lambda >= 0) && (lambda <= 1));
+ }
+ }
+
+ return r;
+ }
+
+ @Override
+ public final boolean isValid() {
+ return secondPosition != null;
+ }
+
+ /**
+ * 2D status getter.
+ * @return true if the zoom is in 2D mode.
+ */
+ public final boolean is2D() {
+ return is2D;
+ }
+
+ @Override
+ public final int getFirstAxisIndex() {
+ return firstAxisIndex;
+ }
+
+ @Override
+ public final Vector3d getFirstPosition() {
+ return firstPosition;
+ }
+
+ @Override
+ public final Vector3d getSecondPosition() {
+ return secondPosition;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointCComputer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointCComputer.java
new file mode 100755
index 000000000..c3b66ddcc
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointCComputer.java
@@ -0,0 +1,72 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction.util;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+
+import java.awt.Point;
+
+/**
+ * @author Pierre Lando
+ */
+public class PointCComputer extends CubeFacesPointComputer implements PointComputer {
+
+ private final Vector3d secondPosition;
+ private final Vector3d firstPosition;
+ private final int firstAxisIndex;
+
+
+ /**
+ * Constructor
+ *
+ * @param axes current axes.
+ * @param pointBComputer previous point computer.
+ * @param point clicked point in AWT coordinate.
+ */
+ public PointCComputer(Axes axes, PointComputer pointBComputer, Point point) {
+ super(axes, point);
+ firstAxisIndex = pointBComputer.getFirstAxisIndex();
+ if (getPosition() != null) {
+ firstPosition = setCoordinate(pointBComputer.getFirstPosition(), getPosition(), firstAxisIndex);
+ secondPosition = setCoordinate(pointBComputer.getSecondPosition(), getPosition(), firstAxisIndex);
+ } else {
+ firstPosition = null;
+ secondPosition = null;
+ }
+ }
+
+ @Override
+ public final boolean isValid() {
+ return secondPosition != null;
+ }
+
+ @Override
+ public final int getFirstAxisIndex() {
+ return firstAxisIndex;
+ }
+
+ @Override
+ public final Vector3d getFirstPosition() {
+ return firstPosition;
+ }
+
+ @Override
+ public final Vector3d getSecondPosition() {
+ return secondPosition;
+ }
+
+ @Override
+ public boolean is2D() {
+ return false;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointComputer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointComputer.java
new file mode 100755
index 000000000..02d608ec8
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointComputer.java
@@ -0,0 +1,53 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction.util;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * @author Pierre Lando
+ */
+public interface PointComputer {
+
+ /** The number of axis */
+ static final int AXIS_NUMBER = 3;
+
+ /**
+ * Validity getter.
+ * @return true if the clicked point is valid.
+ */
+ public abstract boolean isValid();
+
+ /**
+ * First position getter.
+ * @return the first position.
+ */
+ public abstract Vector3d getFirstPosition();
+
+ /**
+ * Second position getter.
+ * @return the second position.
+ */
+ public abstract Vector3d getSecondPosition();
+
+ /**
+ * First axis index getter.
+ * @return the first axis index.
+ */
+ public abstract int getFirstAxisIndex();
+
+ /**
+ * 2D status getter.
+ * @return true if the zoom is in 2D mode.
+ */
+ public boolean is2D();
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointDComputer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointDComputer.java
new file mode 100755
index 000000000..60b2bc91e
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/interaction/util/PointDComputer.java
@@ -0,0 +1,71 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.interaction.util;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+
+import java.awt.Point;
+
+/**
+ * @author Pierre Lando
+ */
+public class PointDComputer extends CubeFacesPointComputer implements PointComputer {
+
+ private final int firstAxisIndex;
+ private final Vector3d secondPosition;
+ private final Vector3d firstPosition;
+
+ /**
+ * Constructor
+ *
+ * @param axes current axes.
+ * @param pointCComputer previous point computer.
+ * @param point clicked point in AWT coordinate.
+ */
+ public PointDComputer(Axes axes, PointComputer pointCComputer, Point point) {
+ super(axes, point);
+ firstAxisIndex = pointCComputer.getFirstAxisIndex();
+ if (getPosition() != null) {
+ firstPosition = pointCComputer.getFirstPosition();
+ secondPosition = setCoordinate(pointCComputer.getSecondPosition(), getPosition(), firstAxisIndex);
+ } else {
+ firstPosition = null;
+ secondPosition = null;
+ }
+ }
+
+ @Override
+ public final boolean isValid() {
+ return secondPosition != null;
+ }
+
+ @Override
+ public final Vector3d getFirstPosition() {
+ return firstPosition;
+ }
+
+ @Override
+ public final Vector3d getSecondPosition() {
+ return secondPosition;
+ }
+
+ @Override
+ public final int getFirstAxisIndex() {
+ return firstAxisIndex;
+ }
+
+ @Override
+ public boolean is2D() {
+ return false;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/AxisLabelPositioner.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/AxisLabelPositioner.java
new file mode 100755
index 000000000..284747d4a
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/AxisLabelPositioner.java
@@ -0,0 +1,320 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2011 - DIGITEO - Manuel JULIACHS
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.label;
+
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * AxisLabelPositioner class.
+ *
+ * Computes the position of a Label in box coordinates [-1, +1]^3, as used
+ * when rulers are drawn {@see AxesDrawer}, where -1 and +1 respectively map
+ * to the corresponding axis' maximum and minimum bounds.
+ * All positions and vectors are specified in box coordinates, except
+ * the projected ticks direction.
+ * Position can be automatically computed or user-specified. In the former case,
+ * four parameters resulting from the axis ruler drawing algorithms are needed:
+ * the distance ratio and projected ticks direction, which are computed by the Ruler
+ * drawer (used by AxesRulerDrawer), and the label position and box coordinates
+ * ticks direction, obtained from the AxesRuler drawer {@see AxesRulerDrawer}.
+ * These parameters must be set before computing the label's position values.
+ * The rotation angle can also be determined automatically or user-specified
+ * and requires the same parameters (as well as for sprite anchor position correction).
+ *
+ * To do:
+ * -take into account logarithmic coordinates.
+ * -implement window-coordinates displacement computation.
+ * -optimize the anchor position computation methods.
+ *
+ * @author Manuel JULIACHS
+ */
+public class AxisLabelPositioner extends LabelPositioner {
+ /** The box coordinates ticks direction, as specified by the ruler model. */
+ private Vector3d ticksDirection;
+
+ /** The ratio between the maximum tick label sprite distance and the projected ticks direction norm. */
+ private double distRatio;
+
+ /** The normalized projected ticks direction. */
+ private Vector3d projectedTicksDirection;
+
+ /**
+ * The array of allowed anchor positions.
+ * It is used to determine the corrected anchor position as a function of the rotation angle.
+ * The uncorrected position (angle = 0) is obtained from the auto-positioning algorithm.
+ * Adding k*90 (respectively -k*90) degrees to its angle amounts to shifing by k elements to the right
+ * (respectively to the left) from its location in the array, modulo the array size.
+ */
+ private static final AnchorPosition[] allowedAnchorPositionsArray = {AnchorPosition.LEFT, AnchorPosition.DOWN,
+ AnchorPosition.RIGHT, AnchorPosition.UP
+ };
+
+ /** The list of allowed anchor positions. */
+ private static final ArrayList<AnchorPosition> allowedAnchorPositions = new ArrayList<AnchorPosition>(Arrays.asList(allowedAnchorPositionsArray));
+
+ /**
+ * Constructor.
+ */
+ public AxisLabelPositioner() {
+ super();
+ ticksDirection = new Vector3d(0.0, 0.0, 0.0);
+ distRatio = 0.0;
+ projectedTicksDirection = new Vector3d(0.0, 0.0, 0.0);
+ }
+
+ /**
+ * Sets the ticks direction in box coordinates.
+ * @param ticksDirection the ticks direction to set.
+ */
+ public void setTicksDirection(Vector3d ticksDirection) {
+ this.ticksDirection = new Vector3d(ticksDirection);
+ }
+
+ /**
+ * Returns the box coordinates ticks direction.
+ * @return the box coordinates ticks direction.
+ */
+ public Vector3d getTicksDirection() {
+ return ticksDirection;
+ }
+
+ /**
+ * Sets the maximum sprite distance to projected ticks norm ratio.
+ * @param distanceRatio the distance ratio to set.
+ */
+ public void setDistanceRatio(double distanceRatio) {
+ this.distRatio = distanceRatio;
+ }
+
+ /**
+ * Returns the maximum sprite distance to projected ticks norm ratio.
+ * @return the distance ratio.
+ */
+ public double getDistanceRatio() {
+ return distRatio;
+ }
+
+ /**
+ * Sets the normalized projected ticks direction.
+ * @param projectedTicksDirection the projected ticks direction to set.
+ */
+ public void setProjectedTicksDirection(Vector3d projectedTicksDirection) {
+ this.projectedTicksDirection = new Vector3d(projectedTicksDirection);
+ }
+
+ /**
+ * Returns the normalized projected ticks direction.
+ * @return the projected ticks direction.
+ */
+ public Vector3d getProjectedTicksDirection() {
+ return projectedTicksDirection;
+ }
+
+ /**
+ * Determines and returns the rotation angle (in degrees) from the window coordinate system's axis
+ * (+Y, -Y, +X, -X) most closely aligned with the projected ticks direction to the projected ticks direction itself.
+ * (the most closely aligned axis is the one such that the angle between the two is minimal). Positive angles
+ * are measured clockwise.
+ * @return the angle from the most closely aligned axis to the projected ticks direction.
+ */
+ private double computeTicksDirectionAngle() {
+ double sign;
+
+ Vector3d axis;
+
+ double signX = Math.signum(projectedTicksDirection.getX());
+ double signY = Math.signum(projectedTicksDirection.getY());
+
+ if (projectedTicksDirection.getY() > Math.abs(projectedTicksDirection.getX())) {
+ /* Nearest: +Y */
+ axis = new Vector3d(0.0, 1.0, 0.0);
+ sign = signX;
+
+ } else if (projectedTicksDirection.getY() < -Math.abs(projectedTicksDirection.getX())) {
+ /* Nearest: -Y */
+ axis = new Vector3d(0.0, -1.0, 0.0);
+ sign = -signX;
+
+ } else if (projectedTicksDirection.getX() > 0.0) {
+ /* Nearest: +X */
+ axis = new Vector3d(1.0, 0.0, 0.0);
+ sign = -signY;
+
+ } else {
+ /* Nearest: -X */
+ axis = new Vector3d(-1.0, 0.0, 0.0);
+ sign = signY;
+ }
+
+ double dp = axis.scalar(projectedTicksDirection);
+ double angle = Math.acos(dp) * 180.0 / Math.PI;
+
+ angle *= sign;
+
+ return angle;
+ }
+
+ /**
+ * Computes and returns the position of the label's anchor point,
+ * obtained by adding the displacement vector to its position.
+ * It additionally sets the displacement vector member.
+ * @return the position of the label's anchor point.
+ */
+ protected Vector3d computeDisplacedPosition() {
+ Vector3d position = new Vector3d(labelPosition);
+
+ /* Compute the label displacement and set it */
+ labelDisplacement = ticksDirection.times(distRatio);
+ position = position.plus(labelDisplacement);
+
+ return position;
+ }
+
+ /**
+ * Returns the automatically computed rotation angle.
+ * Set to 0 as a default.
+ * @return the rotation angle.
+ */
+ protected double getAutoRotationAngle() {
+ return 0.0;
+ }
+
+ /**
+ * Returns the automatically computed sprite anchor position.
+ * The anchor position is first determined from the projected ticks direction and
+ * then corrected depending on the label's rotation angle.
+ * To do so, a signed offset is computed (number of quadrants swept by the angle)
+ * and added to the uncorrected position (read from the array of allowed values)
+ * to obtain the corrected one.
+ * The orientation of the label's axis is taken into account by subtracting the angle between
+ * the closest window coordinate axis and the ticks direction from the rotation angle.
+ * The resulting angle therefore amounts to the angle from the ticks direction to
+ * the vector going from the anchor point to (and orthogonal to) the opposite side of the label box.
+ * The anchor position remains constant when the corrected angle lies in the initial quadrant
+ * centered about the ticks direction (from -45 to 45 degrees relative to it),
+ *
+ * The result is such that the anchor-to-opposite side vector always points away from
+ * the interior of the Axes box. This avoids overlapping between the label's box and its axis
+ * when the rotation angle is such that the label box's width vector is parallel or orthogonal
+ * to the axis.
+ *
+ * @return the sprite anchor position.
+ */
+ protected AnchorPosition getAutoAnchorPosition() {
+ AnchorPosition anchorPosition = getUncorrectedAutoAnchorPosition();
+
+ double tmpRotationAngle;
+
+ /* Get the angle from the closest window coordinate axis to the ticks direction. */
+ double ticksDirectionAngle = computeTicksDirectionAngle();
+
+ tmpRotationAngle = rotationAngle % 360.0;
+
+ /*
+ * Subtract the closest axis to ticks direction angle from the rotation angle
+ * to take into account the associated axis' orientation.
+ */
+ tmpRotationAngle -= ticksDirectionAngle;
+
+ int anchorIndex = 0;
+
+ anchorIndex = allowedAnchorPositions.indexOf(anchorPosition);
+
+ /*
+ * The offset is the number of quadrants swept by the rotation angle.
+ * The inital quadrant is -45/+45 degrees about the reference vector
+ * (ticks direction) and amounts to 0.
+ */
+ int offset = (int) ((Math.abs(tmpRotationAngle) + 45.0) / 90.0);
+
+ if (tmpRotationAngle < 0.0) {
+ offset = -offset;
+ }
+
+ /* Cycle through the allowed anchor positions. */
+ anchorIndex = (anchorIndex + offset) % 4;
+
+ if (anchorIndex < 0) {
+ anchorIndex = 4 + anchorIndex;
+ }
+
+ anchorPosition = allowedAnchorPositions.get(anchorIndex);
+
+ return anchorPosition;
+ }
+
+ /**
+ * Returns the automatically computed sprite anchor position corresponding to the projected ticks direction.
+ * It is determined independently of the rotation angle.
+ * @return the sprite anchor position.
+ */
+ private AnchorPosition getUncorrectedAutoAnchorPosition() {
+ if (projectedTicksDirection.getY() > Math.abs(projectedTicksDirection.getX())) {
+ return AnchorPosition.DOWN;
+ } else if (projectedTicksDirection.getY() < -Math.abs(projectedTicksDirection.getX())) {
+ return AnchorPosition.UP;
+ } else if (projectedTicksDirection.getX() > 0.0) {
+ return AnchorPosition.LEFT;
+ } else {
+ return AnchorPosition.RIGHT;
+ }
+ }
+
+ /**
+ * Returns the automatically computed sprite anchor position corresponding to the projected ticks direction.
+ * It uses all the different sprite anchor position values, compared to the 4 used by getAutoAnchorPosition.
+ * However the actual result is less visually pleasing as jumps from one position to the other are
+ * more frequent. To be further tested.
+ * @return the sprite anchor position.
+ */
+ private AnchorPosition getAutoAnchorPosition2() {
+ if (projectedTicksDirection.getY() > 0.0) {
+ if (projectedTicksDirection.getY() > Math.sin(3.0 * Math.PI / 8.0)) {
+ return AnchorPosition.DOWN;
+ } else if (projectedTicksDirection.getY() > Math.sin(Math.PI / 8.0)) {
+ if (projectedTicksDirection.getX() > 0.0) {
+ return AnchorPosition.LOWER_LEFT;
+ } else {
+ return AnchorPosition.LOWER_RIGHT;
+ }
+ } else {
+ if (projectedTicksDirection.getX() > 0.0) {
+ return AnchorPosition.LEFT;
+ } else {
+ return AnchorPosition.RIGHT;
+ }
+ }
+ } else {
+ if (projectedTicksDirection.getY() < -Math.sin(3.0 * Math.PI / 8.0)) {
+ return AnchorPosition.UP;
+ } else if (projectedTicksDirection.getY() < -Math.sin(Math.PI / 8.0)) {
+ if (projectedTicksDirection.getX() > 0.0) {
+ return AnchorPosition.UPPER_LEFT;
+ } else {
+ return AnchorPosition.UPPER_RIGHT;
+ }
+ } else {
+ if (projectedTicksDirection.getX() > 0.0) {
+ return AnchorPosition.LEFT;
+ } else {
+ return AnchorPosition.RIGHT;
+ }
+ }
+ }
+ }
+
+}
+
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelManager.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelManager.java
new file mode 100755
index 000000000..c2af483ba
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelManager.java
@@ -0,0 +1,411 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ * Copyright (C) 2011-2012 - DIGITEO - Manuel Juliachs
+ * Copyright (C) 2013 - Scilab Enterprises - Calixte DENIZET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.label;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.axes.Camera;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.label.Label;
+import org.scilab.modules.graphic_objects.utils.Utils;
+import org.scilab.modules.renderer.JoGLView.axes.AxesDrawer;
+import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
+
+import java.awt.Dimension;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_AUTO_POSITION__;
+import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_AUTO_ROTATION__;
+import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_FONT_ANGLE__;
+import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_POSITION__;
+
+/**
+ *
+ * This class performs the drawing of scilab's Label entity.
+ *
+ * TODO, manage: {font_fractional}
+ *
+ * @author Manuel Juliachs
+ */
+public class LabelManager {
+
+ /**
+ * The {@see Map} of existing {@see Sprite}.
+ */
+ private final Map<Integer, Texture> textureMap = new ConcurrentHashMap<Integer, Texture>();
+
+ /**
+ * The used sprite manager.
+ */
+ private final TextureManager textureManager;
+
+ /**
+ * Default constructor.
+ * @param textureManager the texture manager.
+ */
+ public LabelManager(TextureManager textureManager) {
+ this.textureManager = textureManager;
+ }
+
+ public Dimension[] getLabelsSize(ColorMap colorMap, Axes axes, AxesDrawer drawer) {
+ final Label xl = (Label) GraphicController.getController().getObjectFromId(axes.getXAxisLabel());
+ final Label yl = (Label) GraphicController.getController().getObjectFromId(axes.getYAxisLabel());
+ final Label tl = (Label) GraphicController.getController().getObjectFromId(axes.getTitle());
+ final Dimension[] dims = new Dimension[3];
+ final Label[] labels = new Label[] {xl, yl, tl};
+ final LabelPositioner[] positioners = new LabelPositioner[] {drawer.getXAxisLabelPositioner(axes), drawer.getYAxisLabelPositioner(axes), drawer.getTitlePositioner(axes) };
+ for (int i = 0; i < 3; i++) {
+ if (labels[i] != null && !labels[i].isEmpty() && labels[i].getAutoPosition() && labels[i].getAutoRotation()) {
+ final Texture texture = getTexture(colorMap, labels[i]);
+ dims[i] = texture.getDataProvider().getTextureSize();
+ final double a = positioners[i].getAutoRotationAngle();
+ if (a == 90 || a == 270) {
+ final int t = dims[i].width;
+ dims[i].width = dims[i].height;
+ dims[i].height = t;
+ }
+ } else {
+ dims[i] = new Dimension();
+ }
+ }
+
+ return dims;
+ }
+
+ public Dimension getXLabelSize(ColorMap colorMap, Axes axes, AxesDrawer drawer) {
+ final Label xl = (Label) GraphicController.getController().getObjectFromId(axes.getXAxisLabel());
+ if (xl != null && !xl.isEmpty()) {
+ final Texture texture = getTexture(colorMap, xl);
+ return texture.getDataProvider().getTextureSize();
+ }
+
+ return new Dimension();
+ }
+
+ /**
+ * Draws the given {@see Label} with the given {@see DrawingTools}.
+ * @param drawingTools the given {@see DrawingTools}.
+ * @param colorMap the current {@see ColorMap}.
+ * @param label the given Scilab {@see Label}.
+ * @param axesDrawer the Axes drawer used to draw the label's parent Axes.
+ * @throws SciRendererException if the label is not drawable.
+ */
+ public void draw(final DrawingTools drawingTools, final ColorMap colorMap, final Label label, AxesDrawer axesDrawer) throws SciRendererException {
+ /* Only the z-axis Label may not be drawn depending on the view mode */
+ boolean drawnFlag = true;
+ Integer parentId;
+ Integer labelId = label.getIdentifier();
+ LabelPositioner labelPositioner;
+
+ parentId = label.getParentAxes();
+
+ if (parentId == null) {
+ return;
+ }
+
+ Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentId);
+
+ /* Get the positioner associated to the label */
+ if (parentAxes.getXAxisLabel().equals(label.getIdentifier())) {
+ labelPositioner = axesDrawer.getXAxisLabelPositioner(parentAxes);
+ } else if (parentAxes.getYAxisLabel().equals(label.getIdentifier())) {
+ labelPositioner = axesDrawer.getYAxisLabelPositioner(parentAxes);
+ } else if (parentAxes.getZAxisLabel().equals(label.getIdentifier())) {
+ labelPositioner = axesDrawer.getZAxisLabelPositioner(parentAxes);
+ drawnFlag = (parentAxes.getViewAsEnum() == Camera.ViewType.VIEW_3D);
+ } else if (parentAxes.getTitle().equals(label.getIdentifier())) {
+ labelPositioner = axesDrawer.getTitlePositioner(parentAxes);
+ } else {
+ /* Do not do anything */
+ return;
+ }
+
+ /*
+ * The topmost transformation, which is the data transformation, must be popped before drawing
+ * and restored afterwards because Labels, like Axes rulers, are drawn in box coordinates.
+ */
+ drawingTools.getTransformationManager().getModelViewStack().pop();
+
+ positionAndDraw(drawingTools, colorMap, label, labelPositioner, parentAxes, axesDrawer, drawnFlag);
+
+ drawingTools.getTransformationManager().getModelViewStack().pushRightMultiply(axesDrawer.getDataTransformation());
+ }
+
+ /**
+ * Positions and draws the given Scilab {@see Label} with the given {@see DrawingTools}.
+ * First, it initializes the label positioner's remaining parameters which have not been previously
+ * obtained from the axis ruler drawer. It then asks the positioner the relevant values and
+ * finally draws the label's sprite using these resulting values.
+ * @param drawingTools the given {@see DrawingTools}.
+ * @param colorMap the current {@see ColorMap}.
+ * @param label the given Scilab {@see Label}.
+ * @param labelPositioner the positioner used to compute the label's position.
+ * @param parentAxes the label's parent Axes.
+ * @param axesDrawer the Axes drawer used to draw the label's parent Axes.
+ * @param drawnFlag a flag indicating whether the label must be drawn or not.
+ * @throws SciRendererException if the label is not drawable.
+ */
+ public final void positionAndDraw(final DrawingTools drawingTools, final ColorMap colorMap, final Label label, LabelPositioner labelPositioner, Axes parentAxes, AxesDrawer axesDrawer, boolean drawnFlag) throws SciRendererException {
+ boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
+ Texture labelSprite = getTexture(colorMap, label);
+
+ labelPositioner.setLabelTexture(labelSprite);
+ labelPositioner.setDrawingTools(drawingTools);
+ labelPositioner.setParentAxes(parentAxes);
+ labelPositioner.setAutoPosition(label.getAutoPosition());
+ labelPositioner.setAutoRotation(label.getAutoRotation());
+ labelPositioner.setUserRotationAngle(180.0 * label.getFontAngle() / Math.PI);
+
+ double[][] factors = parentAxes.getScaleTranslateFactors();
+ /* Un scale/translate the label position to be drawn */
+ Vector3d labelUserPosition = computeUnscaledAxesCoords(new Vector3d(label.getPosition()), factors);
+
+ /* Logarithmic scaling must be applied to the label's user position to obtain object coordinates */
+ labelUserPosition = ScaleUtils.applyLogScale(labelUserPosition, logFlags);
+
+ labelUserPosition = axesDrawer.getBoxCoordinates(labelUserPosition);
+ labelPositioner.setLabelUserPosition(labelUserPosition);
+
+ /* Computes the label's position values */
+ labelPositioner.positionLabel();
+
+ Vector3d labelPos = labelPositioner.getAnchorPoint();
+ AnchorPosition labelAnchor = labelPositioner.getAnchorPosition();
+
+ /* Set the lower-left corner position if auto-positioned */
+ if (label.getAutoPosition()) {
+ Vector3d cornerPos = labelPositioner.getLowerLeftCornerPosition();
+ Vector3d objectCornerPos = axesDrawer.getObjectCoordinates(cornerPos);
+ /* Apply inverse scaling to obtain user coordinates */
+ objectCornerPos = ScaleUtils.applyInverseLogScale(objectCornerPos, logFlags);
+
+ objectCornerPos = computeScaledAxesCoords(objectCornerPos, factors);
+ label.setPosition(new Double[] {objectCornerPos.getX(), objectCornerPos.getY(), objectCornerPos.getZ()});
+
+ /*
+ * Must be reset to true as setPosition modifies the label's auto position field.
+ * To be modified.
+ */
+ label.setAutoPosition(true);
+ }
+
+ /* Compute and set the label's corners */
+ Transformation projection = axesDrawer.getProjection();
+ Vector3d[] projCorners = labelPositioner.getProjCorners();
+ Vector3d[] corners = computeCorners(projection, projCorners, parentAxes);
+ Double[] coordinates = cornersToCoordinateArray(corners);
+
+ /* Set the computed coordinates */
+ label.setCorners(coordinates);
+
+ double rotationAngle = 0.0;
+
+ if (label.getAutoRotation()) {
+ rotationAngle = labelPositioner.getRotationAngle();
+ label.setFontAngle(Math.PI * rotationAngle / 180.0);
+
+ /*
+ * Must be reset to true as setFontAngle modifies the label's auto rotation field.
+ * To be modified.
+ */
+ label.setAutoRotation(true);
+ } else {
+ rotationAngle = labelPositioner.getUserRotationAngle();
+ }
+
+ /* The label's rotation direction convention is opposite to the standard one. */
+ rotationAngle = -rotationAngle;
+
+ if (label.getVisible() && drawnFlag) {
+ if (Utils.isValid(labelPos.getX(), labelPos.getY(), labelPos.getZ()) && Utils.isValid(rotationAngle)) {
+ if (labelPositioner.getUseWindowCoordinates()) {
+ /* Draw in window coordinates */
+ Transformation canvasProjection = drawingTools.getTransformationManager().getCanvasProjection();
+ Vector3d projLabelPos = canvasProjection.project(labelPos);
+ projLabelPos = new Vector3d(Math.round(projLabelPos.getX()), Math.round(projLabelPos.getY()), Math.round(projLabelPos.getZ()));
+ drawingTools.getTransformationManager().useWindowCoordinate();
+ drawingTools.draw(labelSprite, labelAnchor, projLabelPos, rotationAngle);
+ drawingTools.getTransformationManager().useSceneCoordinate();
+ } else {
+ /* Draw using box coordinates */
+ drawingTools.draw(labelSprite, labelAnchor, labelPos, rotationAngle);
+ }
+ }
+ }
+ }
+
+ /**
+ * Computes the given scaled/translated coordinate for the given vector and factors
+ * Used to keep the Label position and Corners in Axes coordinates
+ * @param unscaled The un scaled/translated vector
+ * @param factors The Axes factors
+ * @return The new Coordinates
+ */
+ private Vector3d computeScaledAxesCoords(Vector3d unscaled, double[][] factors) {
+
+ double[] coord = unscaled.getData();
+ coord[0] = (coord[0] - factors[1][0]) / factors[0][0];
+ coord[1] = (coord[1] - factors[1][1]) / factors[0][1];
+ coord[2] = (coord[2] - factors[1][2]) / factors[0][2];
+
+ return new Vector3d(coord);
+ }
+
+ /**
+ * Computes the given un scaled/translated coordinate for the given vector and factors
+ * Used to draw the Label in the correct position
+ * @param scaled The scaled/translated vector
+ * @param factors The Axes factors
+ * @return The new Coordinates
+ */
+ private Vector3d computeUnscaledAxesCoords(Vector3d scaled, double[][] factors) {
+
+ double[] coord = scaled.getData();
+ coord[0] = coord[0] * factors[0][0] + factors[1][0];
+ coord[1] = coord[1] * factors[0][1] + factors[1][1];
+ coord[2] = coord[2] * factors[0][2] + factors[1][2];
+
+ return new Vector3d(coord);
+ }
+ /**
+ * Computes and returns the corners (in user coordinates) of a label's bounding box.
+ * @param projection the projection from object coordinates to window coordinates.
+ * @param projCorners the corners of the label's bounding box in window coordinates (4-element array).
+ * @param parentAxes the Axes for which the coordinates are computed.
+ * @return the corners of the label's bounding box in user coordinates (4-element array).
+ */
+ private Vector3d[] computeCorners(Transformation projection, Vector3d[] projCorners, Axes parentAxes) {
+ Vector3d[] corners = new Vector3d[4];
+ boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
+
+ double[][] factors = parentAxes.getScaleTranslateFactors();
+ corners[0] = projection.unproject(projCorners[0]);
+ corners[1] = projection.unproject(projCorners[1]);
+ corners[2] = projection.unproject(projCorners[2]);
+ corners[3] = projection.unproject(projCorners[3]);
+
+ /* Apply inverse logarithmic scaling in order to obtain user coordinates */
+ corners[0] = ScaleUtils.applyInverseLogScale(corners[0], logFlags);
+ corners[1] = ScaleUtils.applyInverseLogScale(corners[1], logFlags);
+ corners[2] = ScaleUtils.applyInverseLogScale(corners[2], logFlags);
+ corners[3] = ScaleUtils.applyInverseLogScale(corners[3], logFlags);
+
+ /* Used to keep corners in axes scaled/translated coordinates */
+ corners[0] = computeScaledAxesCoords(corners[0], factors);
+ corners[1] = computeScaledAxesCoords(corners[1], factors);
+ corners[2] = computeScaledAxesCoords(corners[2], factors);
+ corners[3] = computeScaledAxesCoords(corners[3], factors);
+
+ return corners;
+ }
+
+ /**
+ * Returns the positions of a bounding box's corners as an array of (x,y,z) coordinate triplets.
+ * The output corners are reordered to match their order in the {@see Label} object's
+ * equivalent array, respectively: lower-left, lower-right, upper-left, upper-right in the input array,
+ * starting from the lower-left and going in clockwise order in the returned array.
+ * @param corners of the bounding box (4-element array).
+ * @return the corners' coordinates (12-element array).
+ */
+ private Double[] cornersToCoordinateArray(Vector3d[] corners) {
+ Double[] coordinates = new Double[12];
+ coordinates[0] = corners[0].getX();
+ coordinates[1] = corners[0].getY();
+ coordinates[2] = corners[0].getZ();
+
+ coordinates[3] = corners[2].getX();
+ coordinates[4] = corners[2].getY();
+ coordinates[5] = corners[2].getZ();
+
+ coordinates[6] = corners[3].getX();
+ coordinates[7] = corners[3].getY();
+ coordinates[8] = corners[3].getZ();
+
+ coordinates[9] = corners[1].getX();
+ coordinates[10] = corners[1].getY();
+ coordinates[11] = corners[1].getZ();
+
+ return coordinates;
+ }
+
+ /**
+ * Updates the sprite data if needed.
+ * @param id the modified object.
+ * @param property the changed property.
+ */
+ public void update(Integer id, int property) {
+ if (!(__GO_POSITION__ == property) && !(__GO_AUTO_POSITION__ == property)
+ && !(__GO_FONT_ANGLE__ == property) && !(__GO_AUTO_ROTATION__ == property)) {
+ dispose(id);
+ }
+ }
+
+ /**
+ * Returns the SciRenderer {@see Sprite} corresponding to the given Scilab {@see Label}.
+ * @param colorMap the current color map.
+ * @param label the given Scilab {@see Label}.
+ * @return the SciRenderer {@see Sprite} corresponding to the given Scilab {@see Label}.
+ */
+ public Texture getTexture(final ColorMap colorMap, final Label label) {
+ Texture texture = textureMap.get(label.getIdentifier());
+ if (texture == null) {
+ texture = createSprite(colorMap, label);
+ textureMap.put(label.getIdentifier(), texture);
+ }
+ return texture;
+ }
+
+ /**
+ * Creates a sprite for the given label.
+ * @param colorMap the current colormap.
+ * @param label the given label.
+ * @return a new sprite for the given label.
+ */
+ private Texture createSprite(final ColorMap colorMap, final Label label) {
+ LabelSpriteDrawer spriteDrawer = new LabelSpriteDrawer(colorMap, label);
+ Texture sprite = textureManager.createTexture();
+ sprite.setMagnificationFilter(Texture.Filter.LINEAR);
+ sprite.setMinifyingFilter(Texture.Filter.LINEAR);
+ sprite.setDrawer(spriteDrawer);
+ return sprite;
+ }
+
+ /**
+ * Disposes the texture corresponding to the given id.
+ * @param id the given id.
+ */
+ public void dispose(Integer id) {
+ Texture texture = textureMap.get(id);
+ if (texture != null) {
+ textureManager.dispose(texture);
+ textureMap.remove(id);
+ }
+ }
+
+ /**
+ * Disposes all the label text sprites.
+ */
+ public void disposeAll() {
+ textureManager.dispose(textureMap.values());
+ textureMap.clear();
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelPositioner.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelPositioner.java
new file mode 100755
index 000000000..61ce19bb7
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelPositioner.java
@@ -0,0 +1,502 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2011-2012 - DIGITEO - Manuel JULIACHS
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.label;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.tranformations.DegenerateMatrixException;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+
+import java.awt.Dimension;
+
+/**
+ * LabelPositioner class
+ *
+ * Computes the position of a Label in box coordinates [-1, +1]^3, as used
+ * when rulers are drawn {@see AxesDrawer}, where -1 and +1 respectively map
+ * to the corresponding axis' maximum and minimum bounds.
+ * As it is an abstract class, there are two derived classes implementing
+ * positioning for respectively axis-associated labels and title labels
+ * (respectively {@see AxisLabelPositioner} and {@see TitlePositioner}).
+ * All positions and vectors are specified in box coordinates, unless stated otherwise.
+ * The position and rotation angle can be both automatically computed or user-specified.
+ *
+ * To do:
+ * -take into account logarithmic coordinates.
+ * -implement window-coordinates displacement computation.
+ * -optimize the lower-left corner computation methods.
+ *
+ * @author Manuel JULIACHS
+ */
+public abstract class LabelPositioner {
+ /** Specifies whether the label is automatically positioned or not. */
+ protected boolean autoPosition;
+
+ /** Specifies whether the label is automatically rotated or not. */
+ protected boolean autoRotation;
+
+ /**
+ * The label's position, which is its anchor point's undisplaced position.
+ * For axis-associated labels, it is located on the associated axis,
+ * whereas for title labels, it is the point whose projection
+ * is on the middle of the Axes box's projection's top segment (in 2D view mode).
+ * Relevant only to automatic positioning.
+ */
+ protected Vector3d labelPosition;
+
+ /** The label's user-specified position. */
+ protected Vector3d labelUserPosition;
+
+ /**
+ * The label's rotation angle (degrees).
+ * This is the angle from the window coordinate system's +X axis to
+ * the label's half-width vector. Positive values are measured clockwise
+ * (opposite to the standard convention).
+ */
+ protected double rotationAngle;
+
+ /**
+ * The label's user-specified rotation angle (degrees). Positive values are
+ * measured clockwise (see rotationAngle).
+ */
+ protected double userRotationAngle;
+
+ /** The label displacement vector from its position to its anchor point. */
+ protected Vector3d labelDisplacement;
+
+ /** The label's anchor point position. */
+ protected Vector3d anchorPoint;
+
+ /** The label's sprite anchor position. */
+ protected AnchorPosition anchorPosition;
+
+ /** The label's associated sprite. */
+ protected Texture labelTexture;
+
+ /** The current drawing tools. */
+ protected DrawingTools drawingTools;
+
+ /** The label's current parent Axes. */
+ protected Axes parentAxes;
+
+ /**
+ * A flag specifying whether drawing is done using box coordinates (false)
+ * or window coordinates (true).
+ */
+ protected boolean useWindowCoordinates;
+
+ /** The label's anchor point position in window coordinates. */
+ protected Vector3d projAnchorPoint;
+
+ /** The label's half-width vector in window coordinates. */
+ protected Vector3d projHalfWidth;
+
+ /** The label's half-height vector in window coordinates. */
+ protected Vector3d projHalfHeight;
+
+ /**
+ * The positions of the corners of the label's bounding box in window coordinates,
+ * stored in the following order: lower-left, lower-right, upper-left, upper-right.
+ */
+ protected Vector3d[] projCornerCoordinates;
+
+ /**
+ * Constructor.
+ */
+ public LabelPositioner() {
+ autoPosition = false;
+ autoRotation = false;
+ labelPosition = new Vector3d(0.0, 0.0, 0.0);
+ labelUserPosition = new Vector3d(0.0, 0.0, 0.0);
+ rotationAngle = 0.0;
+ userRotationAngle = 0.0;
+ labelDisplacement = new Vector3d(0.0, 0.0, 0.0);
+ anchorPoint = new Vector3d(0.0, 0.0, 0.0);
+ anchorPosition = AnchorPosition.LOWER_LEFT;
+ labelTexture = null;
+ drawingTools = null;
+ parentAxes = null;
+ /* Labels are drawn in box coordinates as a default. */
+ useWindowCoordinates = false;
+ projAnchorPoint = new Vector3d(0.0, 0.0, 0.0);
+ projHalfWidth = new Vector3d(0.0, 0.0, 0.0);
+ projHalfHeight = new Vector3d(0.0, 0.0, 0.0);
+ projCornerCoordinates = new Vector3d[4];
+ }
+
+ /**
+ * Sets the label's auto position flag.
+ * @param autoPosition the autoPosition to set.
+ */
+ public void setAutoPosition(boolean autoPosition) {
+ this.autoPosition = autoPosition;
+ }
+
+ /**
+ * Returns the label's auto position flag.
+ * @return autoPosition the autoPosition to set.
+ */
+ public boolean getAutoPosition() {
+ return autoPosition;
+ }
+
+ /**
+ * Sets the label's auto rotation flag.
+ * @param autoRotation the autoRotation to set.
+ */
+ public void setAutoRotation(boolean autoRotation) {
+ this.autoRotation = autoRotation;
+ }
+
+ /**
+ * Returns the label's auto rotation flag.
+ * @return autoRotation the autoRotation to set.
+ */
+ public boolean getAutoRotation() {
+ return autoRotation;
+ }
+
+ /**
+ * Sets the label's position.
+ * @param labelPosition the position to set.
+ */
+ public void setLabelPosition(Vector3d labelPosition) {
+ this.labelPosition = new Vector3d(labelPosition);
+ }
+
+ /**
+ * Returns the label's position.
+ * @return the label position.
+ */
+ public Vector3d getLabelPosition() {
+ return labelPosition;
+ }
+
+ /**
+ * Sets the label's user position.
+ * @param labelUserPosition the user position to set.
+ */
+ public void setLabelUserPosition(Vector3d labelUserPosition) {
+ this.labelUserPosition = new Vector3d(labelUserPosition);
+ }
+
+ /**
+ * Returns the label's user position.
+ * @return the label user position.
+ */
+ public Vector3d
+ getLabelUserPosition() {
+ return labelUserPosition;
+ }
+
+ /**
+ * Sets the label's rotation angle.
+ * @param rotationAngle the rotation angle to set.
+ */
+ public void setRotationAngle(double rotationAngle) {
+ this.rotationAngle = rotationAngle;
+ }
+
+ /**
+ * Returns the label's rotation angle.
+ * @return the rotation angle.
+ */
+ public double getRotationAngle() {
+ return rotationAngle;
+ }
+
+ /**
+ * Sets the label's user rotation angle.
+ * @param userRotationAngle the user rotation angle to set.
+ */
+ public void setUserRotationAngle(double userRotationAngle) {
+ this.userRotationAngle = userRotationAngle;
+ }
+
+ /**
+ * Returns the label's user rotation angle.
+ * @return the user rotation angle.
+ */
+ public double getUserRotationAngle() {
+ return userRotationAngle;
+ }
+
+ /**
+ * Sets the label displacement.
+ * @param labelDisplacement the label displacement to set.
+ */
+ public void setLabelDisplacement(Vector3d labelDisplacement) {
+ this.labelDisplacement = new Vector3d(labelDisplacement);
+ }
+
+ /**
+ * Returns the label displacement.
+ * @return the label displacement.
+ */
+ public Vector3d getLabelDisplacement() {
+ return labelDisplacement;
+ }
+
+ /**
+ * Returns the position of the label's anchor point.
+ * @return the anchor point's position.
+ */
+ public Vector3d getAnchorPoint() {
+ return anchorPoint;
+ }
+
+ /**
+ * Returns the label's sprite anchor position.
+ * @return the labe's sprite anchor position.
+ */
+ public AnchorPosition getAnchorPosition() {
+ return anchorPosition;
+ }
+
+ /**
+ * Sets the label's associated texture.
+ * @param labelTexture the texture to set.
+ */
+ public void setLabelTexture(Texture labelTexture) {
+ this.labelTexture = labelTexture;
+ }
+
+ /**
+ * Sets the current drawing tools.
+ * @param drawingTools the drawing tools to set.
+ */
+ public void setDrawingTools(DrawingTools drawingTools) {
+ this.drawingTools = drawingTools;
+ }
+
+ /**
+ * Sets the current parent Axes.
+ * @param parentAxes the parent Axes to set.
+ */
+ public void setParentAxes(Axes parentAxes) {
+ this.parentAxes = parentAxes;
+ }
+
+ /**
+ * Returns the flag specifying whether drawing occurs in window coordinates or not.
+ * @return the window coordinates flag.
+ */
+ public boolean getUseWindowCoordinates() {
+ return useWindowCoordinates;
+ }
+
+ /**
+ * Computes the label's anchor point and sprite anchor position
+ * and sets the corresponding members to the results.
+ */
+ public void positionLabel() {
+ computeAnchorPoint();
+ computeRotationAngle();
+
+ /* Depends on the rotation angle and must therefore be computed afterwards. */
+ computeAnchorPosition();
+
+ /* Computes the label's bounding box's corners (in window coordinates) */
+ computeCorners();
+ }
+
+ /**
+ * Computes the position of the label's anchor point depending on the
+ * automatic position mode and sets the anchorPoint member to the result.
+ * If positioning is not automatic, the position is set to the user-specified one.
+ */
+ private void computeAnchorPoint() {
+ if (autoPosition) {
+ anchorPoint = computeDisplacedPosition();
+ } else {
+ anchorPoint = labelUserPosition;
+ }
+ }
+
+ /**
+ * Computes and returns the position of the label's anchor point,
+ * obtained by adding the displacement vector to its position.
+ * It additionally sets the displacement vector member.
+ * @return the position of the label's anchor point.
+ */
+ protected Vector3d computeDisplacedPosition() {
+ Vector3d position = new Vector3d(labelPosition);
+
+ /* Compute and set a zero displacement */
+ labelDisplacement = new Vector3d(0.0, 0.0, 0.0);
+
+ return position;
+ }
+
+ /**
+ * Computes and sets the label's rotation angle depending on
+ * the automatic rotation mode. If it is not automatic, the angle
+ * is set to the user-specified one.
+ */
+ private void computeRotationAngle() {
+ if (autoRotation) {
+ setRotationAngle(getAutoRotationAngle());
+ } else {
+ setRotationAngle(userRotationAngle);
+ }
+ }
+
+ /**
+ * Returns the automatically computed rotation angle.
+ * Set to 0 as a default.
+ * @return the rotation angle.
+ */
+ protected double getAutoRotationAngle() {
+ return 0.0;
+ }
+
+ /**
+ * Returns the automatically computed sprite anchor position.
+ * @return the sprite anchor position.
+ */
+ protected AnchorPosition getAutoAnchorPosition() {
+ return AnchorPosition.LEFT;
+ }
+
+ /**
+ * Computes the label's sprite anchor position depending on the automatic position mode
+ * and sets the anchorPosition member to the result.
+ */
+ private void computeAnchorPosition() {
+ if (autoPosition) {
+ anchorPosition = getAutoAnchorPosition();
+ } else {
+ anchorPosition = AnchorPosition.LOWER_LEFT;
+ }
+ }
+
+ /**
+ * Computes and returns the position of the label's lower-left corner either in box or window coordinates
+ * from the label's position and half-width/-height vectors (also specified either in box or window coordinates).
+ * The label's anchor point and anchor position must have been determined beforehand.
+ * @param anchorPoint the position of the label's anchor point.
+ * @param halfWidth the displacement vector corresponding to half the label's width.
+ * @param halfHeight the displacement vector corresponding to half the label's height.
+ * @return the position of the label's lower-left corner.
+ */
+ private Vector3d computeLowerLeftCornerPosition(Vector3d anchorPoint, Vector3d halfWidth, Vector3d halfHeight) {
+ Vector3d returnedPosition = new Vector3d(anchorPoint);
+
+ if (anchorPosition == AnchorPosition.LEFT) {
+ returnedPosition = returnedPosition.minus(halfHeight);
+ } else if (anchorPosition == AnchorPosition.RIGHT) {
+ returnedPosition = returnedPosition.minus(halfWidth.times(2.0));
+ returnedPosition = returnedPosition.minus(halfHeight);
+ } else if (anchorPosition == AnchorPosition.UP) {
+ returnedPosition = returnedPosition.minus(halfWidth);
+ returnedPosition = returnedPosition.minus(halfHeight.times(2.0));
+ } else if (anchorPosition == AnchorPosition.DOWN) {
+ returnedPosition = returnedPosition.minus(halfWidth);
+ } else if (anchorPosition == AnchorPosition.UPPER_LEFT) {
+ returnedPosition = returnedPosition.minus(halfHeight.times(2.0));
+ } else if (anchorPosition == AnchorPosition.UPPER_RIGHT) {
+ returnedPosition = returnedPosition.minus(halfWidth.times(2.0));
+ returnedPosition = returnedPosition.minus(halfHeight.times(2.0));
+ } else if (anchorPosition == AnchorPosition.LOWER_LEFT) {
+ // Do nothing: in this case, the positions of the anchor point and the lower-left corner are equal.
+ } else if (anchorPosition == AnchorPosition.LOWER_RIGHT) {
+ returnedPosition = returnedPosition.minus(halfWidth.times(2.0));
+ }
+
+ return returnedPosition;
+ }
+
+ /**
+ * Computes and returns the position of the label's lower-left corner in box coordinates.
+ * It projects the label's anchor point to compute the points located from it at
+ * respectively half the sprite width and half its height, using the previously computed
+ * projected anchor point, half-width and half-height vectors, finally computing the half-vectors
+ * in box coordinates to obtain the lower-left corner's position.
+ * The label's anchor point and anchor position, rotation angle, associated sprite, and drawing tools
+ * must have been initialized beforehand.
+ * @return the label's lower-left corner position.
+ */
+ public Vector3d getLowerLeftCornerPosition() {
+ Transformation canvasProjection = drawingTools.getTransformationManager().getCanvasProjection();
+ Vector3d labelPoint = new Vector3d(anchorPoint);
+ Vector3d projLabelPoint = new Vector3d(projAnchorPoint);
+
+ Vector3d projRightPoint = projLabelPoint.plus(projHalfWidth);
+ Vector3d unprojRightPoint = canvasProjection.unproject(projRightPoint);
+
+ Vector3d halfWidth = unprojRightPoint.minus(labelPoint);
+
+ Vector3d projUpperPoint = projLabelPoint.plus(projHalfHeight);
+ Vector3d unprojUpperPoint = canvasProjection.unproject(projUpperPoint);
+
+ Vector3d halfHeight = unprojUpperPoint.minus(labelPoint);
+
+ Vector3d cornerPosition = computeLowerLeftCornerPosition(labelPoint, halfWidth, halfHeight);
+
+ return cornerPosition;
+ }
+
+ /**
+ * Computes the corners of the label's bounding box, in window coordinates.
+ * The label's point, rotation angle and anchor position must have been determined beforehand.
+ * It also computes the anchor point, half-width and half-height vectors in window coordinates.
+ */
+ private void computeCorners() {
+ Transformation canvasProjection = drawingTools.getTransformationManager().getCanvasProjection();
+ Vector3d labelPoint = new Vector3d(anchorPoint);
+
+ /*
+ * Ought to be -rotationAngle as positive angle values are measured clockwise for labels.
+ * Apparently uses the same convention as the labels (clockwise positive directions).
+ * To be verified.
+ */
+ Transformation winRotation;
+ try {
+ winRotation = TransformationFactory.getRotationTransformation(rotationAngle, 0.0, 0.0, 1.0);
+ } catch (DegenerateMatrixException e) {
+ // Should never happen, as long as the rotation axes is (0, 0, 1) and not zero.
+ winRotation = TransformationFactory.getIdentity();
+ }
+
+ Dimension textureSize = labelTexture.getDataProvider().getTextureSize();
+ projHalfWidth = new Vector3d(0.5 * textureSize.getWidth(), 0.0, 0.0);
+ projHalfHeight = new Vector3d(0.0, 0.5 * textureSize.getHeight(), 0.0);
+
+ projHalfWidth = winRotation.projectDirection(projHalfWidth);
+ projHalfHeight = winRotation.projectDirection(projHalfHeight);
+
+ projAnchorPoint = canvasProjection.project(labelPoint);
+
+ /* Compute the corners of the label's bounding box in window coordinates */
+ Vector3d projCornerPosition = computeLowerLeftCornerPosition(projAnchorPoint, projHalfWidth, projHalfHeight);
+
+ projCornerCoordinates[0] = new Vector3d(projCornerPosition);
+ projCornerCoordinates[1] = projCornerPosition.plus(projHalfWidth.times(2.0));
+ projCornerCoordinates[2] = projCornerPosition.plus(projHalfHeight.times(2.0));
+ projCornerCoordinates[3] = projCornerCoordinates[2].plus(projHalfWidth.times(2.0));
+ }
+
+ /**
+ * Returns the positions of the label's corners (in window coordinates).
+ * The returned corners are in the following order: lower-left, lower-right,
+ * upper-left and upper-right.
+ * @return the corners' window coordinates (4-element array).
+ */
+ public Vector3d[] getProjCorners() {
+ return projCornerCoordinates;
+ }
+}
+
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelSpriteDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelSpriteDrawer.java
new file mode 100755
index 000000000..4df9d23eb
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/LabelSpriteDrawer.java
@@ -0,0 +1,76 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ * Copyright (C) 2011 - DIGITEO - Manuel Juliachs
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.label;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.texture.TextureDrawer;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.label.Label;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+import org.scilab.modules.renderer.JoGLView.util.TextObjectSpriteDrawer;
+
+/**
+ * A {@see SpriteDrawer} which draws a Scilab {@see Label} object.
+ * To do:
+ * -take into account the font angle property
+ * -refactoring
+ * @author Pierre Lando
+ */
+public class LabelSpriteDrawer extends TextObjectSpriteDrawer implements TextureDrawer {
+
+ /**
+ * Default constructor.
+ * @param colorMap the color map to use.
+ * @param label the scilab {@see Label} to draw.
+ */
+ public LabelSpriteDrawer(final ColorMap colorMap, final Label label) {
+ super(colorMap, label);
+ /* Alignment factor set to left */
+ setAlignmentFactor(0.0f);
+
+ Appearance appearance = computeAppearance(colorMap, label);
+ setAppearance(appearance);
+ setThickness((int) Math.ceil(appearance.getLineWidth()));
+ }
+
+ /**
+ * Compute and return an {@see Appearance} adapted to the given scilab label.
+ * @param colorMap the current scilab color map.
+ * @param label the given label.
+ * @return an appearance adapted to the given scilab label.
+ */
+ private Appearance computeAppearance(final ColorMap colorMap, final Label label) {
+ Appearance a = new Appearance();
+
+ if (label.getFillMode()) {
+ Color fillColor = ColorFactory.createColor(colorMap, label.getBackground());
+ a.setFillColor(fillColor);
+ } else {
+ a.setFillColor(new Color(0, 0, 0, 0));
+ }
+
+ /* Fill mode must be set to on */
+ if (label.getLineMode() && label.getFillMode()) {
+ Color lineColor = ColorFactory.createColor(colorMap, label.getLineColor());
+ a.setLineColor(lineColor);
+ a.setLineWidth(1);
+ } else {
+ a.setLineWidth(0);
+ }
+
+ return a;
+ }
+
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/TitlePositioner.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/TitlePositioner.java
new file mode 100755
index 000000000..ebdfc9de7
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/TitlePositioner.java
@@ -0,0 +1,136 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2011 - DIGITEO - Manuel JULIACHS
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.label;
+
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.AxisProperty;
+
+/**
+ * TitlePositioner class.
+ *
+ * Computes the position of a Label in box coordinates [-1, +1]^3, as used
+ * when rulers are drawn {@see AxesDrawer}, where -1 and +1 respectively map
+ * to the corresponding axis' maximum and minimum bounds.
+ * Automatic positioning uses the middle of the Axes box's projection's top segment
+ * as a reference point. In order to keep the Title label fixed when the viewpoint changes,
+ * its position is first computed in window coordinates (viewpoint-independent), using
+ * the reference point, and is then unprojected to obtain the anchor point's position
+ * in box coordinates (depends on the viewpoint).
+ *
+ * To do:
+ * -take into account label text angle and automatic rotation.
+ * -take into account logarithmic coordinates.
+ * -implement window-coordinates displacement computation.
+ *
+ * @author Manuel JULIACHS
+ */
+public class TitlePositioner extends LabelPositioner {
+ /**
+ * The offset in window coordinates from the top of the Axes box
+ * to the Title label's anchor point. Relevant only to
+ * automatic positioning.
+ */
+ public static final double TITLEOFFSET = 8.0;
+
+ /**
+ * The minimum z value in window coordinates.
+ * In accordance with how window coordinates are usually defined, this should be 0,
+ * however Scirenderer uses respectively -1 and +1 as the minimum and maximum z values
+ * instead of 0 and 1. To be modified if deemed necessary.
+ */
+ private static final double ZNEAR = -1.0;
+
+ /** The ratio between the maximum tick label sprite distance and the projected ticks direction norm. */
+ private double distRatio;
+ private int xlabelHeight;
+
+ /**
+ * Constructor.
+ */
+ public TitlePositioner() {
+ super();
+ /* Title labels are drawn in window coordinates to avoid jittering. */
+ useWindowCoordinates = true;
+ }
+
+ /**
+ * Sets the maximum sprite distance to projected ticks norm ratio.
+ * @param distanceRatio the distance ratio to set.
+ */
+ public void setDistanceRatio(double distanceRatio) {
+ this.distRatio = distanceRatio;
+ }
+
+ public void setXLabelHeight(int height) {
+ this.xlabelHeight = height;
+ }
+
+ /**
+ * Computes and returns the position of the label's anchor point,
+ * obtained by adding the displacement vector to its position.
+ * It additionally sets the displacement vector and label position members.
+ * @return the position of the label's anchor point.
+ */
+ protected Vector3d computeDisplacedPosition() {
+ Transformation canvasProjection = drawingTools.getTransformationManager().getCanvasProjection();
+
+ Double[] axesBounds = {0.0, 0.0, 0.0, 0.0};
+ Double[] margins = {0.0, 0.0, 0.0, 0.0};
+ boolean onTop = false;
+ if (parentAxes != null) {
+ axesBounds = parentAxes.getAxesBounds();
+ margins = parentAxes.getMargins();
+ AxisProperty.AxisLocation xloc = parentAxes.getXAxis().getAxisLocation();
+ if (xloc == AxisProperty.AxisLocation.TOP) {
+ onTop = true;
+ }
+ }
+
+ /* Compute the anchor point's position in window coordinates */
+ double xmid = axesBounds[0] + axesBounds[2] * margins[0] + 0.5 * axesBounds[2] * (1.0 - margins[0] - margins[1]);
+ double ymid = 1.0 - axesBounds[1] - axesBounds[3] * margins[2];
+
+ Vector3d projAnchorPoint = new Vector3d(Math.floor((xmid) * (double) drawingTools.getCanvas().getWidth()),
+ Math.floor((ymid) * (double) drawingTools.getCanvas().getHeight()),
+ ZNEAR);
+
+ Vector3d unprojAnchorPoint = new Vector3d(projAnchorPoint);
+ unprojAnchorPoint = canvasProjection.unproject(unprojAnchorPoint);
+ int h = 0;
+
+ if (onTop) {
+ h = (int) ((1 - margins[2] - margins[3]) * distRatio / 2 * axesBounds[3] * drawingTools.getCanvas().getHeight()) + xlabelHeight;
+ }
+
+ /* The anchor point is displaced along the y-axis by TITLEOFFSET pixels. */
+ projAnchorPoint = projAnchorPoint.setY(projAnchorPoint.getY() + TITLEOFFSET + h);
+
+ Vector3d unprojDispAnchorPoint = canvasProjection.unproject(projAnchorPoint);
+ Vector3d position = new Vector3d(unprojDispAnchorPoint);
+
+ /* Compute and set the LabelPositioner-inherited members */
+ labelPosition = new Vector3d(unprojAnchorPoint);
+ labelDisplacement = unprojDispAnchorPoint.minus(unprojAnchorPoint);
+
+ return position;
+ }
+
+ /**
+ * Returns the automatically computed sprite anchor position.
+ * @return the sprite anchor position.
+ */
+ protected AnchorPosition getAutoAnchorPosition() {
+ return AnchorPosition.DOWN;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/YAxisLabelPositioner.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/YAxisLabelPositioner.java
new file mode 100755
index 000000000..c866ca5f5
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/label/YAxisLabelPositioner.java
@@ -0,0 +1,47 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2011 - DIGITEO - Manuel JULIACHS
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.label;
+
+import org.scilab.modules.graphic_objects.axes.Camera;
+
+/**
+ * YAxisLabelPositioner class.
+ *
+ * Implements automatic rotation specific to y-axis labels.
+ * Refer to the parent class {@see AxisLabelPositioner} for the full
+ * implementation of positioning.
+ *
+ * @author Manuel JULIACHS
+ */
+public class YAxisLabelPositioner extends AxisLabelPositioner {
+
+ /**
+ * Constructor.
+ */
+ public YAxisLabelPositioner() {
+ super();
+ }
+
+ /**
+ * Returns the automatically computed rotation angle.
+ * It is equal to 270 when the parent axes' view mode is set to 2D, 0
+ * in any other case.
+ * @return the rotation angle.
+ */
+ protected double getAutoRotationAngle() {
+ if (parentAxes != null && parentAxes.getViewAsEnum() == Camera.ViewType.VIEW_3D) {
+ return 0.0;
+ } else {
+ return 270.0;
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/legend/LegendDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/legend/LegendDrawer.java
new file mode 100755
index 000000000..6fda83d19
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/legend/LegendDrawer.java
@@ -0,0 +1,753 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2011-2012 - DIGITEO - Manuel JULIACHS
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.legend;
+
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.buffers.IndicesBuffer;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
+import org.scilab.forge.scirenderer.tranformations.TransformationStack;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.figure.Figure;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+import org.scilab.modules.graphic_objects.legend.Legend;
+import org.scilab.modules.graphic_objects.legend.Legend.LegendLocation;
+import org.scilab.modules.graphic_objects.polyline.Polyline;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.mark.MarkSpriteManager;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+
+import java.awt.Dimension;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * LegendDrawer class.
+ * Utility class used by DrawerVisitor to draw the Legend object.
+ *
+ * To do:
+ * - clean up the code
+ * - modify bounds depending on the location (for OUT_* values)
+ * - take into account the actual tick/label size (instead of an arbitrary value)
+ * - implement box clipping mode
+ * - use the GraphicController to update links / move the update code somewhere else
+ * in order to perform it when objects are deleted, add the Links property to the set of
+ * properties affecting the sprite's update.
+ *
+ * @author Manuel JULIACHS
+ */
+public class LegendDrawer {
+
+ /**
+ * Set of properties that affect the legend sprite
+ */
+ private static final Set<Integer> SPRITE_PROPERTIES = new HashSet<Integer>(Arrays.asList(
+ GraphicObjectProperties.__GO_FONT_SIZE__,
+ GraphicObjectProperties.__GO_FONT_COLOR__,
+ GraphicObjectProperties.__GO_FONT_STYLE__,
+ GraphicObjectProperties.__GO_FONT_FRACTIONAL__,
+ GraphicObjectProperties.__GO_TEXT_ARRAY_DIMENSIONS__,
+ GraphicObjectProperties.__GO_TEXT_STRINGS__
+ ));
+
+ /** The height of a bar relative to the height difference between two lines */
+ private static final float BAR_HEIGHT = 0.5f;
+
+ /** The DrawerVisitor used */
+ private final DrawerVisitor visitor;
+
+ /** The SpriteManager used */
+ private final TextureManager textureManager;
+
+ /** The MarkSpriteManager used */
+ private final MarkSpriteManager markManager;
+
+ /** The Legend sprite drawer */
+ private LegendSpriteDrawer legendSpriteDrawer;
+
+ /** The relative line width */
+ public static final double LINE_WIDTH = 0.1;
+
+ /** The relative y-offset */
+ public static final double Y_OFFSET = 0.01;
+
+ /** The relative tick and label size (arbitrarily chosen) */
+ private static final double TICK_LABEL_SIZE = 0.055;
+
+ /** The z-value corresponding to the frontmost position */
+ private static final float Z_FRONT = 0.99f;
+
+ /** The legend background's vertices */
+ private ElementsBuffer rectangleVertices;
+
+ /** The vertices used to draw lines */
+ private ElementsBuffer lineVertices;
+
+ /** The vertices used to draw bars */
+ private ElementsBuffer barVertices;
+
+ /** The indices used to draw lines */
+ private IndicesBuffer lineIndices;
+
+ /** The indices used to draw a rectangle */
+ private IndicesBuffer rectangleIndices;
+
+ /** The indices used to draw the outline of a rectangle */
+ private IndicesBuffer rectangleOutlineIndices;
+
+ /** The map storing legend text sprites */
+ private Map<Integer, Texture> textureMap;
+
+ /**
+ * Constructor.
+ * @param visitor the DrawerVisitor {@see DrawerVisitor}.
+ */
+ public LegendDrawer(DrawerVisitor visitor) {
+ this.visitor = visitor;
+ this.textureManager = visitor.getCanvas().getTextureManager();
+ this.markManager = visitor.getMarkManager();
+
+ rectangleVertices = visitor.getCanvas().getBuffersManager().createElementsBuffer();
+ lineVertices = visitor.getCanvas().getBuffersManager().createElementsBuffer();
+ barVertices = visitor.getCanvas().getBuffersManager().createElementsBuffer();
+ lineIndices = visitor.getCanvas().getBuffersManager().createIndicesBuffer();
+ rectangleIndices = visitor.getCanvas().getBuffersManager().createIndicesBuffer();
+ rectangleOutlineIndices = visitor.getCanvas().getBuffersManager().createIndicesBuffer();
+
+ textureMap = new ConcurrentHashMap<Integer, Texture>();
+
+ int[] lineIndexData = new int[] {0, 1, 1, 2};
+ lineIndices.setData(lineIndexData);
+ }
+
+ public Dimension computeDimensions(Axes parentAxes, Legend legend) {
+ LegendLocation loc = legend.getLegendLocationAsEnum();
+ if (loc != LegendLocation.IN_UPPER_RIGHT && loc != LegendLocation.IN_UPPER_LEFT &&
+ loc != LegendLocation.IN_LOWER_RIGHT && loc != LegendLocation.IN_LOWER_LEFT) {
+ Figure figure = (Figure) GraphicController.getController().getObjectFromId(parentAxes.getParentFigure());
+ final ColorMap colorMap = figure.getColorMap();
+ final Integer[] links = legend.getLinks();
+ final int nbValidLinks = getNumberValidLinks(legend);
+ if (nbValidLinks < links.length) {
+ dispose(legend.getIdentifier());
+ updateLinks(legend, nbValidLinks);
+ }
+
+ if (nbValidLinks > 0) {
+ Texture legendSprite = getTexture(colorMap, legend);
+ return legendSprite.getDataProvider().getTextureSize();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Draws the given Legend.
+ * @param legend the Legend to draw.
+ * @throws SciRendererException if the draw fail.
+ */
+ public void draw(Legend legend) throws SciRendererException {
+ /* The coordinates of the legend box's lower-left corner */
+ double[] legendCorner = new double[] {0.25, 0.75, Z_FRONT};
+
+ DrawingTools drawingTools = visitor.getDrawingTools();
+ ColorMap colorMap = visitor.getColorMap();
+ Canvas canvas = visitor.getCanvas();
+
+ Integer[] links = legend.getLinks();
+
+ /*
+ * Determine whether any links have become invalid,
+ * force the sprite's update and update the Legend's
+ * links property as needed.
+ */
+ int nbValidLinks = getNumberValidLinks(legend);
+
+ if (nbValidLinks < links.length) {
+ dispose(legend.getIdentifier());
+ updateLinks(legend, nbValidLinks);
+ }
+
+ links = legend.getLinks();
+
+ /*
+ * Set the projection and modelview transformations so that coordinates
+ * are specified in the {0,+1,0,+1,0,+1} space.
+ */
+ TransformationStack modelViewStack = drawingTools.getTransformationManager().getModelViewStack();
+ TransformationStack projectionStack = drawingTools.getTransformationManager().getProjectionStack();
+
+ Transformation identity = TransformationFactory.getIdentity();
+ modelViewStack.push(identity);
+
+ Transformation orthoProj = TransformationFactory.getOrthographic(0.0, 1.0, 0.0, 1.0, -1.0, 0.0);
+ projectionStack.push(orthoProj);
+
+
+ /* First, compute the legend box's position and dimensions from the Axes' parameters and the text sprite's dimensions */
+
+ Integer parentAxesID = legend.getParentAxes();
+ Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentAxesID);
+
+ Double[] axesBounds = parentAxes.getAxesBounds();
+ Double[] margins = parentAxes.getMargins();
+
+ int xAxisLocation = parentAxes.getXAxisLocation();
+ int yAxisLocation = parentAxes.getYAxisLocation();
+
+
+ int canvasWidth = canvas.getWidth();
+ int canvasHeight = canvas.getHeight();
+
+ if (canvasWidth == 0) {
+ canvasWidth = 1;
+ }
+
+ if (canvasHeight == 0) {
+ canvasHeight = 1;
+ }
+
+ Texture legendSprite = null;
+ double normSpriteWidth = 0;
+ double normSpriteHeight = 0;
+
+ if (nbValidLinks > 0) {
+ legendSprite = getTexture(colorMap, legend);
+ Dimension textureSize = legendSprite.getDataProvider().getTextureSize();
+ normSpriteWidth = textureSize.getWidth() / (double) canvasWidth;
+ normSpriteHeight = textureSize.getHeight() / (double) canvasHeight;
+ }
+
+ double lineWidth;
+
+ /* The legend box's width and height */
+ double[] legendDims = new double[2];
+
+ double[] axesPos = new double[2];
+ double[] axesDims = new double[2];
+
+ lineWidth = legend.getLineWidth() * (axesBounds[2]) * (1.0 - margins[0] - margins[1]);
+
+ double xOffset = LINE_WIDTH * (axesBounds[2]) * (1.0 - margins[0] - margins[1]) / 8.0;
+ double yOffset = (Y_OFFSET * (axesBounds[3]) * (1.0 - margins[2] - margins[3]));
+
+ /*
+ * If one of these relations is modified, then AxesDrawer::computeMargins should be modified too
+ */
+ legendDims[0] = normSpriteWidth + lineWidth + 3.0 * xOffset;
+ legendDims[1] = normSpriteHeight + 2.0 * yOffset;
+
+ /* Save the legend box size */
+ Double[] DimsToSet = { legendDims[0], legendDims[1]};
+ legend.setSize(DimsToSet);
+
+ axesPos[0] = axesBounds[0];
+ axesPos[1] = 1.0 - (axesBounds[1] + axesBounds[3]);
+
+ axesDims[0] = axesBounds[2];
+ axesDims[1] = axesBounds[3];
+
+ /* The {x, y} coordinates of the axes box's lower-left and upper-right corners (as defined by bounds and margins) */
+ double[] llBoxCorner = new double[2];
+ double[] urBoxCorner = new double[2];
+
+ LegendLocation legendLocation = legend.getLegendLocationAsEnum();
+
+ llBoxCorner[0] = axesPos[0] + margins[0] * axesDims[0];
+ llBoxCorner[1] = axesPos[1] + margins[3] * axesDims[1];
+
+ urBoxCorner[0] = axesPos[0] + (1.0 - margins[1]) * axesDims[0];
+ urBoxCorner[1] = axesPos[1] + (1.0 - margins[2]) * axesDims[1];
+
+ switch (legendLocation) {
+ case IN_UPPER_RIGHT:
+ legendCorner[0] = (float) (urBoxCorner[0] - xOffset - legendDims[0]);
+ legendCorner[1] = (float) (urBoxCorner[1] - yOffset - legendDims[1]);
+ break;
+ case IN_UPPER_LEFT:
+ legendCorner[0] = (float) (llBoxCorner[0] + xOffset);
+ legendCorner[1] = (float) (urBoxCorner[1] - yOffset - legendDims[1]);
+ break;
+ case IN_LOWER_RIGHT:
+ legendCorner[0] = (float) (urBoxCorner[0] - xOffset - legendDims[0]);
+ legendCorner[1] = (float) (llBoxCorner[1] + yOffset);
+ break;
+ case IN_LOWER_LEFT:
+ legendCorner[0] = (float) (llBoxCorner[0] + xOffset);
+ legendCorner[1] = (float) (llBoxCorner[1] + yOffset);
+ break;
+ case OUT_UPPER_RIGHT:
+ legendCorner[0] = (float) (urBoxCorner[0] + xOffset);
+ legendCorner[1] = (float) (urBoxCorner[1] - legendDims[1]);
+ break;
+ case OUT_UPPER_LEFT:
+ legendCorner[0] = (float) (llBoxCorner[0] - xOffset - legendDims[0]);
+ legendCorner[1] = (float) (urBoxCorner[1] - legendDims[1]);
+ break;
+ case OUT_LOWER_RIGHT:
+ legendCorner[0] = (float) (urBoxCorner[0] + xOffset);
+ legendCorner[1] = (float) (llBoxCorner[1]);
+ break;
+ case OUT_LOWER_LEFT:
+ legendCorner[0] = (float) (llBoxCorner[0] - xOffset - legendDims[0]);
+ legendCorner[1] = (float) (llBoxCorner[1]);
+ break;
+ case UPPER_CAPTION:
+ legendCorner[0] = (float) (llBoxCorner[0]);
+ legendCorner[1] = (float) (urBoxCorner[1] + yOffset);
+
+ /* x-axis at the top */
+ if (xAxisLocation == 1) {
+ /* To do: use the actual label+tick bounding box height */
+ legendCorner[1] += TICK_LABEL_SIZE;
+ }
+ break;
+ case LOWER_CAPTION:
+ legendCorner[0] = (float) (llBoxCorner[0]);
+ legendCorner[1] = (float) (llBoxCorner[1] - yOffset - legendDims[1]);
+
+ /* x-axis at the bottom */
+ if (xAxisLocation == 0) {
+ /* To do: use the actual label+tick bounding box height */
+ legendCorner[1] -= TICK_LABEL_SIZE;
+ }
+ break;
+ case BY_COORDINATES:
+ Double[] legPos = legend.getPosition();
+
+ legendCorner[0] = (float) (axesPos[0] + legPos[0] * axesBounds[2]);
+ legendCorner[1] = (float) (axesPos[1] + (1.0 - legPos[1]) * axesBounds[3] - legendDims[1]);
+ break;
+ }
+
+ /* y-axis positioned to the left */
+ if ((legendLocation == LegendLocation.OUT_UPPER_LEFT || legendLocation == LegendLocation.OUT_LOWER_LEFT) && yAxisLocation == 4) {
+ /* To do: use the actual label+tick bounding box width */
+ legendCorner[0] -= TICK_LABEL_SIZE;
+ /* y-axis positioned to the right */
+ } else if ((legendLocation == LegendLocation.OUT_UPPER_RIGHT || legendLocation == LegendLocation.OUT_LOWER_RIGHT) && yAxisLocation == 5) {
+ /* To do: use the actual label+tick bounding box width */
+ legendCorner[0] += TICK_LABEL_SIZE;
+ }
+
+
+ /* Afterwards, draw the elements making up the Legend using the previously computed values */
+
+ /* Legend background vertex data: lower-left, lower-right, upper-left and upper-right corners */
+ float[] rectangleVertexData = new float[] {
+ (float)legendCorner[0], (float)legendCorner[1], Z_FRONT, 1.0f,
+ (float)(legendCorner[0] + legendDims[0]), (float)legendCorner[1], Z_FRONT, 1.0f,
+ (float)legendCorner[0], (float)(legendCorner[1] + legendDims[1]), Z_FRONT, 1.0f,
+ (float)(legendCorner[0] + legendDims[0]), (float)(legendCorner[1] + legendDims[1]), Z_FRONT, 1.0f
+ };
+
+ /* The indices of a rectangle's triangles and a rectangle outline's segment loop */
+ int[] rectangleIndexData = new int[] {0, 1, 3, 0, 3, 2};
+ int[] rectangleOutlineIndexData = new int[] {0, 1, 1, 3, 3, 2, 2, 0};
+
+ rectangleIndices.setData(rectangleIndexData);
+ rectangleOutlineIndices.setData(rectangleOutlineIndexData);
+
+ rectangleVertices.setData(rectangleVertexData, 4);
+
+ /* Legend rectangle background and outline */
+ DefaultGeometry legendRectangle = new DefaultGeometry();
+ legendRectangle.setVertices(rectangleVertices);
+ legendRectangle.setIndices(rectangleIndices);
+
+ Appearance appearance = new Appearance();
+
+ if (legend.getFillMode()) {
+ legendRectangle.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+ appearance.setFillColor(ColorFactory.createColor(colorMap, legend.getBackground()));
+ } else {
+ legendRectangle.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ }
+
+ /* Legend outline */
+ if (legend.getLineMode()) {
+ legendRectangle.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ legendRectangle.setWireIndices(rectangleOutlineIndices);
+
+ appearance.setLineColor(ColorFactory.createColor(colorMap, legend.getLineColor()));
+ appearance.setLineWidth(legend.getLineThickness().floatValue());
+ appearance.setLinePattern(legend.getLineStyleAsEnum().asPattern());
+ } else {
+ legendRectangle.setLineDrawingMode(Geometry.LineDrawingMode.NONE);
+ }
+
+ drawingTools.draw(legendRectangle, appearance);
+
+ /* Lines: 3 vertices each, left, middle, and right */
+ float[] lineVertexData = new float[] {0.25f, 0.75f, Z_FRONT, 1.0f,
+ 0.5f, 0.75f, Z_FRONT, 1.0f,
+ 0.75f, 0.75f, Z_FRONT, 1.0f
+ };
+
+ double normSpriteMargin = 0.0;
+
+ if (nbValidLinks > 0) {
+ normSpriteMargin = (double) legendSpriteDrawer.getVMargin() / (double) canvasHeight;
+ }
+
+ lineVertexData[0] = (float) (legendCorner[0] + xOffset);
+ lineVertexData[1] = (float) (legendCorner[1] + normSpriteMargin + yOffset);
+
+ lineVertexData[4] = lineVertexData[0] + 0.5f * (float) lineWidth;
+ lineVertexData[5] = lineVertexData[1];
+
+ lineVertexData[8] = lineVertexData[0] + (float) lineWidth;
+ lineVertexData[9] = lineVertexData[1];
+
+ float deltaHeight = 0.0f;
+
+ if (links.length > 0) {
+ deltaHeight = (float) (normSpriteHeight - 2.0 * normSpriteMargin) / ((float)(links.length));
+ }
+
+ lineVertexData[1] = lineVertexData[1] + 0.5f * deltaHeight;
+ lineVertexData[5] = lineVertexData[5] + 0.5f * deltaHeight;
+ lineVertexData[9] = lineVertexData[9] + 0.5f * deltaHeight;
+
+ /* Bar vertex data: lower-left, lower-right, upper-left and upper-right corners */
+ float[] barVertexData = new float[] {0.25f, 0.75f, Z_FRONT, 1.0f,
+ 0.75f, 0.75f, Z_FRONT, 1.0f,
+ 0.25f, 1.00f, Z_FRONT, 1.0f,
+ 0.75f, 1.00f, Z_FRONT, 1.0f
+ };
+
+ float barHeight = BAR_HEIGHT * deltaHeight;
+
+ barVertexData[0] = (float) (legendCorner[0] + xOffset);
+ barVertexData[1] = (float) (legendCorner[1] + normSpriteMargin + yOffset) + 0.5f * (deltaHeight - barHeight);
+
+ barVertexData[4] = barVertexData[0] + (float) lineWidth;
+ barVertexData[5] = barVertexData[1];
+
+ barVertexData[8] = barVertexData[0];
+ barVertexData[9] = barVertexData[1] + barHeight;
+
+ barVertexData[12] = barVertexData[4];
+ barVertexData[13] = barVertexData[9];
+
+ for (Integer link : links) {
+ Polyline currentLine = (Polyline) GraphicController.getController().getObjectFromId(link);
+
+ drawLegendItem(legend, drawingTools, colorMap, currentLine, barVertexData, lineVertexData);
+
+ /* Update the vertex data's vertical position */
+ lineVertexData[1] += deltaHeight;
+ lineVertexData[5] += deltaHeight;
+ lineVertexData[9] += deltaHeight;
+
+ barVertexData[1] += deltaHeight;
+ barVertexData[5] += deltaHeight;
+ barVertexData[9] += deltaHeight;
+ barVertexData[13] += deltaHeight;
+ }
+
+ /* Legend text */
+ float[] spritePosition = new float[] {lineVertexData[8] + (float) xOffset, (float) (legendCorner[1] + yOffset), Z_FRONT};
+
+ /* Draw the sprite only if there are valid links */
+ if (nbValidLinks > 0) {
+ drawingTools.draw(legendSprite, AnchorPosition.LOWER_LEFT, new Vector3d(spritePosition));
+ }
+
+ /* Restore the transformation stacks */
+ modelViewStack.pop();
+ projectionStack.pop();
+
+ /* Output the position if required */
+ Double[] legendPosition = new Double[2];
+
+ if (axesDims[0] == 0.0) {
+ axesDims[0] = 1.0;
+ }
+
+ if (axesDims[1] == 0.0) {
+ axesDims[1] = 1.0;
+ }
+
+ legendPosition[0] = (legendCorner[0] - axesPos[0]) / axesDims[0];
+ legendPosition[1] = 1.0 - (legendCorner[1] + legendDims[1] - axesPos[1]) / axesDims[1];
+
+ if (legendLocation != LegendLocation.BY_COORDINATES) {
+ legend.setPosition(legendPosition);
+ }
+ }
+
+ /**
+ * Draw the legend item corresponding to the given polyline.
+ * It draws either a horizontal line or bar depending on the polyline's properties (style, fill and line modes).
+ * @param legend the Legend.
+ * @param drawingTools the DrawingTools {@see DrawingTools} used to draw the Legend.
+ * @param colorMap the colorMap used.
+ * @param polyline the given polyline.
+ * @param barVertexData a bar's vertex data (4 consecutive (x,y,z,w) quadruplets: lower-left, lower-right, upper-left and upper-right corners.
+ * @param lineVertexData a line's vertex data (3 consecutive (x,y,z,w) quadruplets: left, middle and right vertices).
+ * @throws org.scilab.forge.scirenderer.SciRendererException if the draw fail.
+ */
+ private void drawLegendItem(Legend legend, DrawingTools drawingTools, ColorMap colorMap, Polyline polyline, float[] barVertexData, float[] lineVertexData) throws SciRendererException {
+ int polylineStyle = polyline.getPolylineStyle();
+
+ int lineColor = polyline.getLineColor();
+ double lineThickness = polyline.getLineThickness();
+ short linePattern = polyline.getLineStyleAsEnum().asPattern();
+
+ boolean isBar = (polylineStyle == 6) || (polylineStyle == 7);
+ boolean barDrawn = isBar || polyline.getFillMode();
+
+ /* Draw a bar if the curve is a bar or if it is filled */
+ if (barDrawn) {
+ barVertices.setData(barVertexData, 4);
+
+ DefaultGeometry bar = new DefaultGeometry();
+ bar.setFillDrawingMode(Geometry.FillDrawingMode.TRIANGLES);
+
+ Appearance barAppearance = new Appearance();
+ barAppearance.setFillColor(ColorFactory.createColor(colorMap, polyline.getBackground()));
+ bar.setVertices(barVertices);
+ bar.setIndices(rectangleIndices);
+
+ /* Bar outline */
+ if (isBar || polyline.getLineMode()) {
+ bar.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+ bar.setWireIndices(rectangleOutlineIndices);
+
+ barAppearance.setLineColor(ColorFactory.createColor(colorMap, polyline.getLineColor()));
+ barAppearance.setLineWidth((float) lineThickness);
+ barAppearance.setLinePattern(linePattern);
+ } else {
+ bar.setLineDrawingMode(Geometry.LineDrawingMode.NONE);
+ }
+
+ drawingTools.draw(bar, barAppearance);
+ }
+
+ /* Draw a line otherwise */
+ if (!barDrawn) {
+ lineVertices.setData(lineVertexData, 4);
+
+ /* A line must also be drawn for the vertical polyline style (3), whatever line mode's value */
+ if (polyline.getLineMode() || polylineStyle == 3) {
+ DefaultGeometry line = new DefaultGeometry();
+ line.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+ line.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS_STRIP);
+ line.setVertices(lineVertices);
+ Appearance lineAppearance = new Appearance();
+ lineAppearance.setLineColor(ColorFactory.createColor(colorMap, lineColor));
+ lineAppearance.setLineWidth((float) lineThickness);
+ lineAppearance.setLinePattern(linePattern);
+
+ drawingTools.draw(line, lineAppearance);
+ }
+ }
+
+ /* Draw arrows */
+ if (polylineStyle == 4) {
+ if (barDrawn) {
+ /*
+ * Overlap can occur between the arrow heads of the bar's two smallest segments and the adjacent items.
+ * To do: adjust arrow size to correct this.
+ */
+ visitor.getArrowDrawer().drawArrows(polyline.getParentAxes(), barVertices, rectangleOutlineIndices,
+ polyline.getArrowSizeFactor(), lineThickness, lineColor, false);
+ } else {
+ visitor.getArrowDrawer().drawArrows(polyline.getParentAxes(), lineVertices, lineIndices,
+ polyline.getArrowSizeFactor(), lineThickness, lineColor, false);
+ }
+ }
+
+ if (polyline.getMarkMode()) {
+ Appearance lineAppearance = new Appearance();
+ lineAppearance.setLineWidth((float) lineThickness);
+ Texture markTexture = markManager.getMarkSprite(polyline, colorMap, lineAppearance);
+ if (barDrawn) {
+ drawingTools.draw(markTexture, AnchorPosition.CENTER, barVertices);
+ } else {
+ int marksCount = legend.getMarksCount();
+ float[] data;
+ if (marksCount != 0) {
+ switch (marksCount) {
+ case 1:
+ data = new float[] {lineVertexData[4], lineVertexData[5], lineVertexData[6], lineVertexData[7]};
+ break;
+ case 2:
+ data = new float[] {lineVertexData[0], lineVertexData[1], lineVertexData[2], lineVertexData[3],
+ lineVertexData[8], lineVertexData[9], lineVertexData[10], lineVertexData[11]
+ };
+ break;
+ default:
+ data = new float[] {lineVertexData[0], lineVertexData[1], lineVertexData[2], lineVertexData[3],
+ lineVertexData[4], lineVertexData[5], lineVertexData[6], lineVertexData[7],
+ lineVertexData[8], lineVertexData[9], lineVertexData[10], lineVertexData[11]
+ };
+ break;
+ }
+ lineVertices.setData(data, 4);
+ drawingTools.draw(markTexture, AnchorPosition.CENTER, lineVertices);
+ }
+ }
+ }
+ }
+
+ /**
+ * Updates the legend by disposing its sprite.
+ * @param id the legend id.
+ * @param property the property to update.
+ */
+ public void update(Integer id, int property) {
+ if (textureMap.containsKey(id)) {
+ if (SPRITE_PROPERTIES.contains(property)) {
+ dispose(id);
+ }
+ }
+ }
+
+ /**
+ * Disposes the Legend sprite corresponding to the given id.
+ * @param id the legend id.
+ */
+ public void dispose(Integer id) {
+ Texture texture = textureMap.get(id);
+ if (texture != null) {
+ textureManager.dispose(texture);
+ textureMap.remove(id);
+ }
+ }
+
+ /**
+ * Disposes all the Legend resources.
+ */
+ public void disposeAll() {
+ visitor.getCanvas().getBuffersManager().dispose(rectangleVertices);
+ visitor.getCanvas().getBuffersManager().dispose(lineVertices);
+ visitor.getCanvas().getBuffersManager().dispose(barVertices);
+ visitor.getCanvas().getBuffersManager().dispose(lineIndices);
+ visitor.getCanvas().getBuffersManager().dispose(rectangleIndices);
+ visitor.getCanvas().getBuffersManager().dispose(rectangleOutlineIndices);
+
+ textureManager.dispose(textureMap.values());
+ textureMap.clear();
+ }
+
+ /**
+ * Returns the legend text texture.
+ * @param colorMap the color map.
+ * @param legend the Legend.
+ * @return the text sprite.
+ */
+ private Texture getTexture(ColorMap colorMap, Legend legend) {
+ Texture texture = textureMap.get(legend.getIdentifier());
+ if (texture == null) {
+ this.legendSpriteDrawer = new LegendSpriteDrawer(colorMap, legend);
+ texture = textureManager.createTexture();
+ texture.setDrawer(legendSpriteDrawer);
+ textureMap.put(legend.getIdentifier(), texture);
+ }
+ return texture;
+ }
+
+ /**
+ * Determines and returns the number of valid links for the given Legend object.
+ * @param legend the given Legend.
+ * @return the number of valid links.
+ */
+ private int getNumberValidLinks(Legend legend) {
+ int nbValidLinks = 0;
+ Integer[] links = legend.getLinks();
+
+ for (Integer link : links) {
+ Polyline currentLine = (Polyline) GraphicController.getController().getObjectFromId(link);
+
+ if (currentLine != null) {
+ nbValidLinks++;
+ }
+ }
+
+ return nbValidLinks;
+ }
+
+ /**
+ * Updates the links and text properties of the Legend depending
+ * on the number of valid links provided (the number of links
+ * to non-null objects).
+ * To do: use the graphic controller to perform the update;
+ * move the link update from LegendDrawer to somewhere more appropriate.
+ * @param legend the Legend to update.
+ * @param nbValidLinks the number of valid links.
+ */
+ private void updateLinks(Legend legend, int nbValidLinks) {
+ int i1 = 0;
+ ArrayList <Integer> newLinks = new ArrayList<Integer>(legend.getLinks().length);
+ String[] newStrings;
+ Integer[] newDims = new Integer[2];
+
+ /*
+ * In case there are no valid links, we create a single empty String
+ * in order to retain the Legend's font properties.
+ */
+ if (nbValidLinks == 0) {
+ newDims[0] = 1;
+ } else {
+ newDims[0] = nbValidLinks;
+ }
+
+ newDims[1] = 1;
+
+ newStrings = new String[newDims[0]];
+
+ if (nbValidLinks == 0) {
+ newStrings[0] = new String("");
+ }
+
+ Integer[] links = legend.getLinks();
+ String[] strings = legend.getTextStrings();
+
+ for (int i = 0; i < links.length; i++) {
+ Polyline currentLine = (Polyline) GraphicController.getController().getObjectFromId(links[i]);
+
+ /* Text strings are stored in reverse order relative to links. */
+ if (currentLine != null) {
+ newLinks.add(links[i]);
+
+ newStrings[nbValidLinks - i1 - 1] = new String(strings[strings.length - i - 1]);
+ i1++;
+ }
+ }
+
+ /* Update the legend's links and text */
+ legend.setLinks(newLinks);
+
+ legend.setTextArrayDimensions(newDims);
+ legend.setTextStrings(newStrings);
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/legend/LegendSpriteDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/legend/LegendSpriteDrawer.java
new file mode 100755
index 000000000..ff84b3b4f
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/legend/LegendSpriteDrawer.java
@@ -0,0 +1,96 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ * Copyright (C) 2011 - DIGITEO - Manuel Juliachs
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.legend;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.texture.TextureDrawer;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.legend.Legend;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+import org.scilab.modules.renderer.JoGLView.util.TextObjectSpriteDrawer;
+
+/**
+ * A {@see SpriteDrawer} who draw a Scilab {@see Legend} object.
+ * Adapted from TextSpriteDrawer, minus the unneeded functionalities.
+ * (text box, etc.).
+ * To do: refactoring.
+ * @author Pierre Lando
+ */
+public class LegendSpriteDrawer extends TextObjectSpriteDrawer implements TextureDrawer {
+
+ /**
+ * Default constructor.
+ * @param colorMap the color map to use.
+ * @param legend the scilab {@see Legend} to draw.
+ */
+ LegendSpriteDrawer(final ColorMap colorMap, final Legend legend) {
+ super(colorMap, legend);
+ Appearance appearance = computeAppearance(colorMap, legend);
+ setAppearance(appearance);
+ setThickness((int) Math.ceil(appearance.getLineWidth()));
+ }
+
+ /**
+ * Compute and return an {@see Appearance} adapted to the given scilab legend.
+ * @param colorMap the current scilab color map.
+ * @param legend the given legend.
+ * @return an appearance adapted to the given scilab legend.
+ */
+ private Appearance computeAppearance(final ColorMap colorMap, final Legend legend) {
+ Appearance a = new Appearance();
+
+ if (legend.getFillMode()) {
+ Color fillColor = ColorFactory.createColor(colorMap, legend.getBackground());
+ a.setFillColor(fillColor);
+ } else {
+ a.setFillColor(new Color(0, 0, 0, 0));
+ }
+
+ /* Force line width to 0 */
+ /* For legends, line mode is used to draw the legend outline */
+ /* Line mode must not be used for the text */
+ a.setLineWidth(0);
+
+ return a;
+ }
+
+ /**
+ * Compute and return the matrix of text string from the given {@see Legend} object.
+ * The legend text array is treated as a 1D-array.
+ * @param legend the given {@see Legend} object.
+ * @return the matrix of text strings from the given {@see Legend} object.
+ */
+ private String[][] computeTextData(final Legend legend) {
+ String[] textString = legend.getTextStrings();
+ Integer[] dimensions = legend.getTextArrayDimensions();
+
+ String[][] texts = new String[legend.getLinks().length][1];
+
+ /* Number of actually displayed text items */
+ int nbTextItems = Math.min(legend.getLinks().length, textString.length);
+
+ for (int i = 0; i < nbTextItems; i++) {
+ texts[i][0] = textString[i];
+ }
+
+ /* Pad with blank strings if less input Strings than links */
+ if (nbTextItems < legend.getLinks().length) {
+ for (int i = nbTextItems; i < legend.getLinks().length; i++) {
+ texts[i][0] = new String(" ");
+ }
+ }
+
+ return texts;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/mark/MarkSpriteFactory.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/mark/MarkSpriteFactory.java
new file mode 100755
index 000000000..7c9b9e272
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/mark/MarkSpriteFactory.java
@@ -0,0 +1,495 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.mark;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureDrawer;
+import org.scilab.forge.scirenderer.texture.TextureDrawingTools;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.modules.graphic_objects.contouredObject.Mark;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+
+import java.awt.Dimension;
+
+/**
+ * @author Pierre Lando
+ */
+public class MarkSpriteFactory {
+
+ /**
+ * Return a mark sprite corresponding to the given scilab mark.
+ *
+ *
+ * @param spriteManager the current sprite manager.
+ * @param mark the scilab mark.
+ * @param colorMap the scilab color map.
+ * @return a mark sprite corresponding to the given scilab mark.
+ */
+ public static Texture getMarkSprite(TextureManager spriteManager, Mark mark, Integer selectedColor, ColorMap colorMap, Appearance appearance) {
+ int finalSize;
+
+ /**
+ * Compute the sprite pixel size.
+ */
+ if (mark.getMarkSizeUnit() == Mark.MarkSizeUnitType.TABULATED) {
+ // Special case for compatibility with older versions
+ // dot mark with tabulated size of 0 is a single pixel
+ // drawn in pixel size instead of tabulated size
+ if (mark.getStyle() == 0 && mark.getSize() == 0) {
+ finalSize = 1;
+ } else {
+ finalSize = (8 + 2 * mark.getSize());
+ }
+ } else {
+ finalSize = mark.getSize();
+ }
+
+ Texture sprite = spriteManager.createTexture();
+ sprite.setDrawer(getSpriteDrawer(mark, selectedColor, finalSize, colorMap, appearance));
+
+ return sprite;
+ }
+
+ /**
+ * Return the sprite drawer corresponding to the given mark.
+ * @param mark the mark to draw.
+ * @param finalSize the final mark size.
+ * @param colorMap the scilab colormap to use.
+ * @return the sprite drawer corresponding to the given mark.
+ */
+ private static TextureDrawer getSpriteDrawer(Mark mark, Integer selectedColor, int finalSize, ColorMap colorMap, Appearance usedAppearance) {
+ final Appearance appearance = new Appearance();
+ Integer markColor = selectedColor == null ? mark.getForeground() : selectedColor;
+ Color backgroundColor = ColorFactory.createColor(colorMap, mark.getBackground());
+ Color foregroundColor = ColorFactory.createColor(colorMap, markColor);
+
+ if (mark.getBackground() != 0) {
+ appearance.setFillColor(backgroundColor);
+ } else {
+ appearance.setFillColor(new Color(0.0f, 0.0f, 0.0f, 0.0f));
+ }
+ appearance.setLineColor(foregroundColor);
+ if (usedAppearance != null) {
+ appearance.setLineWidth(usedAppearance.getLineWidth());
+ }
+
+ if (finalSize == 0) {
+ // when finalSize is 0 then a dot is drawn so we draw a dot with a PlusSpriteDrawer
+ // which is well exported with size equal to 1 (see bug 13551)
+ finalSize = 1;
+ }
+
+ if (finalSize != 1) {
+ switch (mark.getStyle()) {
+ case 0:
+ return new DotSpriteDrawer(foregroundColor, finalSize);
+ case 1:
+ return new PlusSpriteDrawer(appearance, finalSize);
+ case 2:
+ return new CrossSpriteDrawer(appearance, finalSize);
+ case 3:
+ return new StarSpriteDrawer(appearance, finalSize);
+ case 4:
+ return new FilledDiamondSpriteDrawer(foregroundColor, finalSize);
+ case 5:
+ return new DiamondSpriteDrawer(appearance, finalSize);
+ case 6:
+ return new TriangleUpSpriteDrawer(appearance, finalSize);
+ case 7:
+ return new TriangleDownSpriteDrawer(appearance, finalSize);
+ case 8:
+ return new DiamondPlusSpriteDrawer(appearance, finalSize);
+ case 9:
+ return new CircleSpriteDrawer(appearance, finalSize);
+ case 10:
+ return new AsteriskSpriteDrawer(appearance, finalSize);
+ case 11:
+ return new SquareSpriteDrawer(appearance, finalSize);
+ case 12:
+ return new TriangleRightSpriteDrawer(appearance, finalSize);
+ case 13:
+ return new TriangleLeftSpriteDrawer(appearance, finalSize);
+ case 14:
+ return new PentagramSpriteDrawer(appearance, finalSize);
+
+ default:
+ return new PlusSpriteDrawer(appearance, finalSize);
+ }
+ } else {
+ return new PlusSpriteDrawer(appearance, finalSize);
+ }
+ }
+
+ /**
+ * Abstract class for all scilab mark sprites.
+ */
+ private static abstract class ScilabSpriteDrawer implements TextureDrawer {
+ protected final Appearance appearance;
+ protected final int size;
+
+ public ScilabSpriteDrawer(Appearance appearance, int size) {
+ this.appearance = appearance;
+ this.size = size;
+ }
+
+ @Override
+ public OriginPosition getOriginPosition() {
+ return TextureDrawer.OriginPosition.CENTER;
+ }
+
+ @Override
+ public Dimension getTextureSize() {
+
+ /** Add a margin such that (0, 0) was pixel aligned. */
+ int margin;
+ if (size % 2 == 0) {
+ margin = 3;
+ } else {
+ margin = 2;
+ }
+ return new Dimension(size + margin, size + margin);
+ }
+ }
+
+ /**
+ * Dot sprite
+ * Scilab ID = 0
+ */
+ private static class DotSpriteDrawer extends ScilabSpriteDrawer {
+ private final Color color;
+
+ public DotSpriteDrawer(Color color, int size) {
+ super(null, size);
+ this.color = color;
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ textureDrawingTools.fillDisc(0, 0, size, color);
+ }
+ }
+
+ /**
+ * Plus sprite
+ * Scilab ID = 1
+ */
+ private static class PlusSpriteDrawer extends ScilabSpriteDrawer {
+
+ public PlusSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ textureDrawingTools.drawPlus(size, appearance);
+ }
+ }
+
+ /**
+ * Cross sprite
+ * Scilab ID = 2
+ */
+ private static class CrossSpriteDrawer extends ScilabSpriteDrawer {
+ private final int[] coordinate1;
+ private final int[] coordinate2;
+
+ public CrossSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+ int r = (int) (size * Math.sqrt(2.0) / 2.0);
+ coordinate1 = new int[] { -r, -r, r, r};
+ coordinate2 = new int[] { -r, r, r, -r};
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ textureDrawingTools.drawPolyline(coordinate1, appearance);
+ textureDrawingTools.drawPolyline(coordinate2, appearance);
+ }
+ }
+
+ /**
+ * Star sprite
+ * Scilab ID = 3
+ */
+ private static class StarSpriteDrawer extends ScilabSpriteDrawer {
+ private final int[] coordinate1;
+ private final int[] coordinate2;
+
+ public StarSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+ int r = size / 2;
+ coordinate1 = new int[] { -r, 0, r, 0};
+ coordinate2 = new int[] { 0, -r, 0, r};
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ textureDrawingTools.fillDisc(0, 0, size, appearance.getFillColor());
+ textureDrawingTools.drawCircle(0, 0, size, appearance);
+ textureDrawingTools.drawPolyline(coordinate1, appearance);
+ textureDrawingTools.drawPolyline(coordinate2, appearance);
+ }
+ }
+
+ /**
+ * Filled diamond sprite
+ * Scilab ID = 4
+ */
+ private static class FilledDiamondSpriteDrawer extends ScilabSpriteDrawer {
+ private final Appearance appearance;
+ private final int[] coordinates;
+
+ public FilledDiamondSpriteDrawer(Color color, int size) {
+ super(null, size);
+ int r = size / 2;
+
+ appearance = new Appearance();
+ appearance.setFillColor(color);
+ appearance.setLineColor(color);
+
+ coordinates = new int[] { -r, 0, 0, -r, +r, 0, 0, +r};
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ textureDrawingTools.fillPolygon(coordinates, appearance);
+ }
+ }
+
+ /**
+ * Abstract class for all the triangle mark sprites.
+ */
+ private static abstract class TriangleSpriteDrawer extends ScilabSpriteDrawer {
+ protected final int r;
+ protected final int basex;
+ protected final int basey;
+ protected int[] coordinates;
+
+ public TriangleSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+ double tmpr = (double)(size / 2);
+
+ r = (int) (tmpr);
+
+ basex = (int) (tmpr * 0.5 * Math.sqrt(3));
+ basey = (int) (tmpr * 0.5);
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ textureDrawingTools.fillPolygon(coordinates, appearance);
+ }
+ }
+
+ /**
+ * Diamond sprite
+ * Scilab ID = 5
+ */
+ private static class DiamondSpriteDrawer extends ScilabSpriteDrawer {
+ protected final int[] coordinates;
+
+ public DiamondSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+ int r = size / 2;
+
+ coordinates = new int[] { -r, 0, 0, -r, r, 0, 0, r};
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ textureDrawingTools.fillPolygon(coordinates, appearance);
+ }
+ }
+
+ /**
+ * Triangle up sprite
+ * Scilab ID = 6
+ */
+ private static class TriangleUpSpriteDrawer extends TriangleSpriteDrawer {
+ public TriangleUpSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+
+ coordinates = new int[] { -basex, basey, 0, -r, basex, basey};
+ }
+ }
+
+ /**
+ * Triangle down sprite
+ * Scilab ID = 7
+ */
+ private static class TriangleDownSpriteDrawer extends TriangleSpriteDrawer {
+ public TriangleDownSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+
+ coordinates = new int[] { -basex, -basey, basex, -basey, 0, r};
+ }
+ }
+
+ /**
+ * Diamond plus sprite
+ * Scilab ID = 8
+ */
+ private static class DiamondPlusSpriteDrawer extends DiamondSpriteDrawer {
+ private final int[] coordinate1;
+ private final int[] coordinate2;
+
+ public DiamondPlusSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+ coordinate1 = new int[] {coordinates[0], coordinates[1], coordinates[4], coordinates[5]};
+ coordinate2 = new int[] {coordinates[2], coordinates[3], coordinates[6], coordinates[7]};
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ super.draw(textureDrawingTools);
+ textureDrawingTools.drawPolyline(coordinate1, appearance);
+ textureDrawingTools.drawPolyline(coordinate2, appearance);
+ }
+ }
+
+ /**
+ * Circle sprite
+ * Scilab ID = 9
+ */
+ private static class CircleSpriteDrawer extends ScilabSpriteDrawer {
+
+ public CircleSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ textureDrawingTools.fillDisc(0, 0, size, appearance.getFillColor());
+ textureDrawingTools.drawCircle(0, 0, size, appearance);
+ }
+ }
+
+ /**
+ * Asterisk sprite
+ * Scilab ID = 10
+ */
+ private static class AsteriskSpriteDrawer extends ScilabSpriteDrawer {
+ private final int[] coordinate1;
+ private final int[] coordinate2;
+ private final int[] coordinate3;
+ private final int[] coordinate4;
+
+ public AsteriskSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+ int r = size / 2;
+ coordinate1 = new int[] { -r, 0, r, 0};
+ coordinate2 = new int[] { 0, -r, 0, r};
+ r = (int) (r * Math.sqrt(2.0) / 2.0);
+ coordinate3 = new int[] { -r, -r, r, r};
+ coordinate4 = new int[] { -r, r, +r, -r};
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ textureDrawingTools.drawPolyline(coordinate1, appearance);
+ textureDrawingTools.drawPolyline(coordinate2, appearance);
+ textureDrawingTools.drawPolyline(coordinate3, appearance);
+ textureDrawingTools.drawPolyline(coordinate4, appearance);
+ }
+ }
+
+ /**
+ * Square sprite
+ * Scilab ID = 11
+ */
+ private static class SquareSpriteDrawer extends ScilabSpriteDrawer {
+ private final int[] coordinate;
+
+ public SquareSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+ int r = size / 2;
+ coordinate = new int[] { -r, -r, +r, -r, +r, +r, -r, +r};
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ textureDrawingTools.fillPolygon(coordinate, appearance);
+ }
+ }
+
+ /**
+ * Triangle right sprite
+ * Scilab ID = 12
+ */
+ private static class TriangleRightSpriteDrawer extends TriangleSpriteDrawer {
+ public TriangleRightSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+
+ coordinates = new int[] { -basey, basex, -basey, -basex, r, 0};
+ }
+ }
+
+ /**
+ * Triangle left sprite
+ * Scilab ID = 13
+ */
+ private static class TriangleLeftSpriteDrawer extends TriangleSpriteDrawer {
+ public TriangleLeftSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+
+ coordinates = new int[] {basey, basex, -r, 0, basey, -basex};
+ }
+ }
+
+ /**
+ * Pentagram sprite (five-pointed star)
+ * Scilab ID = 14
+ */
+ private static class PentagramSpriteDrawer extends ScilabSpriteDrawer {
+ private final int[] coordinates;
+
+ private static final double COS_PI_OVER_10 = Math.cos(Math.PI / 10.0);
+ private static final double SIN_PI_OVER_10 = Math.sin(Math.PI / 10.0);
+ private static final double COS_3_PI_OVER_10 = Math.cos(3.0 * Math.PI / 10.0);
+ private static final double SIN_3_PI_OVER_10 = Math.sin(3.0 * Math.PI / 10.0);
+
+ public PentagramSpriteDrawer(Appearance appearance, int size) {
+ super(appearance, size);
+
+ int r = size / 2;
+
+ double tmpy = SIN_PI_OVER_10 * (double)r;
+
+ int x = (int)(COS_PI_OVER_10 * (double)r);
+ int y = (int)(SIN_PI_OVER_10 * (double)r);
+
+ int x2 = (int)(COS_3_PI_OVER_10 * (double)r);
+ int y2 = (int)(SIN_3_PI_OVER_10 * (double)r);
+
+ double tmpinnr = tmpy / SIN_3_PI_OVER_10;
+
+
+ int xinn = (int)(tmpinnr * COS_3_PI_OVER_10);
+ int yinn = y;
+
+ int xinn2 = (int)(tmpinnr * COS_PI_OVER_10);
+ int yinn2 = (int)(tmpinnr * SIN_PI_OVER_10);
+
+ int innr = (int)tmpinnr;
+
+ coordinates = new int[] { -x2, y2, -xinn2, yinn2, -x, -y, -xinn, -yinn, 0, -r, xinn, -yinn, x, -y, xinn2, yinn2, x2, y2, 0, innr};
+ }
+
+ @Override
+ public void draw(TextureDrawingTools textureDrawingTools) {
+ textureDrawingTools.fillPolygon(coordinates, appearance);
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/mark/MarkSpriteManager.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/mark/MarkSpriteManager.java
new file mode 100755
index 000000000..21455c182
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/mark/MarkSpriteManager.java
@@ -0,0 +1,126 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+package org.scilab.modules.renderer.JoGLView.mark;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.modules.graphic_objects.contouredObject.ContouredObject;
+import org.scilab.modules.graphic_objects.contouredObject.Mark;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ *
+ * This class maintains a mark sprite for graphic entities.
+ *
+ * @author Pierre Lando
+ */
+public class MarkSpriteManager {
+
+ /**
+ * The SciRender sprite manager.
+ */
+ private final TextureManager textureManager;
+
+ /**
+ * The sprite map.
+ */
+ private final Map<Integer, Texture> spriteMap = new ConcurrentHashMap<Integer, Texture>();
+
+
+ /**
+ * Default constructor.
+ * @param textureManager the texture manager to use.
+ */
+ public MarkSpriteManager(TextureManager textureManager) {
+ this.textureManager = textureManager;
+ }
+
+
+ /**
+ * Return the mark sprite for the given contoured object.
+ *
+ * @param contouredObject the given contoured object.
+ * @param colorMap the current color map.
+ * @return the mark sprite for the given contoured object.
+ */
+ public Texture getMarkSprite(ContouredObject contouredObject, ColorMap colorMap, Appearance appearance) {
+ Integer id = contouredObject.getIdentifier();
+ Texture sprite = spriteMap.get(id);
+ if (sprite == null) {
+ Integer selectedColor = contouredObject.getSelected() ? contouredObject.getSelectedColor() : null;
+ sprite = MarkSpriteFactory.getMarkSprite(textureManager, contouredObject.getMark(), selectedColor, colorMap, appearance);
+ spriteMap.put(id, sprite);
+ }
+ return sprite;
+ }
+
+ /**
+ * Return the mark sprite for the given contoured object.
+ * @param id the given contoured object's identifier.
+ * @param mark the given contoured object's Mark.
+ * @param colorMap the current color map.
+ * @return the mark sprite for the given contoured object.
+ */
+ public Texture getMarkSprite(Integer id, Mark mark, ColorMap colorMap, Appearance appearance) {
+ Texture sprite = spriteMap.get(id);
+ if (sprite == null) {
+ sprite = MarkSpriteFactory.getMarkSprite(textureManager, mark, null, colorMap, appearance);
+ spriteMap.put(id, sprite);
+ }
+ return sprite;
+ }
+
+ /**
+ * Update the data if needed.
+ * @param id the modified object.
+ * @param property the changed property.
+ */
+ public void update(Integer id, int property) {
+
+ /**
+ * If the Mark properties have changed.
+ * Dispose the involved mark sprite.
+ */
+ if (property == GraphicObjectProperties.__GO_MARK_MODE__
+ || property == GraphicObjectProperties.__GO_MARK_STYLE__
+ || property == GraphicObjectProperties.__GO_MARK_SIZE_UNIT__
+ || property == GraphicObjectProperties.__GO_MARK_SIZE__
+ || property == GraphicObjectProperties.__GO_MARK_FOREGROUND__
+ || property == GraphicObjectProperties.__GO_MARK_BACKGROUND__
+ || property == GraphicObjectProperties.__GO_LINE_THICKNESS__
+ || property == GraphicObjectProperties.__GO_SELECTED__) {
+ dispose(id);
+ }
+ }
+
+ /**
+ * Dispose the sprite corresponding to the given id.
+ * @param id the given id.
+ */
+ public void dispose(Integer id) {
+ Texture sprite = spriteMap.get(id);
+ textureManager.dispose(sprite);
+ spriteMap.remove(id);
+ }
+
+ /**
+ * Dispose all the mark sprite.
+ */
+ public void disposeAll() {
+ textureManager.dispose(spriteMap.values());
+ spriteMap.clear();
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/postRendering/PostRendered.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/postRendering/PostRendered.java
new file mode 100755
index 000000000..0cec6bd41
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/postRendering/PostRendered.java
@@ -0,0 +1,11 @@
+package org.scilab.modules.renderer.JoGLView.postRendering;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+
+/**
+ * @author Pierre Lando
+ */
+public interface PostRendered {
+ void draw(DrawingTools drawingTools) throws SciRendererException;
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/text/TextManager.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/text/TextManager.java
new file mode 100755
index 000000000..c0208c0ea
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/text/TextManager.java
@@ -0,0 +1,649 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ * Copyright (C) 2012 - DIGITEO - Manuel Juliachs
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.text;
+
+import org.scilab.forge.scirenderer.DrawingTools;
+import org.scilab.forge.scirenderer.SciRendererException;
+import org.scilab.forge.scirenderer.texture.AnchorPosition;
+import org.scilab.forge.scirenderer.texture.Texture;
+import org.scilab.forge.scirenderer.texture.TextureManager;
+import org.scilab.forge.scirenderer.tranformations.DegenerateMatrixException;
+import org.scilab.forge.scirenderer.tranformations.Transformation;
+import org.scilab.forge.scirenderer.tranformations.TransformationFactory;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.modules.graphic_objects.axes.Axes;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
+import org.scilab.modules.graphic_objects.textObject.Text;
+import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
+import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
+
+import java.awt.Dimension;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_FONT_ANGLE__;
+import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_POSITION__;
+
+/**
+ *
+ * This class manage scilab text entity drawing.
+ *
+ *
+ * TODO, Manage: {auto_dimensionning}
+ *
+ *
+ * @author Pierre Lando
+ */
+public class TextManager {
+
+ /**
+ * The {@see Map} off existing {@see TextEntity}.
+ */
+ protected final Map<Integer, Texture> spriteMap = new ConcurrentHashMap<Integer, Texture>();
+
+ /**
+ * The used texture manager.
+ */
+ protected final TextureManager textureManager;
+
+ /**
+ * The bounds of the scale factor range for which the texture does not
+ * need to be updated.
+ */
+ protected double[] FACTOR_UPDATE_INTERVAL = {0.99, 1.01};
+
+ /**
+ * Default constructor.
+ * @param textureManager the texture manager.
+ */
+ public TextManager(TextureManager textureManager) {
+ this.textureManager = textureManager;
+ }
+
+ /**
+ * Draw the given Scilab {@see Text} with the given {@see DrawingTools}.
+ * @param drawingTools the given {@see DrawingTools}.
+ * @param colorMap the current {@see ColorMap}
+ * @param text the given Scilab {@see Text}
+ * @throws SciRendererException if the draw fails.
+ */
+ public final void draw(final DrawingTools drawingTools, final ColorMap colorMap, final Text text) throws SciRendererException {
+ Texture texture = getTexture(colorMap, text);
+
+ /* The unscaled texture's dimensions */
+ Dimension spriteDims = getSpriteDims(colorMap, text);
+
+ Transformation projection = drawingTools.getTransformationManager().getCanvasProjection();
+
+ Integer parentAxesId = text.getParentAxes();
+ Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentAxesId);
+ double[][] factors = parentAxes.getScaleTranslateFactors();
+ Double[] pos = text.getPosition();
+ pos[0] = pos[0] * factors[0][0] + factors[1][0];
+ pos[1] = pos[1] * factors[0][1] + factors[1][1];
+ pos[2] = pos[2] * factors[0][2] + factors[1][2];
+
+ Vector3d textPosition = new Vector3d(pos);
+
+ /* Compute the text box vectors and the text box to texture dimension ratios */
+ Vector3d[] textBoxVectors = computeTextBoxVectors(projection, text, texture.getDataProvider().getTextureSize(), parentAxes);
+ double[] ratios = computeRatios(projection, text, textBoxVectors, texture.getDataProvider().getTextureSize(), spriteDims);
+
+ /* If text box mode is equal to filled, the texture must be updated */
+ if (text.getTextBoxMode() == 2 && ratios[0] != 1.0) {
+ texture = updateSprite(colorMap, text, ratios[0], ratios[1]);
+ }
+
+ /* Compute the text texture's actual position, which depends on the object's text box mode property */
+ Vector3d[] cornerPositions = computeTextPosition(projection, text, textBoxVectors, texture.getDataProvider().getTextureSize());
+
+ /* Draw in window coordinates */
+ drawingTools.getTransformationManager().useWindowCoordinate();
+
+ /* The Text object's rotation direction convention is opposite to the standard one, its angle is expressed in radians. */
+ drawingTools.draw(texture, AnchorPosition.LOWER_LEFT, cornerPositions[0], -180.0 * text.getFontAngle() / Math.PI);
+
+ drawingTools.getTransformationManager().useSceneCoordinate();
+
+ /* Compute the corners of the text's bounding box in window coordinates */
+ Vector3d[] projCorners;
+ if (text.getTextBoxMode() == 2) {
+ projCorners = computeProjTextBoxCorners(cornerPositions[1], text.getFontAngle(), textBoxVectors);
+ } else {
+ projCorners = computeProjCorners(cornerPositions[0], text.getFontAngle(), texture.getDataProvider().getTextureSize());
+ }
+
+ Vector3d[] corners = computeCorners(projection, projCorners, parentAxes);
+ Double[] coordinates = cornersToCoordinateArray(corners);
+
+ /* Set the computed coordinates */
+ text.setCorners(coordinates);
+ }
+
+ /**
+ * Computes and returns the two vectors (in window coordinates) respectively corresponding
+ * to the text box's base and side (also named the text box width and height vectors). If the
+ * Text's text box mode is equal to off, the vectors are then equal to the Text label's base
+ * and side vectors. The Text's rotation is ignored, as it is not required for now.
+ * @param projection the projection from object coordinates to window coordinates.
+ * @param text the Scilab {@see Text}.
+ * @param dimension the current text texture's dimension (in pixels).
+ * @param parentAxes the Axes for which the coordinates are computed.
+ * @return the text box width and height vectors (in window coordinates).
+ */
+ protected Vector3d[] computeTextBoxVectors(Transformation projection, Text text, Dimension dimension, Axes parentAxes) {
+ Double[] textBox = text.getTextBox();
+ Vector3d[] textBoxVectors = new Vector3d[2];
+ double[][] factors = parentAxes.getScaleTranslateFactors();
+ Double[] pos = text.getPosition();
+
+ /* The text position vector before logarithmic scaling */
+ Vector3d textPosition = new Vector3d(pos);
+
+ boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
+
+ /* Apply logarithmic scaling and then project */
+ textPosition = ScaleUtils.applyLogScale(textPosition, logFlags);
+ textPosition = new Vector3d(textPosition.getX() * factors[0][0] + factors[1][0], textPosition.getY() * factors[0][1] + factors[1][1], textPosition.getZ() * factors[0][2] + factors[1][2]);
+ Vector3d projTextPosition = projection.project(textPosition);
+
+ /* Compute the text label vectors in window coordinates */
+ Vector3d width = new Vector3d(dimension.getWidth(), 0.0, 0.0);
+ Vector3d height = new Vector3d(0.0, dimension.getHeight(), 0.0);
+
+ Vector3d projTextWidth = projTextPosition.plus(width);
+ Vector3d projTextHeight = projTextPosition.plus(height);
+
+ /*
+ * Compute the text box's vectors in object coordinates, from the object coordinate text label vectors.
+ * Their norms are unaffected by the text's rotation, which is thus ignored.
+ */
+ Vector3d textWidth = projection.unproject(projTextWidth);
+ Vector3d textHeight = projection.unproject(projTextHeight);
+
+ /* Applies inverse logarithmic scaling */
+ textWidth = ScaleUtils.applyInverseLogScale(textWidth, logFlags);
+ textHeight = ScaleUtils.applyInverseLogScale(textHeight, logFlags);
+
+ textWidth = textWidth.minus(textPosition);
+ textHeight = textHeight.minus(textPosition);
+
+ if (text.getTextBoxMode() >= 1) {
+ textWidth = textWidth.getNormalized().times(textBox[0] * factors[0][0]);
+ textHeight = textHeight.getNormalized().times(textBox[1] * factors[0][1]);
+ }
+
+ /*
+ * We take into account the reverse axes flags in order to
+ * compute the actual text box corners, and hence the correct vectors,
+ * which is necessary when logarithmic scaling is applied.
+ */
+ if (parentAxes.getXAxisReverse()) {
+ textWidth = textWidth.setX(Math.abs(textWidth.getX()));
+ textHeight = textHeight.setX(Math.abs(textHeight.getX()));
+ }
+ if (parentAxes.getYAxisReverse()) {
+ textWidth = textWidth.setY(Math.abs(textWidth.getY()));
+ textHeight = textHeight.setY(Math.abs(textHeight.getY()));
+ }
+ if (parentAxes.getZAxisReverse()) {
+ textWidth = textWidth.setZ(Math.abs(textWidth.getZ()));
+ textHeight = textHeight.setZ(Math.abs(textHeight.getZ()));
+ }
+
+ /* Computes the lower-right and upper-left corners. */
+ textWidth = textWidth.plus(textPosition);
+ textHeight = textHeight.plus(textPosition);
+
+ /* Finally re-apply logarithmic scaling, compute the vectors and project */
+ textWidth = ScaleUtils.applyLogScale(textWidth, logFlags);
+ textHeight = ScaleUtils.applyLogScale(textHeight, logFlags);
+
+ textWidth = textWidth.minus(textPosition);
+ textHeight = textHeight.minus(textPosition);
+
+ projTextWidth = projection.projectDirection(textWidth);
+ projTextHeight = projection.projectDirection(textHeight);
+
+ /*
+ * Ensures that the two window-coordinate base vectors respectively point to the right
+ * and to the top, as taking reversed axes into account may have reversed them (see above).
+ */
+ projTextWidth = projTextWidth.setX(Math.abs(projTextWidth.getX()));
+ projTextHeight = projTextHeight.setX(Math.abs(projTextHeight.getX()));
+ projTextWidth = projTextWidth.setY(Math.abs(projTextWidth.getY()));
+ projTextHeight = projTextHeight.setY(Math.abs(projTextHeight.getY()));
+
+ textBoxVectors[0] = projTextWidth;
+ textBoxVectors[1] = projTextHeight;
+
+ return textBoxVectors;
+ }
+
+ /**
+ * Computes and returns the minimum of the ratios between the text box and the text texture's dimensions.
+ * This minimum ratio is determined for both the current text texture and the unscaled text texture.
+ * @param projection the projection from object coordinates to window coordinates.
+ * @param text the Scilab {@see Text}.
+ * @param textBoxVectors the text box width and height vectors (in window coordinates).
+ * @param spriteDimension the current text texture's dimension (in pixels).
+ * @param baseSpriteDimension the unscaled text texture's dimension (in pixels).
+ * @return the minimum ratios (2 elements: text box to current texture and text box to unscaled texture ratios).
+ */
+ protected double[] computeRatios(Transformation projection, Text text, Vector3d[] textBoxVectors, Dimension spriteDimension,
+ Dimension baseSpriteDimension) {
+ /* 1st element: ratio for the current texture, 2nd element: ratio for the unscaled texture */
+ double[] ratios = new double[] {1.0, 1.0};
+
+ /* Ratios are relevant only to the filled text box mode */
+ if (text.getTextBoxMode() == 2) {
+ Vector3d textBoxWidth = textBoxVectors[0];
+ Vector3d textBoxHeight = textBoxVectors[1];
+
+ /* Compute the ratios. */
+ double minRatio = Math.min(Math.abs(textBoxWidth.getX() / spriteDimension.width), Math.abs(textBoxHeight.getY() / spriteDimension.height));
+ double baseMinRatio = Math.min(Math.abs(textBoxWidth.getX() / baseSpriteDimension.width), Math.abs(textBoxHeight.getY() / baseSpriteDimension.height));
+
+ ratios[0] = minRatio;
+ ratios[1] = baseMinRatio;
+ }
+
+ return ratios;
+ }
+
+ /**
+ * Computes and returns the positions of a Scilab {@see Text} object and its text box in window coordinates, as a function
+ * of its text box mode and text box properties. They are the position of the Text's lower-left corner,
+ * which may differ from the text's unmodified position, depending on its text box properties, and
+ * the position of the text box's lower-left corner. If the text box mode is set to off, the text lower-left corner's position
+ * is simply the text's projected position, and its text box's position is equal to the former.
+ * @param projection the projection from object coordinates to window coordinates.
+ * @param text the Scilab {@see Text}.
+ * @param textBoxVectors the text box width and height vectors (in window coordinates).
+ * @param spriteDim the text texture's dimension (in pixels).
+ * @return the lower-left corners of the Scilab {@see Text}'s text and of its text box in window coordinates (2 elements).
+ * @throws DegenerateMatrixException if the projection is not possible.
+ */
+ protected Vector3d[] computeTextPosition(Transformation projection, Text text, Vector3d[] textBoxVectors, Dimension spriteDim) throws DegenerateMatrixException {
+ Vector3d[] cornerPositions = new Vector3d[2];
+ Integer parentAxesId = text.getParentAxes();
+ Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(parentAxesId);
+ double[][] factors = parentAxes.getScaleTranslateFactors();
+ Double[] pos = text.getPosition();
+ Vector3d textPosition = new Vector3d(pos);
+
+ /* Apply logarithmic scaling */
+ boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
+ textPosition = ScaleUtils.applyLogScale(textPosition, logFlags);
+ textPosition = new Vector3d(textPosition.getX() * factors[0][0] + factors[1][0], textPosition.getY() * factors[0][1] + factors[1][1], textPosition.getZ() * factors[0][2] + factors[1][2]);
+
+ textPosition = projection.project(textPosition);
+
+ cornerPositions[0] = new Vector3d(textPosition);
+ cornerPositions[1] = new Vector3d(textPosition);
+
+ if (text.getTextBoxMode() >= 1) {
+ Vector3d textBoxWidth = new Vector3d(textBoxVectors[0]);
+ Vector3d textBoxHeight = new Vector3d(textBoxVectors[1]);
+
+ double[] textBoxWidthData = textBoxWidth.getData();
+ double[] textBoxHeightData = textBoxHeight.getData();
+
+ /* Reversed axes must be taken into account to correctly compute the text texture's lower-left corner. */
+ if (parentAxes.getXAxisReverse()) {
+ textBoxWidthData[0] = -textBoxWidthData[0];
+ textBoxHeightData[0] = -textBoxHeightData[0];
+ }
+
+ if (parentAxes.getYAxisReverse()) {
+ textBoxWidthData[1] = -textBoxWidthData[1];
+ textBoxHeightData[1] = -textBoxHeightData[1];
+ }
+
+ if (parentAxes.getZAxisReverse()) {
+ textBoxWidthData[2] = -textBoxWidthData[2];
+ textBoxHeightData[2] = -textBoxHeightData[2];
+ }
+
+ Vector3d revTextBoxWidth = new Vector3d(textBoxWidthData);
+ Vector3d revTextBoxHeight = new Vector3d(textBoxHeightData);
+
+ Vector3d[] projCorners = computeProjCorners(textPosition, text.getFontAngle(), spriteDim);
+
+ Vector3d textWidth = projCorners[1].minus(projCorners[0]);
+ Vector3d textHeight = projCorners[2].minus(projCorners[0]);
+
+ /*
+ * Compute the final text box's and text's half-length vectors,
+ * using the rotated text label vectors.
+ */
+ revTextBoxWidth = textWidth.getNormalized().times(0.5 * revTextBoxWidth.getX());
+ revTextBoxHeight = textHeight.getNormalized().times(0.5 * revTextBoxHeight.getY());
+
+ textBoxWidth = textWidth.getNormalized().times(0.5 * textBoxWidth.getX());
+ textBoxHeight = textHeight.getNormalized().times(0.5 * textBoxHeight.getY());
+
+ textWidth = textWidth.times(0.5);
+ textHeight = textHeight.times(0.5);
+
+ /* Compute the actual corner positions from the initial projected position and the half-length vectors */
+ textPosition = textPosition.plus(revTextBoxWidth);
+ textPosition = textPosition.plus(revTextBoxHeight);
+
+ Vector3d textBoxCorner = textPosition.minus(textBoxWidth);
+ textBoxCorner = textBoxCorner.minus(textBoxHeight);
+
+ textPosition = textPosition.minus(textWidth);
+ textPosition = textPosition.minus(textHeight);
+
+ cornerPositions[0] = textPosition;
+ cornerPositions[1] = textBoxCorner;
+ }
+
+ return cornerPositions;
+ }
+
+ /**
+ * Computes and returns the corners of a {@see Text} object's bounding box, in window coordinates.
+ * The returned corners are in the following order: lower-left, lower-right, upper-left and upper-right.
+ * @param canvasProj the projection from object coordinates to window coordinates.
+ * @param position the text's position in object coordinates.
+ * @param fontAngle the text's font angle (radians).
+ * @param spriteDim the text texture's dimension (in pixels).
+ * @return the corners' window coordinates (4-element array).
+ * @throws DegenerateMatrixException if the projection is not possible.
+ */
+ protected Vector3d[] computeProjCorners(Transformation canvasProj, Vector3d position, double fontAngle, Dimension spriteDim) throws DegenerateMatrixException {
+ position = canvasProj.project(position);
+ return computeProjCorners(position, fontAngle, spriteDim);
+ }
+
+ /**
+ * Computes the corners of a {@see Text} object's text box, in window coordinates.
+ * @param position the position of the text box's lower-left corner in window cordinates.
+ * @param fontAngle the text's font angle (radians).
+ * @param textBoxVectors the text box width and height vectors (in window coordinates).
+ * @return the corners' window coordinates (4-element array).
+ * @throws DegenerateMatrixException if the projection is not possible.
+ */
+ protected Vector3d[] computeProjTextBoxCorners(Vector3d position, double fontAngle, Vector3d[] textBoxVectors) throws DegenerateMatrixException {
+ double projTextBoxWidth = textBoxVectors[0].getNorm();
+ double projTextBoxHeight = textBoxVectors[1].getNorm();
+
+ return computeProjCorners(position, fontAngle, new Dimension((int) projTextBoxWidth, (int) projTextBoxHeight));
+ }
+
+ /**
+ * Computes and returns the corners of a {@see Text} object's bounding box, in window coordinates.
+ * The returned corners are in the following order: lower-left, lower-right, upper-left and upper-right.
+ * @param projPosition the text's position in window coordinates.
+ * @param fontAngle the text's font angle (radians).
+ * @param spriteDim the text texture's dimension (in pixels).
+ * @return the corners' window coordinates (4-element array).
+ * @throws DegenerateMatrixException if the projection is not possible.
+ */
+ protected Vector3d[] computeProjCorners(Vector3d projPosition, double fontAngle, Dimension spriteDim) throws DegenerateMatrixException {
+ Vector3d[] projCorners = new Vector3d[4];
+
+ /*
+ * Should be -fontAngle, as positive angle values are measured clockwise for texts.
+ * Apparently uses the same convention as the texts (clockwise positive directions).
+ * To be verified.
+ */
+ Transformation projRotation = TransformationFactory.getRotationTransformation(180.0 * fontAngle / Math.PI, 0.0, 0.0, 1.0);
+
+ projCorners[0] = projPosition;
+
+ Vector3d width = new Vector3d(spriteDim.width, 0.0, 0.0);
+ Vector3d height = new Vector3d(0.0, spriteDim.height, 0.0);
+
+ width = projRotation.projectDirection(width);
+ height = projRotation.projectDirection(height);
+
+ projCorners[1] = projCorners[0].plus(width);
+ projCorners[2] = projCorners[0].plus(height);
+ projCorners[3] = projCorners[2].plus(width);
+
+ return projCorners;
+ }
+
+ /**
+ * Computes and returns the corners (in user coordinates) of a text's bounding box.
+ * @param projection the projection from object coordinates to window coordinates.
+ * @param projCorners the corners of the text's bounding box in window coordinates (4-element array).
+ * @param parentAxes the Axes for which the coordinates are computed.
+ * @return the corners of the text's bounding box in user coordinates (4-element array).
+ */
+ protected Vector3d[] computeCorners(Transformation projection, Vector3d[] projCorners, Axes parentAxes) {
+ Vector3d[] corners = new Vector3d[4];
+ boolean[] logFlags = new boolean[] {parentAxes.getXAxisLogFlag(), parentAxes.getYAxisLogFlag(), parentAxes.getZAxisLogFlag()};
+
+ corners[0] = projection.unproject(projCorners[0]);
+ corners[1] = projection.unproject(projCorners[1]);
+ corners[2] = projection.unproject(projCorners[2]);
+ corners[3] = projection.unproject(projCorners[3]);
+
+ /* Apply inverse logarithmic scaling in order to obtain user coordinates */
+ corners[0] = ScaleUtils.applyInverseLogScale(corners[0], logFlags);
+ corners[1] = ScaleUtils.applyInverseLogScale(corners[1], logFlags);
+ corners[2] = ScaleUtils.applyInverseLogScale(corners[2], logFlags);
+ corners[3] = ScaleUtils.applyInverseLogScale(corners[3], logFlags);
+
+ return corners;
+ }
+
+ /**
+ * Returns the positions of a bounding box's corners as an array of (x,y,z) coordinate triplets.
+ * The output corners are reordered to match their order in the {@see Text} object's
+ * equivalent array, respectively: lower-left, lower-right, upper-left, upper-right in the input array,
+ * starting from the lower-left and going in clockwise order in the returned array.
+ * @param corners of the bounding box (4-element array).
+ * @return the corners' coordinates (12-element array).
+ */
+ protected Double[] cornersToCoordinateArray(Vector3d[] corners) {
+ Double[] coordinates = new Double[12];
+ coordinates[0] = corners[0].getX();
+ coordinates[1] = corners[0].getY();
+ coordinates[2] = corners[0].getZ();
+
+ coordinates[3] = corners[2].getX();
+ coordinates[4] = corners[2].getY();
+ coordinates[5] = corners[2].getZ();
+
+ coordinates[6] = corners[3].getX();
+ coordinates[7] = corners[3].getY();
+ coordinates[8] = corners[3].getZ();
+
+ coordinates[9] = corners[1].getX();
+ coordinates[10] = corners[1].getY();
+ coordinates[11] = corners[1].getZ();
+
+ return coordinates;
+ }
+
+ /**
+ * Update the data if needed.
+ * @param id the modified object.
+ * @param property the changed property.
+ */
+ public void update(Integer id, int property) {
+ if (!(__GO_POSITION__ == property) && !(__GO_FONT_ANGLE__ == property)) {
+ dispose(id);
+ }
+ }
+
+ /**
+ * Return the SciRenderer {@see Texture} corresponding to the given Scilab {@see Text}.
+ * @param colorMap the current color map.
+ * @param text the given Scilab {@see Text}.
+ * @return the SciRenderer {@see Texture} corresponding to the given Scilab {@see Text}.
+ */
+ protected Texture getTexture(final ColorMap colorMap, final Text text) {
+ Texture texture = spriteMap.get(text.getIdentifier());
+ if (texture == null) {
+ if (text.getTextBoxMode() == 2) {
+ /* Create an unscaled texture (scale factor equal to 1) */
+ texture = createSprite(colorMap, text, 1.0);
+ } else {
+ texture = createSprite(colorMap, text);
+ }
+ spriteMap.put(text.getIdentifier(), texture);
+ }
+ return texture;
+ }
+
+ /**
+ * Updates a texture according to a scale factor, which is the ratio by which the texture is enlarged.
+ * @param colorMap the current color map.
+ * @param text the Scilab Text.
+ * @param scaleFactor the scale factor relative to the current texture's dimensions.
+ * @param baseScaleFactor the scale factor relative to the unscaled texture's dimensions.
+ * @return the corresponding texture.
+ */
+ protected Texture updateSprite(final ColorMap colorMap, final Text text, double scaleFactor, double baseScaleFactor) {
+ Texture texture = spriteMap.get(text.getIdentifier());
+
+ /* Create a new texture if the scale factor falls outside of the range */
+ if (scaleFactor < FACTOR_UPDATE_INTERVAL[0] || scaleFactor > FACTOR_UPDATE_INTERVAL[1]) {
+ dispose(text.getIdentifier());
+ texture = createSprite(colorMap, text, baseScaleFactor);
+ spriteMap.put(text.getIdentifier(), texture);
+ }
+
+ return texture;
+ }
+
+ /**
+ * Returns the dimensions of the SciRenderer {@see Texture} corresponding to the given Scilab {@see Text}.
+ * The dimensions are in pixels (width, height).
+ * @param colorMap the current color map.
+ * @param text the given Scilab {@see Text}.
+ * @return the texture's dimension.
+ */
+ protected Dimension getSpriteDims(final ColorMap colorMap, final Text text) {
+ TextSpriteDrawer spriteDrawer;
+
+ if (text.getTextBoxMode() == 2) {
+ /* Set the scale factor to 1 in order to return the dimensions of an unscaled texture. */
+ spriteDrawer = new TextSpriteDrawer(colorMap, text, 1.0);
+ } else {
+ spriteDrawer = new TextSpriteDrawer(colorMap, text);
+ }
+
+ return spriteDrawer.getTextureSize();
+ }
+
+ /**
+ * Create a texture for the given text object.
+ * @param colorMap the current colormap.
+ * @param textObject the given text object.
+ * @return a new texture for the given text object.
+ */
+ protected Texture createSprite(final ColorMap colorMap, final Text textObject) {
+ TextSpriteDrawer spriteDrawer = new TextSpriteDrawer(colorMap, textObject);
+ Texture texture = textureManager.createTexture();
+ texture.setMagnificationFilter(Texture.Filter.LINEAR);
+ texture.setMinifyingFilter(Texture.Filter.LINEAR);
+ texture.setDrawer(spriteDrawer);
+ return texture;
+ }
+
+ /**
+ * Creates a texture for the given text object, scaled by the given scale factor.
+ * @param colorMap the current colormap.
+ * @param textObject the given text object.
+ * @param scaleFactor the scale factor to apply.
+ * @return a new texture for the given text object.
+ */
+ protected Texture createSprite(final ColorMap colorMap, final Text textObject, double scaleFactor) {
+ TextSpriteDrawer spriteDrawer = new TextSpriteDrawer(colorMap, textObject, scaleFactor);
+ Texture texture = textureManager.createTexture();
+ texture.setMagnificationFilter(Texture.Filter.LINEAR);
+ texture.setMinifyingFilter(Texture.Filter.LINEAR);
+ texture.setDrawer(spriteDrawer);
+ return texture;
+ }
+
+ /**
+ * Dispose the texture corresponding to the given id.
+ * @param id the given id.
+ */
+ public void dispose(Integer id) {
+ Texture texture = spriteMap.get(id);
+ if (texture != null) {
+ textureManager.dispose(texture);
+ spriteMap.remove(id);
+ }
+ }
+
+ /**
+ * Dispose all the text sprites.
+ */
+ public void disposeAll() {
+ textureManager.dispose(spriteMap.values());
+ spriteMap.clear();
+ }
+
+ /**
+ * Computes and updates the corners of the given Scilab {@see Text}.
+ * @param text the given Scilab {@see Text}.
+ */
+ public static void updateTextCorners(Text text) {
+ Vector3d[] projCorners = null;
+
+ DrawerVisitor currentVisitor = DrawerVisitor.getVisitor(text.getParentFrameOrFigure());
+ Axes parentAxes = (Axes) GraphicController.getController().getObjectFromId(text.getParentAxes());
+
+ /* Compute the corners */
+ try {
+ Transformation currentProj = currentVisitor.getAxesDrawer().getCurrentProjection(parentAxes);
+
+ Dimension spriteDim = currentVisitor.getTextManager().getSpriteDims(currentVisitor.getColorMap(), text);
+
+ Vector3d[] textBoxVectors = currentVisitor.getTextManager().computeTextBoxVectors(currentProj, text, spriteDim, parentAxes);
+ Vector3d[] cornerPositions = currentVisitor.getTextManager().computeTextPosition(currentProj, text, textBoxVectors, spriteDim);
+
+ if (text.getTextBoxMode() == 2) {
+ projCorners = currentVisitor.getTextManager().computeProjTextBoxCorners(cornerPositions[1], text.getFontAngle(), textBoxVectors);
+ } else {
+ projCorners = currentVisitor.getTextManager().computeProjCorners(cornerPositions[0], text.getFontAngle(), spriteDim);
+ }
+
+ Vector3d[] corners = currentVisitor.getTextManager().computeCorners(currentProj, projCorners, parentAxes);
+ Double[] coordinates = currentVisitor.getTextManager().cornersToCoordinateArray(corners);
+
+ double[][] factors = parentAxes.getScaleTranslateFactors();
+ coordinates[0] = (coordinates[0] - factors[1][0]) / factors[0][0];
+ coordinates[1] = (coordinates[1] - factors[1][1]) / factors[0][1];
+ coordinates[2] = (coordinates[2] - factors[1][2]) / factors[0][2];
+ coordinates[3] = (coordinates[3] - factors[1][0]) / factors[0][0];
+ coordinates[4] = (coordinates[4] - factors[1][1]) / factors[0][1];
+ coordinates[5] = (coordinates[5] - factors[1][2]) / factors[0][2];
+ coordinates[6] = (coordinates[6] - factors[1][0]) / factors[0][0];
+ coordinates[7] = (coordinates[7] - factors[1][1]) / factors[0][1];
+ coordinates[8] = (coordinates[8] - factors[1][2]) / factors[0][2];
+ coordinates[9] = (coordinates[9] - factors[1][0]) / factors[0][0];
+ coordinates[10] = (coordinates[10] - factors[1][1]) / factors[0][1];
+ coordinates[11] = (coordinates[11] - factors[1][2]) / factors[0][2];
+
+ /* Set the computed coordinates */
+ text.setCorners(coordinates);
+
+ } catch (DegenerateMatrixException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/text/TextSpriteDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/text/TextSpriteDrawer.java
new file mode 100755
index 000000000..91fe1a4a6
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/text/TextSpriteDrawer.java
@@ -0,0 +1,112 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.text;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.texture.TextureDrawer;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.textObject.Text;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
+import org.scilab.modules.renderer.JoGLView.util.TextObjectSpriteDrawer;
+
+/**
+ * A {@see TextureDrawer} that draw a Scilab {@see Text} object.
+ * @author Pierre Lando
+ */
+class TextSpriteDrawer extends TextObjectSpriteDrawer implements TextureDrawer {
+
+ /** The scale factor. */
+ private double scaleFactor = 1.0;
+
+ /**
+ * Default constructor.
+ * @param colorMap the color map to use.
+ * @param textObject the scilab {@see Text} to draw.
+ */
+ TextSpriteDrawer(final ColorMap colorMap, final Text textObject) {
+ super(colorMap, textObject);
+ setAlignmentFactor(computeAlignmentFactor(textObject));
+ Appearance appearance = computeAppearance(colorMap, textObject);
+
+ setAppearance(appearance);
+ setThickness((int) Math.ceil(appearance.getLineWidth()));
+ }
+
+ /**
+ * Constructor.
+ * Specifies a scale factor used to scale the text matrix.
+ * @param colorMap the color map to use.
+ * @param textObject the Scilab {@link Text} to draw.
+ * @param scaleFactor the scale factor to apply.
+ */
+ TextSpriteDrawer(final ColorMap colorMap, final Text textObject, double scaleFactor) {
+ super(colorMap, textObject, scaleFactor);
+ setAlignmentFactor(computeAlignmentFactor(textObject));
+ Appearance appearance = computeAppearance(colorMap, textObject);
+
+ setAppearance(appearance);
+ setThickness((int) Math.ceil(appearance.getLineWidth()));
+
+ this.scaleFactor = scaleFactor;
+ }
+
+ /**
+ * Compute and return an {@see Appearance} adapted to the given scilab text.
+ * @param colorMap the current scilab color map.
+ * @param text the given text.
+ * @return an appearance adapted to the given scilab text.
+ */
+ private Appearance computeAppearance(final ColorMap colorMap, final Text text) {
+ Appearance a = new Appearance();
+
+ if (text.getBox() && text.getFillMode()) {
+ Color fillColor = ColorFactory.createColor(colorMap, text.getBackground());
+ a.setFillColor(fillColor);
+ } else {
+ a.setFillColor(new Color(0, 0, 0, 0));
+ }
+
+ if (text.getBox() && text.getLineMode()) {
+ Color lineColor = ColorFactory.createColor(colorMap, text.getLineColor());
+ a.setLineColor(lineColor);
+ a.setLineWidth(1);
+ } else {
+ a.setLineWidth(0);
+ }
+
+ return a;
+ }
+
+ /**
+ * Returns the margin modified by the scale factor.
+ */
+ public int getHMargin() {
+ return (int)(scaleFactor * (double) super.getHMargin());
+ }
+
+ /**
+ * Returns the margin modified by the scale factor.
+ */
+ public int getVMargin() {
+ return (int)(scaleFactor * (double) super.getVMargin());
+ }
+
+ /**
+ * Returns the space width modified by the scale factor.
+ */
+ public int getSpaceWidth() {
+ return (int)(scaleFactor * (double) super.getSpaceWidth());
+ }
+
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/BufferAllocation.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/BufferAllocation.java
new file mode 100755
index 000000000..60e3a65b0
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/BufferAllocation.java
@@ -0,0 +1,100 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.util;
+
+import com.jogamp.opengl.util.GLBuffers;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * @author Pierre Lando
+ */
+public final class BufferAllocation {
+
+ /** keep 32 Mo of free memory */
+ private static final int REMAINING_MEMORY = 32 * 1024 * 1024;
+
+ /** Hidden constructor */
+ private BufferAllocation() {
+ }
+
+ /**
+ * Allocate a new direct byte buffer of given length.
+ * @param length the given length.
+ * @return a new direct byte buffer of given length.
+ * @throws OutOfMemoryException if java heap space is to small.
+ */
+ public static ByteBuffer newByteBuffer(int length) throws OutOfMemoryException {
+ haveFreeMemory(length);
+ ByteBuffer buffer = GLBuffers.newDirectByteBuffer(length);
+ if (buffer.limit() != length) {
+ throw new OutOfMemoryException();
+ }
+ return buffer;
+ }
+
+ /**
+ * Allocate a new direct integer buffer of given length.
+ * @param length the given length.
+ * @return a new direct integer buffer of given length.
+ * @throws OutOfMemoryException if java heap space is to small.
+ */
+ public static IntBuffer newIntBuffer(int length) throws OutOfMemoryException {
+ haveFreeMemory(length * Integer.SIZE / Byte.SIZE);
+ IntBuffer buffer = GLBuffers.newDirectIntBuffer(length);
+ if (buffer.limit() != length) {
+ throw new OutOfMemoryException();
+ }
+ return buffer;
+ }
+
+ /**
+ * Allocate a new direct float buffer of given length.
+ * @param length the given length.
+ * @return a new direct float buffer of given length.
+ * @throws OutOfMemoryException if java heap space is to small.
+ */
+ public static FloatBuffer newFloatBuffer(int length) throws OutOfMemoryException {
+ haveFreeMemory(length * Float.SIZE / Byte.SIZE);
+ FloatBuffer buffer = GLBuffers.newDirectFloatBuffer(length);
+ if (buffer.limit() != length) {
+ throw new OutOfMemoryException();
+ }
+ return buffer;
+ }
+
+ /**
+ * Check if the java heap space have enough memory.
+ * @param length the memory needed (in bytes).
+ * @throws OutOfMemoryException if there was not enough memory.
+ * @return a byte buffer of given length.
+ */
+ private static void haveFreeMemory(int length) throws OutOfMemoryException {
+ final long max = Runtime.getRuntime().maxMemory();
+ long total = Runtime.getRuntime().totalMemory();
+ long free = Runtime.getRuntime().freeMemory();
+
+ long realFree = max - total + free;
+ if (realFree < length + REMAINING_MEMORY) {
+ Runtime.getRuntime().gc();
+ total = Runtime.getRuntime().totalMemory();
+ free = Runtime.getRuntime().freeMemory();
+ }
+
+ realFree = max - total + free;
+ if (realFree < length + REMAINING_MEMORY) {
+ throw new OutOfMemoryException();
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/ColorFactory.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/ColorFactory.java
new file mode 100755
index 000000000..eddbe2133
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/ColorFactory.java
@@ -0,0 +1,52 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.util;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+
+/**
+ * Utility class to create color form scilab color.
+ *
+ * @author Pierre Lando
+ */
+public final class ColorFactory {
+
+ /**
+ * Create a {@see Color} object representing the given scilab color.
+ * @param colorMap the scilab colormap to use.
+ * @param colorIndex the given scilab color.
+ * @return a {@see Color} object representing the given scilab color.
+ */
+ public static Color createColor(ColorMap colorMap, int colorIndex) {
+ if (colorMap != null) {
+ float[] colorData = colorMap.getScilabColor(colorIndex);
+ return new Color(colorData[0], colorData[1], colorData[2]);
+ } else {
+ return new Color(0, 0, 0);
+ }
+ }
+
+ /**
+ * Create a float array filled with the RGBA data of the given scilab color.
+ * @param colorMap the scilab colormap to use.
+ * @param colorIndex the given scilab color.
+ * @return a float array filled with the RGBA data of the given scilab color.
+ */
+ public static float[] createRGBAColor(ColorMap colorMap, int colorIndex) {
+ float[] rgbData = colorMap.getScilabColor(colorIndex);
+ float[] rgbaData = new float[4];
+ System.arraycopy(rgbData, 0, rgbaData, 0, 3);
+ rgbaData[3] = 1f;
+ return rgbaData;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/FormattedTextSpriteDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/FormattedTextSpriteDrawer.java
new file mode 100755
index 000000000..5b2c5332b
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/FormattedTextSpriteDrawer.java
@@ -0,0 +1,121 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+package org.scilab.modules.renderer.JoGLView.util;
+
+import org.scilab.forge.jlatexmath.TeXConstants;
+import org.scilab.forge.jlatexmath.TeXFormula;
+import org.scilab.forge.jlatexmath.TeXIcon;
+import org.scilab.forge.scirenderer.texture.TextEntity;
+import org.scilab.forge.scirenderer.texture.TextureDrawer;
+import org.scilab.forge.scirenderer.texture.TextureDrawingTools;
+import org.scilab.modules.console.utils.ScilabSpecialTextUtilities;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.textObject.Font;
+import org.scilab.modules.graphic_objects.textObject.FormattedText;
+import org.scilab.modules.jvm.LoadClassPath;
+import org.scilab.modules.renderer.utils.textRendering.FontManager;
+
+import javax.swing.Icon;
+import java.awt.Dimension;
+
+/**
+ * @author Pierre Lando
+ */
+public class FormattedTextSpriteDrawer implements TextureDrawer {
+ private final TextEntity textEntity;
+ private final Dimension dimension;
+ private final int descent;
+ private final Icon icon;
+
+ public FormattedTextSpriteDrawer(ColorMap colorMap, String text, Font font) {
+ if (text != null && font != null) {
+ if (isLatex(text)) {
+ LoadClassPath.loadOnUse("graphics_latex_textrendering");
+ TeXFormula formula = new TeXFormula(text.substring(1, text.length() - 1));
+ formula.setColor(ColorFactory.createColor(colorMap, font.getColor()));
+ icon = formula.createTeXIcon(TeXConstants.STYLE_DISPLAY, FontManager.scilabSizeToAwtSize(font.getSize()));
+ descent = ((TeXIcon) icon).getIconDepth();
+ } else if (isMathML(text)) {
+ LoadClassPath.loadOnUse("graphics_mathml_textrendering");
+ icon = ScilabSpecialTextUtilities.compileMathMLExpression(text, ((int) FontManager.scilabSizeToAwtSize(font.getSize() + .5)), ColorFactory.createColor(colorMap, font.getColor()));
+ descent = 0;
+ } else {
+ icon = null;
+ descent = 0;
+ }
+
+ if (icon != null) {
+ textEntity = null;
+ dimension = new Dimension(icon.getIconWidth(), icon.getIconHeight() + descent);
+ } else {
+ textEntity = new TextEntity(text);
+
+ textEntity.setFont(FontManager.getSciFontManager().getFontFromIndex(font.getStyle(), font.getSize()));
+ textEntity.setText(text);
+ textEntity.setTextColor(ColorFactory.createColor(colorMap, font.getColor()));
+ textEntity.setTextUseFractionalMetrics(font.getFractional());
+ textEntity.setTextAntiAliased(true);
+
+ dimension = textEntity.getSize();
+ }
+ } else {
+ icon = null;
+ textEntity = null;
+ dimension = new Dimension();
+ descent = 0;
+ }
+ }
+
+ public FormattedTextSpriteDrawer(ColorMap colorMap, FormattedText formattedText) {
+ this(colorMap, formattedText != null ? formattedText.getText() : null, formattedText != null ? formattedText.getFont() : null);
+ }
+
+ @Override
+ public void draw(TextureDrawingTools drawingTools) {
+ if (textEntity != null) {
+ drawingTools.draw(textEntity, 0, 0);
+ } else if (icon != null) {
+ drawingTools.draw(icon, 0, descent);
+ }
+ }
+
+ @Override
+ public Dimension getTextureSize() {
+ return new Dimension(dimension);
+ }
+
+ @Override
+ public OriginPosition getOriginPosition() {
+ return OriginPosition.UPPER_LEFT;
+ }
+
+ public Dimension getSpriteSize() {
+ return new Dimension(dimension);
+ }
+
+ /**
+ * Return true if the given string represent a latex entity.
+ * @param string the given string.
+ * @return true if the given string represent a latex entity.
+ */
+ public static boolean isLatex(String string) {
+ return (string.length() >= 2) && string.endsWith("$") && string.startsWith("$");
+ }
+
+ /**
+ * Return true if the given string represent a MathML entity.
+ * @param string the given string.
+ * @return true if the given string represent a MathML entity.
+ */
+ public static boolean isMathML(String string) {
+ return (string.length() >= 2) && string.endsWith(">") && string.startsWith("<");
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/LightingUtils.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/LightingUtils.java
new file mode 100755
index 000000000..5447444fe
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/LightingUtils.java
@@ -0,0 +1,119 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2013 - Pedro SOUZA
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+package org.scilab.modules.renderer.JoGLView.util;
+
+import org.scilab.forge.scirenderer.shapes.appearance.Material;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+import org.scilab.forge.scirenderer.lightning.Light;
+import org.scilab.forge.scirenderer.lightning.LightManager;
+
+import org.scilab.modules.graphic_objects.graphicObject.GraphicObject;
+import org.scilab.modules.graphic_objects.graphicController.GraphicController;
+
+/**
+ * Utility functions to setup lighting.
+ * @author Pedro SOUZA
+ */
+public class LightingUtils {
+
+ /**
+ * Convert the given material to a scirenderer material.
+ * @param m the material.
+ */
+ public static Material getMaterial(org.scilab.modules.graphic_objects.lighting.Material m) {
+ Material mtl = new Material();
+
+ Double[] color = m.getAmbientColor();
+ mtl.setAmbientColor(new Color(color[0].floatValue(), color[1].floatValue(), color[2].floatValue()));
+ color = m.getDiffuseColor();
+ mtl.setDiffuseColor(new Color(color[0].floatValue(), color[1].floatValue(), color[2].floatValue()));
+ color = m.getSpecularColor();
+ mtl.setSpecularColor(new Color(color[0].floatValue(), color[1].floatValue(), color[2].floatValue()));
+ mtl.setColorMaterialEnable(m.getColorMaterialMode().booleanValue());
+ mtl.setShininess(m.getShininess().floatValue());
+
+ return mtl;
+ }
+
+ /**
+ * Enables/disables lighting.
+ * @param manager the light manager.
+ * @param status the status.
+ */
+ public static void setLightingEnable(LightManager manager, Boolean status) {
+ if (manager == null) {
+ return;
+ }
+ manager.setLightningEnable(status.booleanValue());
+ Light light = manager.getLight(0);
+ light.setEnable(status.booleanValue());
+ }
+
+
+ public static void setupLights(LightManager manager, org.scilab.modules.graphic_objects.axes.Axes axes) {
+
+ if (manager == null) {
+ return;
+ }
+
+ boolean hasLight = false;
+ int index = 0;
+
+ for (Integer child : axes.getChildren()) {
+ GraphicObject object = GraphicController.getController().getObjectFromId(child);
+ if (object instanceof org.scilab.modules.graphic_objects.lighting.Light) {
+ //setup only visible lights
+ if (((org.scilab.modules.graphic_objects.lighting.Light)object).getVisible()) {
+ setLight(manager, (org.scilab.modules.graphic_objects.lighting.Light)object, index++, axes);
+ hasLight = true;
+ }
+ }
+ if (index >= manager.getLightNumber()) {
+ break;
+ }
+ }
+ for (int i = index; i < manager.getLightNumber(); ++i) {
+ //manager.getLight(i).setEnable(false);
+ }
+ manager.setLightningEnable(hasLight);
+ }
+
+ /**
+ * Setup the give light.
+ * @param manager the light manager.
+ * @param light the light.
+ * @param index the light index.
+ */
+ public static void setLight(LightManager manager, org.scilab.modules.graphic_objects.lighting.Light light, int index, org.scilab.modules.graphic_objects.axes.Axes axes) {
+ Light sciLight = manager.getLight(index);
+ double[][] factors = axes.getScaleTranslateFactors();
+ Double[] coords = light.getLightTypeAsInteger() == 0 ? light.getDirection() : light.getPosition();
+ coords[0] = coords[0] * factors[0][0] + factors[1][0];
+ coords[1] = coords[1] * factors[0][1] + factors[1][1];
+ coords[2] = coords[2] * factors[0][2] + factors[1][2];
+
+ Double[] color = light.getAmbientColor();
+ sciLight.setAmbientColor(new Color(color[0].floatValue(), color[1].floatValue(), color[2].floatValue()));
+ color = light.getDiffuseColor();
+ sciLight.setDiffuseColor(new Color(color[0].floatValue(), color[1].floatValue(), color[2].floatValue()));
+ color = light.getSpecularColor();
+ sciLight.setSpecularColor(new Color(color[0].floatValue(), color[1].floatValue(), color[2].floatValue()));
+
+ if (light.getLightTypeAsInteger() == 0) {
+ sciLight.setDirection(new Vector3d(coords));
+ } else {
+ sciLight.setPosition(new Vector3d(coords));
+ }
+
+ sciLight.setEnable(true);
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/OutOfMemoryException.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/OutOfMemoryException.java
new file mode 100755
index 000000000..4bccba06c
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/OutOfMemoryException.java
@@ -0,0 +1,23 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.util;
+
+/**
+ * @author Pierre Lando
+ */
+@SuppressWarnings(value = { "serial" })
+public class OutOfMemoryException extends Exception {
+
+ public OutOfMemoryException() {
+ super("no more memory");
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/ScaleUtils.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/ScaleUtils.java
new file mode 100755
index 000000000..376678178
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/ScaleUtils.java
@@ -0,0 +1,131 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2012 - DIGITEO - Manuel JULIACHS
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.util;
+
+import org.scilab.forge.scirenderer.tranformations.Vector3d;
+
+/**
+ * Class ScaleUtils
+ * A set of utility methods for logarithmic scaling and unscaling.
+ *
+ * @author Manuel JULIACHS
+ */
+public class ScaleUtils {
+
+ /**
+ * Applies logarithmic scaling to a point and returns the result.
+ * @param point the point.
+ * @param logFlags the flags indicating whether scaling must be applied for respectively the x,y,z axes (3 elements).
+ * @return the transformed point.
+ */
+ public static Vector3d applyLogScale(Vector3d point, boolean[] logFlags) {
+ double[] coords = point.getData();
+
+ if (logFlags[0]) {
+ coords[0] = Math.log10(coords[0]);
+ }
+
+ if (logFlags[1]) {
+ coords[1] = Math.log10(coords[1]);
+ }
+
+ if (logFlags[2]) {
+ coords[2] = Math.log10(coords[2]);
+ }
+
+ return new Vector3d(coords);
+ }
+
+ /**
+ * Applies logarithmic scaling to a coords array.
+ * @param coords the coords (a 3-array).
+ * @param logFlags the flags indicating whether scaling must be applied for respectively the x,y,z axes (3 elements).
+ */
+ public static void applyLogScale(double[] coords, boolean[] logFlags) {
+ if (logFlags[0]) {
+ coords[0] = Math.log10(coords[0]);
+ }
+
+ if (logFlags[1]) {
+ coords[1] = Math.log10(coords[1]);
+ }
+
+ if (logFlags[2]) {
+ coords[2] = Math.log10(coords[2]);
+ }
+ }
+
+ /**
+ * Applies inverse logarithmic scaling to a point and returns the result.
+ * @param point the point.
+ * @param logFlags the flags indicating whether inverse scaling must be applied for respectively the x,y,z axes (3 elements).
+ * @return the transformed point.
+ */
+ public static Vector3d applyInverseLogScale(Vector3d point, boolean[] logFlags) {
+ double[] coords = point.getData();
+
+ if (logFlags[0]) {
+ coords[0] = Math.pow(10.0, coords[0]);
+ }
+
+ if (logFlags[1]) {
+ coords[1] = Math.pow(10.0, coords[1]);
+ }
+
+ if (logFlags[2]) {
+ coords[2] = Math.pow(10.0, coords[2]);
+ }
+
+ return new Vector3d(coords);
+ }
+
+ /**
+ * Applies inverse logarithmic scaling to a coords array.
+ * @param coords the coords (a 3-array).
+ * @param logFlags the flags indicating whether inverse scaling must be applied for respectively the x,y,z axes (3 elements).
+ */
+ public static void applyInverseLogScale(double[] coords, boolean[] logFlags) {
+ if (logFlags[0]) {
+ coords[0] = Math.pow(10.0, coords[0]);
+ }
+
+ if (logFlags[1]) {
+ coords[1] = Math.pow(10.0, coords[1]);
+ }
+
+ if (logFlags[2]) {
+ coords[2] = Math.pow(10.0, coords[2]);
+ }
+ }
+
+ /**
+ * Applies inverse logarithmic scaling to a bounds array.
+ * @param bounds the bounds (a 6-array).
+ * @param logFlags the flags indicating whether inverse scaling must be applied for respectively the x,y,z axes (3 elements).
+ */
+ public static void applyInverseLogScaleToBounds(Double[] bounds, boolean[] logFlags) {
+ if (logFlags[0]) {
+ bounds[0] = Math.pow(10, bounds[0]);
+ bounds[1] = Math.pow(10, bounds[1]);
+ }
+
+ if (logFlags[1]) {
+ bounds[2] = Math.pow(10, bounds[2]);
+ bounds[3] = Math.pow(10, bounds[3]);
+ }
+
+ if (logFlags[2]) {
+ bounds[4] = Math.pow(10, bounds[4]);
+ bounds[5] = Math.pow(10, bounds[5]);
+ }
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/TextObjectSpriteDrawer.java b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/TextObjectSpriteDrawer.java
new file mode 100755
index 000000000..46227968e
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/util/TextObjectSpriteDrawer.java
@@ -0,0 +1,405 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Pierre Lando
+ * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ */
+
+package org.scilab.modules.renderer.JoGLView.util;
+
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.font.TextLayout;
+import java.awt.geom.Rectangle2D;
+
+import javax.swing.Icon;
+
+import org.scilab.forge.jlatexmath.TeXConstants;
+import org.scilab.forge.jlatexmath.TeXFormula;
+import org.scilab.forge.jlatexmath.TeXIcon;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.appearance.Color;
+import org.scilab.forge.scirenderer.texture.TextEntity;
+import org.scilab.forge.scirenderer.texture.TextureDrawer;
+import org.scilab.forge.scirenderer.texture.TextureDrawingTools;
+import org.scilab.modules.console.utils.ScilabSpecialTextUtilities;
+import org.scilab.modules.graphic_objects.figure.ColorMap;
+import org.scilab.modules.graphic_objects.textObject.Text;
+import org.scilab.modules.graphic_objects.textObject.TextObject;
+import org.scilab.modules.jvm.LoadClassPath;
+import org.scilab.modules.renderer.utils.textRendering.FontManager;
+
+/**
+ * A {@see SpriteDrawer} who draw a Scilab {@see Text} object.
+ * @author Pierre Lando
+ */
+public class TextObjectSpriteDrawer implements TextureDrawer {
+
+ /**
+ * Scilab text margin.
+ */
+ private static final int HMARGIN = 2;
+ private static final int VMARGIN = 2;
+ private static final int SPACEWIDTH = (int) Math.ceil(new TextEntity("_").getSize().getWidth()) - 2;
+
+ private Appearance appearance;
+ private int thickness;
+ private final Object[][] entities;
+ private float alignmentFactor;
+
+ private final int[] lineHeight;
+ private final int[] columnWidth;
+ private final float[] lineAscent;
+
+ private final int width;
+ private final int height;
+
+ private boolean latexSet = false;
+ private boolean mathmlSet = false;
+
+ /**
+ * Default constructor.
+ * @param colorMap the color map to use.
+ * @param textObject the scilab {@see Text} to draw.
+ */
+ public TextObjectSpriteDrawer(final ColorMap colorMap, final TextObject textObject) {
+ String[][] stringArray = computeTextData(textObject);
+ int columnNumber = -1;
+ for (String[] stringLine : stringArray) {
+ columnNumber = Math.max(stringLine.length, columnNumber);
+ }
+ int lineNumber = stringArray.length;
+
+ this.lineHeight = new int[lineNumber];
+ this.lineAscent = new float[lineNumber];
+ this.columnWidth = new int[columnNumber];
+ this.entities = new Object[columnNumber][lineNumber];
+
+ boolean fractionalFont = textObject.getFontFractional();
+ Color textColor = ColorFactory.createColor(colorMap, textObject.getFont().getColor());
+ Font font = computeFont(textObject);
+
+ loadDeps(stringArray);
+ fillEntityMatrix(stringArray, fractionalFont, textColor, font);
+
+ this.width = sum(columnWidth) + HMARGIN * (columnNumber + 1) + 2 * thickness + SPACEWIDTH * (columnNumber - 1);
+ this.height = sum(lineHeight) + VMARGIN * (lineNumber + 1) + 2 * thickness;
+ }
+
+ /**
+ * Constructor.
+ * Specifies a scale factor used to scale the text matrix.
+ * @param colorMap the color map to used.
+ * @param textObject the scilab {@see TextObject} to draw.
+ * @param scaleFactor the scale factor to apply.
+ */
+ public TextObjectSpriteDrawer(final ColorMap colorMap, final TextObject textObject, double scaleFactor) {
+ String[][] stringArray = computeTextData(textObject);
+ int columnNumber = -1;
+ for (String[] stringLine : stringArray) {
+ columnNumber = Math.max(stringLine.length, columnNumber);
+ }
+ int lineNumber = stringArray.length;
+
+ this.lineHeight = new int[lineNumber];
+ this.lineAscent = new float[lineNumber];
+ this.columnWidth = new int[columnNumber];
+ this.entities = new Object[columnNumber][lineNumber];
+
+ boolean fractionalFont = textObject.getFontFractional();
+ Color textColor = ColorFactory.createColor(colorMap, textObject.getFont().getColor());
+ Font font = computeFont(textObject, scaleFactor);
+
+ /* Fill the entity matrix */
+ loadDeps(stringArray);
+ fillEntityMatrix(stringArray, fractionalFont, textColor, font);
+
+ this.width = (int)((double)sum(columnWidth) + scaleFactor * (double)(HMARGIN * (columnNumber + 1)) + 2 * thickness + scaleFactor * (double)(SPACEWIDTH * (columnNumber - 1)));
+ this.height = (int)((double)sum(lineHeight) + scaleFactor * (double)(VMARGIN * (lineNumber + 1)) + 2 * thickness);
+ }
+
+ /**
+ * Load JLaTeXMath or JEuclid if mandatory
+ * @param stringArray the text to check
+ */
+ protected void loadDeps(String[][] stringArray) {
+ loop: {
+ for (String[] textLine : stringArray) {
+ for (String text : textLine) {
+ if (text != null) {
+ if (!latexSet && isLatex(text)) {
+ latexSet = true;
+ LoadClassPath.loadOnUse("graphics_latex_textrendering");
+ } else if (!mathmlSet && isMathML(text)) {
+ LoadClassPath.loadOnUse("graphics_mathml_textrendering");
+ } else if (latexSet && mathmlSet) {
+ break loop;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Fills the entity matrix
+ * @param stringArray the matrix of text strings used to fill the entity matrix.
+ * @param fractionalFont specifies whether a fractional font is used or not.
+ * @param textColor the text color.
+ * @param font the font to use.
+ */
+ protected void fillEntityMatrix(String[][] stringArray, boolean fractionalFont, Color textColor, Font font) {
+ int line = 0;
+ for (String[] textLine : stringArray) {
+ int column = 0;
+ for (String text : textLine) {
+ if (text != null) {
+ Dimension dimension = null;
+ Icon icon = null;
+ float ascent = 0;
+ if (isLatex(text)) {
+ try {
+ TeXFormula formula = new TeXFormula(text.substring(1, text.length() - 1));
+ formula.setColor(textColor);
+ icon = formula.createTeXIcon(TeXConstants.STYLE_DISPLAY, font.getSize());
+ ascent = ((TeXIcon) icon).getIconHeight() - ((TeXIcon) icon).getIconDepth();
+ } catch (Exception e) { }
+ } else if (isMathML(text)) {
+ try {
+ icon = ScilabSpecialTextUtilities.compileMathMLExpression(text, font.getSize(), textColor);
+ ScilabSpecialTextUtilities.SpecialIcon si = (ScilabSpecialTextUtilities.SpecialIcon) icon;
+ ascent = si.getIconHeight() - si.getIconDepth();
+ } catch (Exception e) { }
+ }
+
+ if (icon != null) {
+ dimension = new Dimension(icon.getIconWidth(), icon.getIconHeight());
+ entities[column][line] = icon;
+ } else {
+ TextEntity textEntity = new TextEntity(text);
+ textEntity.setTextUseFractionalMetrics(fractionalFont);
+ textEntity.setTextAntiAliased(true);
+ textEntity.setTextColor(textColor);
+ textEntity.setFont(font);
+ entities[column][line] = textEntity;
+ dimension = textEntity.getSize();
+ ascent = textEntity.isValid() ? textEntity.getLayout().getAscent() : 0;
+ }
+
+ lineAscent[line] = Math.max(lineAscent[line], ascent);
+
+ if (dimension != null) {
+ columnWidth[column] = Math.max(columnWidth[column], dimension.width);
+ lineHeight[line] = Math.max(lineHeight[line], dimension.height);
+ }
+ }
+ column++;
+ }
+ line++;
+ }
+ }
+
+ /**
+ * Return true if the given string represent a latex entity.
+ * @param string the given string.
+ * @return true if the given string represent a latex entity.
+ */
+ private boolean isLatex(String string) {
+ return (string.length() >= 2) && string.endsWith("$") && string.startsWith("$");
+ }
+
+ /**
+ * Return true if the given string represent a MathML entity.
+ * @param string the given string.
+ * @return true if the given string represent a MathML entity.
+ */
+ private boolean isMathML(String string) {
+ return (string.length() >= 2) && string.endsWith(">") && string.startsWith("<");
+ }
+
+ @Override
+ public void draw(TextureDrawingTools drawingTools) {
+ // Draw background.
+ if (appearance.getFillColor().getAlphaAsFloat() != 0) {
+ drawingTools.clear(appearance.getFillColor());
+ }
+
+ final int currentHMargin = getHMargin();
+ final int currentVMargin = getVMargin();
+ final int currentSpaceWidth = getSpaceWidth();
+
+ // Draw text.
+ int x = currentHMargin + thickness;
+ int column = 0;
+ for (Object[] entitiesLine : entities) {
+ int y = currentVMargin + thickness;
+ int line = 0;
+ for (Object entity : entitiesLine) {
+ if (entity != null) {
+ if (entity instanceof TextEntity) {
+ TextEntity textEntity = (TextEntity) entity;
+ float ascent = textEntity.isValid() ? textEntity.getLayout().getAscent() : 0.f;
+ double deltaX = alignmentFactor * (columnWidth[column] - textEntity.getSize().getWidth());
+ drawingTools.draw(textEntity, (int) (x + deltaX), Math.round(y - ascent + lineAscent[line]));
+ y += lineHeight[line] + currentVMargin;
+ line++;
+ } else if (entity instanceof Icon) {
+ Icon icon = (Icon) entity;
+ double deltaX = alignmentFactor * (columnWidth[column] - icon.getIconWidth());
+ if (latexSet && (icon instanceof TeXIcon)) {
+ TeXIcon tex = (TeXIcon) icon;
+ float ascent = tex.getIconHeight() - tex.getIconDepth();
+ drawingTools.draw(icon, (int) (x + deltaX), Math.round(y - ascent + lineAscent[line]));
+ } else {
+ // MathML
+ ScilabSpecialTextUtilities.SpecialIcon si = (ScilabSpecialTextUtilities.SpecialIcon) icon;
+ int ascent = si.getIconHeight() - si.getIconDepth();
+ drawingTools.draw(icon, (int) (x + deltaX), y - ascent + Math.round(lineAscent[line]));
+ }
+ y += lineHeight[line] + currentVMargin;
+ line++;
+ }
+ }
+ }
+ x += columnWidth[column] + currentHMargin + currentSpaceWidth;
+ column++;
+ }
+
+ // Draw border lines.
+ if (appearance.getLineWidth() > 0) {
+ float hlw = appearance.getLineWidth() / 2;
+ int x1 = (int) hlw;
+ int y1 = (int) hlw;
+ int x2 = (int) (width - hlw);
+ int y2 = (int) (height - hlw);
+ drawingTools.drawPolyline(new int[] {x1, y1, x2, y1, x2, y2, x1, y2, x1, y1}, appearance);
+ }
+ }
+
+ @Override
+ public OriginPosition getOriginPosition() {
+ return OriginPosition.UPPER_LEFT;
+ }
+
+ @Override
+ public Dimension getTextureSize() {
+ return new Dimension(width, height);
+ }
+
+ /**
+ * Return the sprite width needed by this drawer.
+ * @return the sprite width needed by this drawer.
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * Return the sprite height needed by this drawer.
+ * @return the sprite height needed by this drawer.
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ protected void setAlignmentFactor(float alignmentFactor) {
+ this.alignmentFactor = alignmentFactor;
+ }
+
+ protected void setAppearance(Appearance appearance) {
+ this.appearance = appearance;
+ }
+
+ protected void setThickness(int thickness) {
+ this.thickness = thickness;
+ }
+
+ public int getHMargin() {
+ return HMARGIN;
+ }
+
+ public int getVMargin() {
+ return VMARGIN;
+ }
+
+ public int getSpaceWidth() {
+ return SPACEWIDTH;
+ }
+
+ /**
+ * Compute and return the matrix of text string from the given {@see Text} object.
+ * @param text the given {@see Text} object.
+ * @return the matrix of text string from the given {@see Text} object.
+ */
+ protected String[][] computeTextData(final TextObject text) {
+ String[] textString = text.getTextStrings();
+ Integer[] dimensions = text.getTextArrayDimensions();
+ String[][] texts = new String[dimensions[0]][dimensions[1]];
+ int i = 0;
+ for (int c = 0; c < dimensions[1]; c++) {
+ for (int l = 0; l < dimensions[0]; l++) {
+ texts[l][c] = textString[i];
+ i++;
+ }
+ }
+ return texts;
+ }
+
+ /**
+ * Compute and return the {@see Font} adapted to the given scilab text.
+ * @param text the given scilab text.
+ * @return the {@see Font} adapted to the given scilab text.
+ */
+ private Font computeFont(final TextObject text) {
+ return FontManager.getSciFontManager().getFontFromIndex(text.getFontStyle(), text.getFontSize());
+ }
+
+ /**
+ * Computes and returns the {@link Font} adapted to the given Scilab text, taking into account the scale factor.
+ * It takes the size 1 Font to derive a new Font whose size is increased according to the scale factor.
+ * @param text the given {@see Text} object.
+ * @param scaleFactor the scale factor to apply.
+ * @return the {@see Font} adapted to the given Scilab text.
+ */
+ private Font computeFont(final TextObject text, double scaleFactor) {
+ Font font = FontManager.getSciFontManager().getFontFromIndex(text.getFontStyle(), 1.0);
+ return font.deriveFont(font.getSize2D() * (float)scaleFactor);
+ }
+
+ /**
+ * Compute and return the alignment factor corresponding to the given scilab text.
+ * @param text the given scilab text.
+ * @return the alignment factor corresponding to the given scilab text.
+ */
+ protected float computeAlignmentFactor(Text text) {
+ switch (text.getAlignmentAsEnum()) {
+ case LEFT:
+ return 0f;
+ case CENTER:
+ return 1f / 2f;
+ case RIGHT:
+ return 1f;
+ default:
+ return 0f;
+ }
+ }
+
+ /**
+ * Util function.
+ * Return sum of the element of the given array.
+ * @param values the given array.
+ * @return sum of the element of the given array.
+ */
+ private int sum(int[] values) {
+ int sum = 0;
+ for (int value : values) {
+ sum += value;
+ }
+ return sum;
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/utils/textRendering/FontManager.java b/modules/renderer/src/java/org/scilab/modules/renderer/utils/textRendering/FontManager.java
new file mode 100755
index 000000000..62a3ed41d
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/utils/textRendering/FontManager.java
@@ -0,0 +1,432 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2007 - INRIA - Jean-Baptiste Silvy
+ * Copyright (C) 2008 - INRIA - Allan CORNET
+ * desc : Singleton class used to set font of text objects
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+
+package org.scilab.modules.renderer.utils.textRendering;
+
+import java.io.FileInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.awt.Font;
+import java.awt.FontFormatException;
+import java.awt.GraphicsEnvironment;
+import java.util.ArrayList;
+
+/**
+ * Singleton class used to set font of text objects.
+ * @author Jean-Baptiste Silvy
+ */
+public class FontManager {
+
+ private static final String SCIDIR = System.getenv("SCI");
+ private static final float[] INTERVALS = {3.0f, 4.0f, 5.0f};
+ private static final float[] FIRST_POLY = {2.0f, 8.0f};
+ private static final float[] SECOND_POLY = {4.0f, 2.0f};
+ private static final float[] THIRD_POLY = {6.0f, -6.0f};
+ private static final float[] FOURTH_POLY = {10.0f, -26.0f};
+
+ private static final float SIX = 6.0f;
+
+ private static final float[] INV_INTERVALS = {14.0f, 18.0f, 24.0f};
+ private static final float[] INV_FIRST_POLY = {0.5f, -4.0f};
+ private static final float[] INV_SECOND_POLY = {0.25f, -0.5f};
+ private static final float[] INV_THIRD_POLY = {1.0f / SIX, 1.0f};
+ private static final float[] INV_FOURTH_POLY = {0.1f, 2.6f};
+
+
+ // logical awt fonts
+ // JRE Java guaranteed: "Dialog", "DialogInput",
+ // "Monospaced","Serif", "SansSerif", "Symbol", "Lucida"
+ // Scilab 4.x fonts --> fonts with JRE 1.5 or more
+ // Times --> Serif
+ // Helvetica --> SansSerif
+ // Courier --> Monospaced
+ // Symbol --> Scilab Symbols font
+
+ private static final String MONOSPACED = "Monospaced";
+ private static final String SANSSERIF = "SansSerif";
+ private static final String SERIF = "Serif";
+ private static final String SCILABSYMBOLSFONT = "ScilabSymbols";
+ private static final String SYMBOLSFONTPATH = "/thirdparty/fonts/scilabsymbols.ttf";
+ private static final Font DEFAULT_FONT = new Font("Default", Font.PLAIN, 1);
+
+ /** Singleton instance. */
+ private static final FontManager sciFontManager = new FontManager();
+
+ /**
+ * A list of fonts.
+ */
+ private static class FontList extends ArrayList<Font> {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Default constructor.
+ */
+ public FontList() {
+ super();
+ }
+ }
+
+ private static FontList sciFonts;
+
+ /**
+ * Default constructor.
+ * Should not be called.
+ */
+ private FontManager() {
+ initializeFontManager();
+ }
+
+ /**
+ * Get the font manager instance
+ * @return the only instance of fontmanager.
+ */
+ public static FontManager getSciFontManager() {
+ return sciFontManager;
+ }
+
+ /**
+ * Convert sciab font size to awt font size.
+ * We use a degree 2 polygon to compute this.
+ * We use canonical form of the polygon so the inverse function is easy to compute
+ * Tthe equivalence list is (0 => 8, 1 => 10, 2 => 12, 3 => 14, 4 => 18, 5 => 24).
+ * @param sciSize scilab size
+ * @return awt size
+ */
+ public static float scilabSizeToAwtSize(double sciSize) {
+ float sciSizef = (float) sciSize;
+ // f(x) = | 2x + 8 if x < 3
+ // | 4x + 2 if 3 < x < 4
+ // | 6x - 6 if 4 < x
+ if (sciSizef < INTERVALS[0]) {
+ return FIRST_POLY[0] * sciSizef + FIRST_POLY[1];
+ } else if (sciSizef < INTERVALS[1]) {
+ return SECOND_POLY[0] * sciSizef + SECOND_POLY[1];
+ } else if (sciSizef < INTERVALS[2]) {
+ return THIRD_POLY[0] * sciSizef + THIRD_POLY[1];
+ } else {
+ return FOURTH_POLY[0] * sciSizef + FOURTH_POLY[1];
+ }
+ }
+
+ /**
+ * Inverse of scilabSizeToAwtSize function
+ * @param size size of a AWT font
+ * @return corresponding size in Scilab
+ */
+ public static double awtSizeToScilabSize(float size) {
+ // sqrt(|x - c| / a) - b
+ if (size < INV_INTERVALS[0]) {
+ return INV_FIRST_POLY[0] * size + INV_FIRST_POLY[1];
+ } else if (size < INV_INTERVALS[1]) {
+ return INV_SECOND_POLY[0] * size + INV_SECOND_POLY[1];
+ } else if (size < INV_INTERVALS[2]) {
+ return INV_THIRD_POLY[0] * size + INV_THIRD_POLY[1];
+ } else {
+ return INV_FOURTH_POLY[0] * size + INV_FOURTH_POLY[1];
+ }
+ }
+
+ /**
+ * Get a font from its index in Scilab.
+ * @param fontIndex scilab index of the font.
+ * @return font corresponding to the index with size 1.
+ */
+ public final Font getFontFromIndex(int fontIndex) {
+ if (fontIndex >= 0 && fontIndex < sciFonts.size()) {
+ return sciFonts.get(fontIndex);
+ } else if (fontIndex < 0) {
+ return sciFonts.get(0);
+ } else {
+ return sciFonts.get(sciFonts.size() - 1);
+ }
+ }
+
+ /**
+ * Get a font from its index in Scilab.
+ * @param fontIndex scilab index of the font.
+ * @param fontSize size of the font (scilab size).
+ * @return font corresponding to the index.
+ */
+ public final Font getFontFromIndex(int fontIndex, double fontSize) {
+ Font res = getFontFromIndex(fontIndex);
+ return res.deriveFont(scilabSizeToAwtSize(fontSize));
+ }
+ /**
+ * Add a new font in the font list.
+ * @param newFont font to add to the list
+ * @return index of added font.
+ */
+ public final int addFont(Font newFont) {
+ sciFonts.add(newFont);
+ return sciFonts.size() - 1;
+ }
+
+ /**
+ * Replace a font in the font list by a new one.
+ * @param index index of the font to replace
+ * @param newFont font to add in the font list.
+ * @return index of the added font or -1 if an error occurred.
+ */
+ public final int changeFont(int index, Font newFont) {
+ int nbFonts = sciFonts.size();
+ if (index > nbFonts) {
+ // we need to add fonts until index
+ for (int i = nbFonts; i < index; i++) {
+ addFont(DEFAULT_FONT);
+ }
+ return addFont(newFont);
+ } else if (index == nbFonts) {
+ // add a new Font
+ return addFont(newFont);
+ } else {
+ sciFonts.set(index, newFont);
+ return index;
+ }
+
+ }
+
+ /**
+ * Create a new font knowing its name and size.
+ * @param fontName Name of the font.
+ * @return new font.
+ */
+ protected final Font createFont(String fontName) {
+ // size must be applied after.
+ // by default, we use PLAIN font.
+ return new Font(fontName, Font.PLAIN, 1);
+ }
+
+ /**
+ * Load scilab symbols font
+ * @return font.
+ */
+ protected final Font loadScilabSymbolFont() {
+ return loadFont(SCIDIR + SYMBOLSFONTPATH);
+ }
+
+ /**
+ * load a font from filename
+ * @param fontFileName filename of the font.
+ * @return font.
+ */
+ protected final Font loadFont(String fontFileName) {
+ Font loadedFont;
+ FileInputStream in;
+ File f = new File(fontFileName);
+ try {
+ in = new FileInputStream(f);
+ } catch (FileNotFoundException e) {
+ loadedFont = DEFAULT_FONT;
+ return loadedFont;
+ }
+
+ try {
+ loadedFont = Font.createFont(Font.TRUETYPE_FONT, in);
+ } catch (IOException e) {
+ loadedFont = DEFAULT_FONT;
+ } catch (FontFormatException ffe) {
+ loadedFont = DEFAULT_FONT;
+ }
+
+ return loadedFont;
+ }
+
+ /**
+ * Create a new font knowing its name and size.
+ * @param fontName Name of the font.
+ * @param isBold wether the font is bold or not.
+ * @param isItalic wether the font is in italic or not.
+ * @return new font.
+ */
+ protected final Font createFont(String fontName, boolean isBold, boolean isItalic) {
+ int style;
+ if (isBold && isItalic) {
+ style = Font.BOLD | Font.ITALIC;
+ } else if (isBold) {
+ style = Font.BOLD;
+ } else if (isItalic) {
+ style = Font.ITALIC;
+ } else {
+ style = Font.PLAIN;
+ }
+ return new Font(fontName, style, 1);
+ }
+
+ /**
+ * Add a new font from its font name.
+ * @param fontName name of the font to add.
+ * @return index of the added font.
+ */
+ public final int addFont(String fontName) {
+ return addFont(createFont(fontName));
+ }
+
+ /**
+ * Add a new font from its font name.
+ * @param fontName name of the font to add.
+ * @param isBold wether the font is bold or not.
+ * @param isItalic wether the font is in italic or not.
+ * @return index of the added font.
+ */
+ public final int addFont(String fontName, boolean isBold, boolean isItalic) {
+ return addFont(createFont(fontName, isBold, isItalic));
+ }
+
+ /**
+ * Add a new font from its filename.
+ * @param fontFilename filename of the font to add.
+ * @return index of the added font.
+ */
+ public final int addFontFromFilename(String fontFilename) {
+ return addFont(loadFont(fontFilename));
+ }
+
+ /**
+ * Replace a font in the font list by a new one.
+ * @param index index of the font to replace
+ * @param fontName Name of the font.
+ * @return index of the added font or -1 if an error occurred.
+ */
+
+ public final int changeFont(int index, String fontName) {
+ return changeFont(index, createFont(fontName));
+ }
+
+ /**
+ * Replace a font in the font list by a new one loaded from a file.
+ * @param index index of the font to replace
+ * @param fontFilename filename of the font
+ * @return index of the added font or -1 if an error occurred.
+ */
+ public final int changeFontFromFilename(int index, String fontFilename) {
+ return changeFont(index, loadFont(fontFilename));
+ }
+
+ /**
+ * Replace a font in the font list by a new one.
+ * @param index index of the font to replace
+ * @param fontName Name of the font.
+ * @param isBold wether the font is bold or not.
+ * @param isItalic wether the font is in italic or not.
+ * @return index of the added font or -1 if an error occurred.
+ */
+ public final int changeFont(int index, String fontName, boolean isBold, boolean isItalic) {
+ return changeFont(index, createFont(fontName, isBold, isItalic));
+ }
+
+ /**
+ * Get the list of all fonts available.
+ * @return Names of the available fonts.
+ */
+ public final String[] getAvailableFontsName() {
+ return GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
+ }
+
+ /**
+ * Get the size of list of all fonts available.
+ * @return size.
+ */
+ public final int getSizeAvailableFontsName() {
+ return GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames().length;
+ }
+
+ /**
+ * Check if fontname is available
+ * @param fontname Name of the font.
+ * @return true or false.
+ */
+ public final boolean isAvailableFontName(String fontname) {
+ int i = getSizeAvailableFontsName();
+ String[] availableFontsName = getAvailableFontsName();
+ for (i = 0; i < availableFontsName.length; i++) {
+ if (fontname.compareTo(availableFontsName[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * returns fontnames installed (used) by scilab
+ * @return fonts name
+ */
+ public final String[] getInstalledFontsName() {
+ int nbFonts = sciFonts.size();
+ String[] fontnames = new String[nbFonts];
+
+ for (int i = 0; i < nbFonts; i++) {
+ Font res = getFontFromIndex(i);
+ fontnames[i] = res.getFamily();
+ if (res.isBold()) {
+ fontnames[i] += " Bold";
+ }
+ if (res.isItalic()) {
+ fontnames[i] += " Italic";
+ }
+ }
+
+ return fontnames;
+ }
+
+ /**
+ * Returns number of fonts installed.
+ * @return number of fonts installed.
+ */
+ public final int getSizeInstalledFontsName() {
+ return sciFonts.size();
+ }
+
+ /**
+ * initializeFontManager
+ */
+ public final void initializeFontManager() {
+ sciFonts = new FontList();
+ // set default font
+ /* Fonts order in Scilab 4.x for compatibility */
+ /* Courrier --> Monospaced
+ Symbol --> Symbol
+ Times --> Serif
+ Times Italic --> Serif Italic
+ Times Bold --> Serif Bold
+ Times Bold Italic --> Serif Bold Italic
+ Helvetica --> SansSerif
+ Helvetica Italic --> SansSerif Italic
+ Helvetica Bold --> SansSerif Bold
+ Helveticas Bold Italic --> SansSerif bold Italic
+ */
+
+ sciFonts.add(createFont(MONOSPACED)); /* scilab font_style 0 */
+ /* Symbols font */ /* scilab font_style 1 */
+ /* on scilab 4.x a --> alpha (symbol) */
+ /* with java , symbols are not ascii codes , but unicodes */
+ /* if font exists on system, we use else we try to load scilab symbols font (truetype) */
+ if (isAvailableFontName(SCILABSYMBOLSFONT)) {
+ sciFonts.add(createFont(SCILABSYMBOLSFONT));
+ } else {
+ sciFonts.add(loadScilabSymbolFont());
+ }
+ sciFonts.add(createFont(SERIF)); /* scilab font_style 2 */
+ sciFonts.add(createFont(SERIF, false, true)); /* scilab font_style 3 */
+ sciFonts.add(createFont(SERIF, true, false)); /* scilab font_style 4 */
+ sciFonts.add(createFont(SERIF, true, true)); /* scilab font_style 5 */
+ sciFonts.add(createFont(SANSSERIF)); /* scilab font_style 6 */
+ sciFonts.add(createFont(SANSSERIF, false, true)); /* scilab font_style 7 */
+ sciFonts.add(createFont(SANSSERIF, true, false)); /* scilab font_style 8 */
+ sciFonts.add(createFont(SANSSERIF, true, true)); /* scilab font_style 9 */
+ sciFonts.add(createFont(SANSSERIF, true, true)); /* scilab font_style 10 */
+ }
+}
diff --git a/modules/renderer/src/java/org/scilab/modules/renderer/utils/textRendering/XlFontManager.java b/modules/renderer/src/java/org/scilab/modules/renderer/utils/textRendering/XlFontManager.java
new file mode 100755
index 000000000..af733f09b
--- /dev/null
+++ b/modules/renderer/src/java/org/scilab/modules/renderer/utils/textRendering/XlFontManager.java
@@ -0,0 +1,130 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2008 - INRIA - Allan CORNET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.renderer.utils.textRendering;
+
+/**
+ * Class to manage FontManager with xlfont in scilab
+ * @author Allan CORNET
+ *
+ */
+
+public class XlFontManager {
+
+ private static FontManager sciFontManager;
+
+ /**
+ * default constructor
+ */
+ public XlFontManager() {
+ sciFontManager = FontManager.getSciFontManager();
+ }
+
+ /**
+ * Returns fonts name of available fonts on system
+ * @return array of string
+ */
+ public String[] getAvailableFontsName() {
+ return sciFontManager.getAvailableFontsName();
+ }
+
+ /**
+ * Returns number of available fonts
+ * @return number of available fonts
+ */
+ public int getSizeAvailableFontsName() {
+ return sciFontManager.getSizeAvailableFontsName();
+ }
+
+ /**
+ * Checks if font name is available
+ * @param fontname font name
+ * @return true or false
+ */
+ public boolean isAvailableFontName(String fontname) {
+ return sciFontManager.isAvailableFontName(fontname);
+ }
+
+ /**
+ * Returns fonts name installed
+ * @return array of String
+ */
+ public String[] getInstalledFontsName() {
+ return sciFontManager.getInstalledFontsName();
+ }
+
+ /**
+ * Returns number of installed fonts
+ * @return number of installed fonts
+ */
+ public int getSizeInstalledFontsName() {
+ return sciFontManager.getSizeInstalledFontsName();
+ }
+
+ /**
+ * add font
+ * @param fontName font name
+ * @return index
+ */
+ public int addFont(String fontName) {
+ return sciFontManager.addFont(fontName);
+ }
+
+ /**
+ * add font loaded from a filename
+ * @param fontFilename String filename
+ * @return index
+ */
+ public int addFontFromFilename(String fontFilename) {
+ return sciFontManager.addFontFromFilename(fontFilename);
+ }
+
+ /**
+ * Change Font
+ * @param index index of font to replace
+ * @param fontName font name
+ * @return index
+ */
+ public int changeFont(int index, String fontName) {
+ return sciFontManager.changeFont(index, fontName);
+ }
+
+ /**
+ * Change Font loaded from a filename
+ * @param index index of font to replace
+ * @param fontFilename filename
+ * @return index
+ */
+ public int changeFontFromFilename(int index, String fontFilename) {
+ return sciFontManager.changeFontFromFilename(index, fontFilename);
+ }
+
+ /**
+ * Change Font
+ * @param index index of font to replace
+ * @param fontName font name
+ * @param isBold true or false
+ * @param isItalic true or false
+ * @return index
+ */
+ public int changeFontWithProperty(int index, String fontName, boolean isBold, boolean isItalic) {
+ return sciFontManager.changeFont(index, fontName, isBold, isItalic);
+ }
+
+ /**
+ * reset XlFontManager with initial value
+ */
+ public void resetXlFontManager() {
+ sciFontManager.initializeFontManager();
+ }
+
+}
diff --git a/modules/renderer/src/jni/.deps/.dirstamp b/modules/renderer/src/jni/.deps/.dirstamp
new file mode 100755
index 000000000..e69de29bb
--- /dev/null
+++ b/modules/renderer/src/jni/.deps/.dirstamp
diff --git a/modules/renderer/src/jni/.deps/libscirenderer_la-CallRenderer.Plo b/modules/renderer/src/jni/.deps/libscirenderer_la-CallRenderer.Plo
new file mode 100755
index 000000000..5f43a3414
--- /dev/null
+++ b/modules/renderer/src/jni/.deps/libscirenderer_la-CallRenderer.Plo
@@ -0,0 +1,341 @@
+src/jni/libscirenderer_la-CallRenderer.lo: src/jni/CallRenderer.cpp \
+ /usr/include/stdc-predef.h src/jni/CallRenderer.hxx \
+ /usr/include/c++/5/iostream \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \
+ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+ /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \
+ /usr/include/c++/5/ostream /usr/include/c++/5/ios \
+ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \
+ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \
+ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \
+ /usr/include/x86_64-linux-gnu/bits/wchar.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \
+ /usr/include/x86_64-linux-gnu/bits/wchar2.h /usr/include/c++/5/exception \
+ /usr/include/c++/5/bits/atomic_lockfree_defines.h \
+ /usr/include/c++/5/bits/char_traits.h \
+ /usr/include/c++/5/bits/stl_algobase.h \
+ /usr/include/c++/5/bits/functexcept.h \
+ /usr/include/c++/5/bits/exception_defines.h \
+ /usr/include/c++/5/bits/cpp_type_traits.h \
+ /usr/include/c++/5/ext/type_traits.h \
+ /usr/include/c++/5/ext/numeric_traits.h \
+ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \
+ /usr/include/c++/5/bits/concept_check.h \
+ /usr/include/c++/5/bits/stl_iterator_base_types.h \
+ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \
+ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \
+ /usr/include/c++/5/bits/ptr_traits.h \
+ /usr/include/c++/5/bits/predefined_ops.h \
+ /usr/include/c++/5/bits/localefwd.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \
+ /usr/include/c++/5/clocale /usr/include/locale.h \
+ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \
+ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \
+ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \
+ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \
+ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \
+ /usr/include/x86_64-linux-gnu/bits/sched.h \
+ /usr/include/x86_64-linux-gnu/bits/time.h \
+ /usr/include/x86_64-linux-gnu/bits/timex.h \
+ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
+ /usr/include/x86_64-linux-gnu/bits/setjmp.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \
+ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \
+ /usr/include/c++/5/bits/allocator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \
+ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \
+ /usr/include/c++/5/bits/ostream_insert.h \
+ /usr/include/c++/5/bits/cxxabi_forced.h \
+ /usr/include/c++/5/bits/stl_function.h \
+ /usr/include/c++/5/backward/binders.h \
+ /usr/include/c++/5/bits/range_access.h \
+ /usr/include/c++/5/bits/basic_string.h \
+ /usr/include/c++/5/ext/alloc_traits.h \
+ /usr/include/c++/5/bits/basic_string.tcc \
+ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \
+ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \
+ /usr/include/c++/5/bits/basic_ios.h \
+ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \
+ /usr/include/wctype.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \
+ /usr/include/c++/5/bits/streambuf_iterator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \
+ /usr/include/c++/5/bits/locale_facets.tcc \
+ /usr/include/c++/5/bits/basic_ios.tcc \
+ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \
+ /usr/include/c++/5/bits/istream.tcc /usr/include/string.h \
+ /usr/include/x86_64-linux-gnu/bits/string3.h /usr/include/stdlib.h \
+ /usr/include/x86_64-linux-gnu/bits/waitflags.h \
+ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \
+ /usr/include/x86_64-linux-gnu/sys/types.h \
+ /usr/include/x86_64-linux-gnu/sys/select.h \
+ /usr/include/x86_64-linux-gnu/bits/select.h \
+ /usr/include/x86_64-linux-gnu/bits/sigset.h \
+ /usr/include/x86_64-linux-gnu/bits/select2.h \
+ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/jni.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio2.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h \
+ ../../modules/commons/src/jni/GiwsException.hxx
+
+/usr/include/stdc-predef.h:
+
+src/jni/CallRenderer.hxx:
+
+/usr/include/c++/5/iostream:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h:
+
+/usr/include/features.h:
+
+/usr/include/x86_64-linux-gnu/sys/cdefs.h:
+
+/usr/include/x86_64-linux-gnu/bits/wordsize.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h:
+
+/usr/include/c++/5/ostream:
+
+/usr/include/c++/5/ios:
+
+/usr/include/c++/5/iosfwd:
+
+/usr/include/c++/5/bits/stringfwd.h:
+
+/usr/include/c++/5/bits/memoryfwd.h:
+
+/usr/include/c++/5/bits/postypes.h:
+
+/usr/include/c++/5/cwchar:
+
+/usr/include/wchar.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h:
+
+/usr/include/x86_64-linux-gnu/bits/wchar.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h:
+
+/usr/include/xlocale.h:
+
+/usr/include/x86_64-linux-gnu/bits/wchar2.h:
+
+/usr/include/c++/5/exception:
+
+/usr/include/c++/5/bits/atomic_lockfree_defines.h:
+
+/usr/include/c++/5/bits/char_traits.h:
+
+/usr/include/c++/5/bits/stl_algobase.h:
+
+/usr/include/c++/5/bits/functexcept.h:
+
+/usr/include/c++/5/bits/exception_defines.h:
+
+/usr/include/c++/5/bits/cpp_type_traits.h:
+
+/usr/include/c++/5/ext/type_traits.h:
+
+/usr/include/c++/5/ext/numeric_traits.h:
+
+/usr/include/c++/5/bits/stl_pair.h:
+
+/usr/include/c++/5/bits/move.h:
+
+/usr/include/c++/5/bits/concept_check.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_types.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_funcs.h:
+
+/usr/include/c++/5/debug/debug.h:
+
+/usr/include/c++/5/bits/stl_iterator.h:
+
+/usr/include/c++/5/bits/ptr_traits.h:
+
+/usr/include/c++/5/bits/predefined_ops.h:
+
+/usr/include/c++/5/bits/localefwd.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h:
+
+/usr/include/c++/5/clocale:
+
+/usr/include/locale.h:
+
+/usr/include/x86_64-linux-gnu/bits/locale.h:
+
+/usr/include/c++/5/cctype:
+
+/usr/include/ctype.h:
+
+/usr/include/x86_64-linux-gnu/bits/types.h:
+
+/usr/include/x86_64-linux-gnu/bits/typesizes.h:
+
+/usr/include/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap-16.h:
+
+/usr/include/c++/5/bits/ios_base.h:
+
+/usr/include/c++/5/ext/atomicity.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h:
+
+/usr/include/pthread.h:
+
+/usr/include/sched.h:
+
+/usr/include/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/sched.h:
+
+/usr/include/x86_64-linux-gnu/bits/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/timex.h:
+
+/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h:
+
+/usr/include/x86_64-linux-gnu/bits/setjmp.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h:
+
+/usr/include/c++/5/bits/locale_classes.h:
+
+/usr/include/c++/5/string:
+
+/usr/include/c++/5/bits/allocator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h:
+
+/usr/include/c++/5/ext/new_allocator.h:
+
+/usr/include/c++/5/new:
+
+/usr/include/c++/5/bits/ostream_insert.h:
+
+/usr/include/c++/5/bits/cxxabi_forced.h:
+
+/usr/include/c++/5/bits/stl_function.h:
+
+/usr/include/c++/5/backward/binders.h:
+
+/usr/include/c++/5/bits/range_access.h:
+
+/usr/include/c++/5/bits/basic_string.h:
+
+/usr/include/c++/5/ext/alloc_traits.h:
+
+/usr/include/c++/5/bits/basic_string.tcc:
+
+/usr/include/c++/5/bits/locale_classes.tcc:
+
+/usr/include/c++/5/stdexcept:
+
+/usr/include/c++/5/streambuf:
+
+/usr/include/c++/5/bits/streambuf.tcc:
+
+/usr/include/c++/5/bits/basic_ios.h:
+
+/usr/include/c++/5/bits/locale_facets.h:
+
+/usr/include/c++/5/cwctype:
+
+/usr/include/wctype.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h:
+
+/usr/include/c++/5/bits/streambuf_iterator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h:
+
+/usr/include/c++/5/bits/locale_facets.tcc:
+
+/usr/include/c++/5/bits/basic_ios.tcc:
+
+/usr/include/c++/5/bits/ostream.tcc:
+
+/usr/include/c++/5/istream:
+
+/usr/include/c++/5/bits/istream.tcc:
+
+/usr/include/string.h:
+
+/usr/include/x86_64-linux-gnu/bits/string3.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitflags.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitstatus.h:
+
+/usr/include/x86_64-linux-gnu/sys/types.h:
+
+/usr/include/x86_64-linux-gnu/sys/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/sigset.h:
+
+/usr/include/x86_64-linux-gnu/bits/select2.h:
+
+/usr/include/x86_64-linux-gnu/sys/sysmacros.h:
+
+/usr/include/alloca.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-float.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/jni.h:
+
+/usr/include/libio.h:
+
+/usr/include/_G_config.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio_lim.h:
+
+/usr/include/x86_64-linux-gnu/bits/sys_errlist.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio2.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h:
+
+../../modules/commons/src/jni/GiwsException.hxx:
diff --git a/modules/renderer/src/jni/.deps/libscirenderer_la-XlFontManager.Plo b/modules/renderer/src/jni/.deps/libscirenderer_la-XlFontManager.Plo
new file mode 100755
index 000000000..9fba859d0
--- /dev/null
+++ b/modules/renderer/src/jni/.deps/libscirenderer_la-XlFontManager.Plo
@@ -0,0 +1,341 @@
+src/jni/libscirenderer_la-XlFontManager.lo: src/jni/XlFontManager.cpp \
+ /usr/include/stdc-predef.h src/jni/XlFontManager.hxx \
+ /usr/include/c++/5/iostream \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h \
+ /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
+ /usr/include/x86_64-linux-gnu/bits/wordsize.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs.h \
+ /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h \
+ /usr/include/c++/5/ostream /usr/include/c++/5/ios \
+ /usr/include/c++/5/iosfwd /usr/include/c++/5/bits/stringfwd.h \
+ /usr/include/c++/5/bits/memoryfwd.h /usr/include/c++/5/bits/postypes.h \
+ /usr/include/c++/5/cwchar /usr/include/wchar.h /usr/include/stdio.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \
+ /usr/include/x86_64-linux-gnu/bits/wchar.h \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h /usr/include/xlocale.h \
+ /usr/include/x86_64-linux-gnu/bits/wchar2.h /usr/include/c++/5/exception \
+ /usr/include/c++/5/bits/atomic_lockfree_defines.h \
+ /usr/include/c++/5/bits/char_traits.h \
+ /usr/include/c++/5/bits/stl_algobase.h \
+ /usr/include/c++/5/bits/functexcept.h \
+ /usr/include/c++/5/bits/exception_defines.h \
+ /usr/include/c++/5/bits/cpp_type_traits.h \
+ /usr/include/c++/5/ext/type_traits.h \
+ /usr/include/c++/5/ext/numeric_traits.h \
+ /usr/include/c++/5/bits/stl_pair.h /usr/include/c++/5/bits/move.h \
+ /usr/include/c++/5/bits/concept_check.h \
+ /usr/include/c++/5/bits/stl_iterator_base_types.h \
+ /usr/include/c++/5/bits/stl_iterator_base_funcs.h \
+ /usr/include/c++/5/debug/debug.h /usr/include/c++/5/bits/stl_iterator.h \
+ /usr/include/c++/5/bits/ptr_traits.h \
+ /usr/include/c++/5/bits/predefined_ops.h \
+ /usr/include/c++/5/bits/localefwd.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h \
+ /usr/include/c++/5/clocale /usr/include/locale.h \
+ /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/5/cctype \
+ /usr/include/ctype.h /usr/include/x86_64-linux-gnu/bits/types.h \
+ /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/endian.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap.h \
+ /usr/include/x86_64-linux-gnu/bits/byteswap-16.h \
+ /usr/include/c++/5/bits/ios_base.h /usr/include/c++/5/ext/atomicity.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h \
+ /usr/include/pthread.h /usr/include/sched.h /usr/include/time.h \
+ /usr/include/x86_64-linux-gnu/bits/sched.h \
+ /usr/include/x86_64-linux-gnu/bits/time.h \
+ /usr/include/x86_64-linux-gnu/bits/timex.h \
+ /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
+ /usr/include/x86_64-linux-gnu/bits/setjmp.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h \
+ /usr/include/c++/5/bits/locale_classes.h /usr/include/c++/5/string \
+ /usr/include/c++/5/bits/allocator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h \
+ /usr/include/c++/5/ext/new_allocator.h /usr/include/c++/5/new \
+ /usr/include/c++/5/bits/ostream_insert.h \
+ /usr/include/c++/5/bits/cxxabi_forced.h \
+ /usr/include/c++/5/bits/stl_function.h \
+ /usr/include/c++/5/backward/binders.h \
+ /usr/include/c++/5/bits/range_access.h \
+ /usr/include/c++/5/bits/basic_string.h \
+ /usr/include/c++/5/ext/alloc_traits.h \
+ /usr/include/c++/5/bits/basic_string.tcc \
+ /usr/include/c++/5/bits/locale_classes.tcc /usr/include/c++/5/stdexcept \
+ /usr/include/c++/5/streambuf /usr/include/c++/5/bits/streambuf.tcc \
+ /usr/include/c++/5/bits/basic_ios.h \
+ /usr/include/c++/5/bits/locale_facets.h /usr/include/c++/5/cwctype \
+ /usr/include/wctype.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h \
+ /usr/include/c++/5/bits/streambuf_iterator.h \
+ /usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h \
+ /usr/include/c++/5/bits/locale_facets.tcc \
+ /usr/include/c++/5/bits/basic_ios.tcc \
+ /usr/include/c++/5/bits/ostream.tcc /usr/include/c++/5/istream \
+ /usr/include/c++/5/bits/istream.tcc /usr/include/string.h \
+ /usr/include/x86_64-linux-gnu/bits/string3.h /usr/include/stdlib.h \
+ /usr/include/x86_64-linux-gnu/bits/waitflags.h \
+ /usr/include/x86_64-linux-gnu/bits/waitstatus.h \
+ /usr/include/x86_64-linux-gnu/sys/types.h \
+ /usr/include/x86_64-linux-gnu/sys/select.h \
+ /usr/include/x86_64-linux-gnu/bits/select.h \
+ /usr/include/x86_64-linux-gnu/bits/sigset.h \
+ /usr/include/x86_64-linux-gnu/bits/select2.h \
+ /usr/include/x86_64-linux-gnu/sys/sysmacros.h /usr/include/alloca.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
+ /usr/include/x86_64-linux-gnu/bits/stdlib.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/jni.h /usr/include/libio.h \
+ /usr/include/_G_config.h /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
+ /usr/include/x86_64-linux-gnu/bits/sys_errlist.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio.h \
+ /usr/include/x86_64-linux-gnu/bits/stdio2.h \
+ /usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h \
+ ../../modules/commons/src/jni/GiwsException.hxx
+
+/usr/include/stdc-predef.h:
+
+src/jni/XlFontManager.hxx:
+
+/usr/include/c++/5/iostream:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++config.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/os_defines.h:
+
+/usr/include/features.h:
+
+/usr/include/x86_64-linux-gnu/sys/cdefs.h:
+
+/usr/include/x86_64-linux-gnu/bits/wordsize.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs.h:
+
+/usr/include/x86_64-linux-gnu/gnu/stubs-64.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/cpu_defines.h:
+
+/usr/include/c++/5/ostream:
+
+/usr/include/c++/5/ios:
+
+/usr/include/c++/5/iosfwd:
+
+/usr/include/c++/5/bits/stringfwd.h:
+
+/usr/include/c++/5/bits/memoryfwd.h:
+
+/usr/include/c++/5/bits/postypes.h:
+
+/usr/include/c++/5/cwchar:
+
+/usr/include/wchar.h:
+
+/usr/include/stdio.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h:
+
+/usr/include/x86_64-linux-gnu/bits/wchar.h:
+
+/usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h:
+
+/usr/include/xlocale.h:
+
+/usr/include/x86_64-linux-gnu/bits/wchar2.h:
+
+/usr/include/c++/5/exception:
+
+/usr/include/c++/5/bits/atomic_lockfree_defines.h:
+
+/usr/include/c++/5/bits/char_traits.h:
+
+/usr/include/c++/5/bits/stl_algobase.h:
+
+/usr/include/c++/5/bits/functexcept.h:
+
+/usr/include/c++/5/bits/exception_defines.h:
+
+/usr/include/c++/5/bits/cpp_type_traits.h:
+
+/usr/include/c++/5/ext/type_traits.h:
+
+/usr/include/c++/5/ext/numeric_traits.h:
+
+/usr/include/c++/5/bits/stl_pair.h:
+
+/usr/include/c++/5/bits/move.h:
+
+/usr/include/c++/5/bits/concept_check.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_types.h:
+
+/usr/include/c++/5/bits/stl_iterator_base_funcs.h:
+
+/usr/include/c++/5/debug/debug.h:
+
+/usr/include/c++/5/bits/stl_iterator.h:
+
+/usr/include/c++/5/bits/ptr_traits.h:
+
+/usr/include/c++/5/bits/predefined_ops.h:
+
+/usr/include/c++/5/bits/localefwd.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++locale.h:
+
+/usr/include/c++/5/clocale:
+
+/usr/include/locale.h:
+
+/usr/include/x86_64-linux-gnu/bits/locale.h:
+
+/usr/include/c++/5/cctype:
+
+/usr/include/ctype.h:
+
+/usr/include/x86_64-linux-gnu/bits/types.h:
+
+/usr/include/x86_64-linux-gnu/bits/typesizes.h:
+
+/usr/include/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/endian.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap.h:
+
+/usr/include/x86_64-linux-gnu/bits/byteswap-16.h:
+
+/usr/include/c++/5/bits/ios_base.h:
+
+/usr/include/c++/5/ext/atomicity.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/gthr-default.h:
+
+/usr/include/pthread.h:
+
+/usr/include/sched.h:
+
+/usr/include/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/sched.h:
+
+/usr/include/x86_64-linux-gnu/bits/time.h:
+
+/usr/include/x86_64-linux-gnu/bits/timex.h:
+
+/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h:
+
+/usr/include/x86_64-linux-gnu/bits/setjmp.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/atomic_word.h:
+
+/usr/include/c++/5/bits/locale_classes.h:
+
+/usr/include/c++/5/string:
+
+/usr/include/c++/5/bits/allocator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h:
+
+/usr/include/c++/5/ext/new_allocator.h:
+
+/usr/include/c++/5/new:
+
+/usr/include/c++/5/bits/ostream_insert.h:
+
+/usr/include/c++/5/bits/cxxabi_forced.h:
+
+/usr/include/c++/5/bits/stl_function.h:
+
+/usr/include/c++/5/backward/binders.h:
+
+/usr/include/c++/5/bits/range_access.h:
+
+/usr/include/c++/5/bits/basic_string.h:
+
+/usr/include/c++/5/ext/alloc_traits.h:
+
+/usr/include/c++/5/bits/basic_string.tcc:
+
+/usr/include/c++/5/bits/locale_classes.tcc:
+
+/usr/include/c++/5/stdexcept:
+
+/usr/include/c++/5/streambuf:
+
+/usr/include/c++/5/bits/streambuf.tcc:
+
+/usr/include/c++/5/bits/basic_ios.h:
+
+/usr/include/c++/5/bits/locale_facets.h:
+
+/usr/include/c++/5/cwctype:
+
+/usr/include/wctype.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_base.h:
+
+/usr/include/c++/5/bits/streambuf_iterator.h:
+
+/usr/include/x86_64-linux-gnu/c++/5/bits/ctype_inline.h:
+
+/usr/include/c++/5/bits/locale_facets.tcc:
+
+/usr/include/c++/5/bits/basic_ios.tcc:
+
+/usr/include/c++/5/bits/ostream.tcc:
+
+/usr/include/c++/5/istream:
+
+/usr/include/c++/5/bits/istream.tcc:
+
+/usr/include/string.h:
+
+/usr/include/x86_64-linux-gnu/bits/string3.h:
+
+/usr/include/stdlib.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitflags.h:
+
+/usr/include/x86_64-linux-gnu/bits/waitstatus.h:
+
+/usr/include/x86_64-linux-gnu/sys/types.h:
+
+/usr/include/x86_64-linux-gnu/sys/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/select.h:
+
+/usr/include/x86_64-linux-gnu/bits/sigset.h:
+
+/usr/include/x86_64-linux-gnu/bits/select2.h:
+
+/usr/include/x86_64-linux-gnu/sys/sysmacros.h:
+
+/usr/include/alloca.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib-float.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdlib.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/jni.h:
+
+/usr/include/libio.h:
+
+/usr/include/_G_config.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio_lim.h:
+
+/usr/include/x86_64-linux-gnu/bits/sys_errlist.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio.h:
+
+/usr/include/x86_64-linux-gnu/bits/stdio2.h:
+
+/usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h:
+
+../../modules/commons/src/jni/GiwsException.hxx:
diff --git a/modules/renderer/src/jni/.dirstamp b/modules/renderer/src/jni/.dirstamp
new file mode 100755
index 000000000..e69de29bb
--- /dev/null
+++ b/modules/renderer/src/jni/.dirstamp
diff --git a/modules/renderer/src/jni/.libs/libscirenderer_la-CallRenderer.o b/modules/renderer/src/jni/.libs/libscirenderer_la-CallRenderer.o
new file mode 100755
index 000000000..e2e6a1a9b
--- /dev/null
+++ b/modules/renderer/src/jni/.libs/libscirenderer_la-CallRenderer.o
Binary files differ
diff --git a/modules/renderer/src/jni/.libs/libscirenderer_la-XlFontManager.o b/modules/renderer/src/jni/.libs/libscirenderer_la-XlFontManager.o
new file mode 100755
index 000000000..b287875ee
--- /dev/null
+++ b/modules/renderer/src/jni/.libs/libscirenderer_la-XlFontManager.o
Binary files differ
diff --git a/modules/renderer/src/jni/CallRenderer.cpp b/modules/renderer/src/jni/CallRenderer.cpp
new file mode 100755
index 000000000..c0ac89400
--- /dev/null
+++ b/modules/renderer/src/jni/CallRenderer.cpp
@@ -0,0 +1,513 @@
+#include "CallRenderer.hxx"
+/* Generated by GIWS (version 2.0.2) with command:
+giws --disable-return-size-array --output-dir src/jni/ --throws-exception-on-error --description-file src/jni/renderer.giws.xml
+*/
+/*
+
+This is generated code.
+
+This software is a computer program whose purpose is to hide the complexity
+of accessing Java objects/methods from C++ code.
+
+This software is governed by the CeCILL-B license under French law and
+abiding by the rules of distribution of free software. You can use,
+modify and/ or redistribute the software under the terms of the CeCILL-B
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info".
+
+As a counterpart to the access to the source code and rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty and the software's author, the holder of the
+economic rights, and the successive licensors have only limited
+liability.
+
+In this respect, the user's attention is drawn to the risks associated
+with loading, using, modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean that it is complicated to manipulate, and that also
+therefore means that it is reserved for developers and experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or
+data to be ensured and, more generally, to use and operate it in the
+same conditions as regards security.
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL-B license and that you accept its terms.
+*/
+
+namespace org_scilab_modules_renderer {
+
+ // Static declarations (if any)
+
+// Returns the current env
+
+JNIEnv * CallRenderer::getCurrentEnv() {
+JNIEnv * curEnv = NULL;
+jint res=this->jvm->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+if (res != JNI_OK) {
+throw GiwsException::JniException(getCurrentEnv());
+}
+return curEnv;
+}
+// Destructor
+
+CallRenderer::~CallRenderer() {
+JNIEnv * curEnv = NULL;
+this->jvm->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+curEnv->DeleteGlobalRef(this->instance);
+curEnv->DeleteGlobalRef(this->instanceClass);
+}
+// Constructors
+CallRenderer::CallRenderer(JavaVM * jvm_) {
+jmethodID constructObject = NULL ;
+jobject localInstance ;
+jclass localClass ;
+
+const std::string construct="<init>";
+const std::string param="()V";
+jvm=jvm_;
+
+JNIEnv * curEnv = getCurrentEnv();
+
+localClass = curEnv->FindClass( this->className().c_str() ) ;
+if (localClass == NULL) {
+ throw GiwsException::JniClassNotFoundException(curEnv, this->className());
+}
+
+this->instanceClass = static_cast<jclass>(curEnv->NewGlobalRef(localClass));
+
+/* localClass is not needed anymore */
+curEnv->DeleteLocalRef(localClass);
+
+if (this->instanceClass == NULL) {
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+}
+
+
+constructObject = curEnv->GetMethodID( this->instanceClass, construct.c_str() , param.c_str() ) ;
+if(constructObject == NULL){
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+}
+
+localInstance = curEnv->NewObject( this->instanceClass, constructObject ) ;
+if(localInstance == NULL){
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+}
+
+this->instance = curEnv->NewGlobalRef(localInstance) ;
+if(this->instance == NULL){
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+}
+/* localInstance not needed anymore */
+curEnv->DeleteLocalRef(localInstance);
+
+ /* Methods ID set to NULL */
+voidstartInteractiveZoomjintintID=NULL;
+jdoubleArray_clickRubberBoxjintintjdoubleArray_doubledoubleID=NULL;
+jdoubleArray_dragRubberBoxjintintID=NULL;
+voidupdateTextBoundsjintintID=NULL;
+voidupdateSubwinScalejintintID=NULL;
+jdoubleArray_get2dViewCoordinatesjintintjdoubleArray_doubledoubleID=NULL;
+jdoubleArray_getPixelFrom2dViewCoordinatesjintintjdoubleArray_doubledoubleID=NULL;
+jdoubleArray_get2dViewFromPixelCoordinatesjintintjdoubleArray_doubledoubleID=NULL;
+jdoubleArray_getViewingAreajintintID=NULL;
+
+
+}
+
+CallRenderer::CallRenderer(JavaVM * jvm_, jobject JObj) {
+ jvm=jvm_;
+
+ JNIEnv * curEnv = getCurrentEnv();
+
+jclass localClass = curEnv->GetObjectClass(JObj);
+ this->instanceClass = static_cast<jclass>(curEnv->NewGlobalRef(localClass));
+ curEnv->DeleteLocalRef(localClass);
+
+ if (this->instanceClass == NULL) {
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+ }
+
+ this->instance = curEnv->NewGlobalRef(JObj) ;
+ if(this->instance == NULL){
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+ }
+ /* Methods ID set to NULL */
+ voidstartInteractiveZoomjintintID=NULL;
+jdoubleArray_clickRubberBoxjintintjdoubleArray_doubledoubleID=NULL;
+jdoubleArray_dragRubberBoxjintintID=NULL;
+voidupdateTextBoundsjintintID=NULL;
+voidupdateSubwinScalejintintID=NULL;
+jdoubleArray_get2dViewCoordinatesjintintjdoubleArray_doubledoubleID=NULL;
+jdoubleArray_getPixelFrom2dViewCoordinatesjintintjdoubleArray_doubledoubleID=NULL;
+jdoubleArray_get2dViewFromPixelCoordinatesjintintjdoubleArray_doubledoubleID=NULL;
+jdoubleArray_getViewingAreajintintID=NULL;
+
+
+}
+
+// Generic methods
+
+void CallRenderer::synchronize() {
+if (getCurrentEnv()->MonitorEnter(instance) != JNI_OK) {
+throw GiwsException::JniMonitorException(getCurrentEnv(), "CallRenderer");
+}
+}
+
+void CallRenderer::endSynchronize() {
+if ( getCurrentEnv()->MonitorExit(instance) != JNI_OK) {
+throw GiwsException::JniMonitorException(getCurrentEnv(), "CallRenderer");
+}
+}
+// Method(s)
+
+void CallRenderer::startInteractiveZoom (JavaVM * jvm_, int id){
+
+JNIEnv * curEnv = NULL;
+jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+jclass cls = initClass(curEnv);
+if ( cls == NULL) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+
+static jmethodID voidstartInteractiveZoomjintintID = curEnv->GetStaticMethodID(cls, "startInteractiveZoom", "(I)V" ) ;
+if (voidstartInteractiveZoomjintintID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "startInteractiveZoom");
+}
+
+ curEnv->CallStaticVoidMethod(cls, voidstartInteractiveZoomjintintID ,id);
+ if (curEnv->ExceptionCheck()) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+}
+
+double* CallRenderer::clickRubberBox (JavaVM * jvm_, int id, double const* startRectangle, int startRectangleSize){
+
+JNIEnv * curEnv = NULL;
+jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+jclass cls = initClass(curEnv);
+if ( cls == NULL) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+
+static jmethodID jdoubleArray_clickRubberBoxjintintjdoubleArray_doubledoubleID = curEnv->GetStaticMethodID(cls, "clickRubberBox", "(I[D)[D" ) ;
+if (jdoubleArray_clickRubberBoxjintintjdoubleArray_doubledoubleID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "clickRubberBox");
+}
+
+jdoubleArray startRectangle_ = curEnv->NewDoubleArray( startRectangleSize ) ;
+
+if (startRectangle_ == NULL)
+{
+// check that allocation succeed
+throw GiwsException::JniBadAllocException(curEnv);
+}
+
+curEnv->SetDoubleArrayRegion( startRectangle_, 0, startRectangleSize, (jdouble*)(startRectangle) ) ;
+
+
+ jdoubleArray res = static_cast<jdoubleArray>( curEnv->CallStaticObjectMethod(cls, jdoubleArray_clickRubberBoxjintintjdoubleArray_doubledoubleID ,id, startRectangle_));
+ if (res == NULL) { return NULL; }
+ if (curEnv->ExceptionCheck()) {
+throw GiwsException::JniCallMethodException(curEnv);
+}int lenRow;
+ lenRow = curEnv->GetArrayLength(res);
+jboolean isCopy = JNI_FALSE;
+
+/* GetPrimitiveArrayCritical is faster than getXXXArrayElements */
+jdouble *resultsArray = static_cast<jdouble *>(curEnv->GetPrimitiveArrayCritical(res, &isCopy));
+double* myArray= new double[ lenRow];
+
+for (jsize i = 0; i < lenRow; i++){
+myArray[i]=resultsArray[i];
+}
+curEnv->ReleasePrimitiveArrayCritical(res, resultsArray, JNI_ABORT);
+
+ curEnv->DeleteLocalRef(res);
+curEnv->DeleteLocalRef(startRectangle_);
+if (curEnv->ExceptionCheck()) {
+delete[] myArray;
+ throw GiwsException::JniCallMethodException(curEnv);
+}
+return myArray;
+
+}
+
+double* CallRenderer::dragRubberBox (JavaVM * jvm_, int id){
+
+JNIEnv * curEnv = NULL;
+jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+jclass cls = initClass(curEnv);
+if ( cls == NULL) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+
+static jmethodID jdoubleArray_dragRubberBoxjintintID = curEnv->GetStaticMethodID(cls, "dragRubberBox", "(I)[D" ) ;
+if (jdoubleArray_dragRubberBoxjintintID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "dragRubberBox");
+}
+
+ jdoubleArray res = static_cast<jdoubleArray>( curEnv->CallStaticObjectMethod(cls, jdoubleArray_dragRubberBoxjintintID ,id));
+ if (res == NULL) { return NULL; }
+ if (curEnv->ExceptionCheck()) {
+throw GiwsException::JniCallMethodException(curEnv);
+}int lenRow;
+ lenRow = curEnv->GetArrayLength(res);
+jboolean isCopy = JNI_FALSE;
+
+/* GetPrimitiveArrayCritical is faster than getXXXArrayElements */
+jdouble *resultsArray = static_cast<jdouble *>(curEnv->GetPrimitiveArrayCritical(res, &isCopy));
+double* myArray= new double[ lenRow];
+
+for (jsize i = 0; i < lenRow; i++){
+myArray[i]=resultsArray[i];
+}
+curEnv->ReleasePrimitiveArrayCritical(res, resultsArray, JNI_ABORT);
+
+ curEnv->DeleteLocalRef(res);
+if (curEnv->ExceptionCheck()) {
+delete[] myArray;
+ throw GiwsException::JniCallMethodException(curEnv);
+}
+return myArray;
+
+}
+
+void CallRenderer::updateTextBounds (JavaVM * jvm_, int id){
+
+JNIEnv * curEnv = NULL;
+jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+jclass cls = initClass(curEnv);
+if ( cls == NULL) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+
+static jmethodID voidupdateTextBoundsjintintID = curEnv->GetStaticMethodID(cls, "updateTextBounds", "(I)V" ) ;
+if (voidupdateTextBoundsjintintID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "updateTextBounds");
+}
+
+ curEnv->CallStaticVoidMethod(cls, voidupdateTextBoundsjintintID ,id);
+ if (curEnv->ExceptionCheck()) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+}
+
+void CallRenderer::updateSubwinScale (JavaVM * jvm_, int id){
+
+JNIEnv * curEnv = NULL;
+jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+jclass cls = initClass(curEnv);
+if ( cls == NULL) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+
+static jmethodID voidupdateSubwinScalejintintID = curEnv->GetStaticMethodID(cls, "updateSubwinScale", "(I)V" ) ;
+if (voidupdateSubwinScalejintintID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "updateSubwinScale");
+}
+
+ curEnv->CallStaticVoidMethod(cls, voidupdateSubwinScalejintintID ,id);
+ if (curEnv->ExceptionCheck()) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+}
+
+double* CallRenderer::get2dViewCoordinates (JavaVM * jvm_, int id, double const* coords, int coordsSize){
+
+JNIEnv * curEnv = NULL;
+jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+jclass cls = initClass(curEnv);
+if ( cls == NULL) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+
+static jmethodID jdoubleArray_get2dViewCoordinatesjintintjdoubleArray_doubledoubleID = curEnv->GetStaticMethodID(cls, "get2dViewCoordinates", "(I[D)[D" ) ;
+if (jdoubleArray_get2dViewCoordinatesjintintjdoubleArray_doubledoubleID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "get2dViewCoordinates");
+}
+
+jdoubleArray coords_ = curEnv->NewDoubleArray( coordsSize ) ;
+
+if (coords_ == NULL)
+{
+// check that allocation succeed
+throw GiwsException::JniBadAllocException(curEnv);
+}
+
+curEnv->SetDoubleArrayRegion( coords_, 0, coordsSize, (jdouble*)(coords) ) ;
+
+
+ jdoubleArray res = static_cast<jdoubleArray>( curEnv->CallStaticObjectMethod(cls, jdoubleArray_get2dViewCoordinatesjintintjdoubleArray_doubledoubleID ,id, coords_));
+ if (res == NULL) { return NULL; }
+ if (curEnv->ExceptionCheck()) {
+throw GiwsException::JniCallMethodException(curEnv);
+}int lenRow;
+ lenRow = curEnv->GetArrayLength(res);
+jboolean isCopy = JNI_FALSE;
+
+/* GetPrimitiveArrayCritical is faster than getXXXArrayElements */
+jdouble *resultsArray = static_cast<jdouble *>(curEnv->GetPrimitiveArrayCritical(res, &isCopy));
+double* myArray= new double[ lenRow];
+
+for (jsize i = 0; i < lenRow; i++){
+myArray[i]=resultsArray[i];
+}
+curEnv->ReleasePrimitiveArrayCritical(res, resultsArray, JNI_ABORT);
+
+ curEnv->DeleteLocalRef(res);
+curEnv->DeleteLocalRef(coords_);
+if (curEnv->ExceptionCheck()) {
+delete[] myArray;
+ throw GiwsException::JniCallMethodException(curEnv);
+}
+return myArray;
+
+}
+
+double* CallRenderer::getPixelFrom2dViewCoordinates (JavaVM * jvm_, int id, double const* coords, int coordsSize){
+
+JNIEnv * curEnv = NULL;
+jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+jclass cls = initClass(curEnv);
+if ( cls == NULL) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+
+static jmethodID jdoubleArray_getPixelFrom2dViewCoordinatesjintintjdoubleArray_doubledoubleID = curEnv->GetStaticMethodID(cls, "getPixelFrom2dViewCoordinates", "(I[D)[D" ) ;
+if (jdoubleArray_getPixelFrom2dViewCoordinatesjintintjdoubleArray_doubledoubleID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "getPixelFrom2dViewCoordinates");
+}
+
+jdoubleArray coords_ = curEnv->NewDoubleArray( coordsSize ) ;
+
+if (coords_ == NULL)
+{
+// check that allocation succeed
+throw GiwsException::JniBadAllocException(curEnv);
+}
+
+curEnv->SetDoubleArrayRegion( coords_, 0, coordsSize, (jdouble*)(coords) ) ;
+
+
+ jdoubleArray res = static_cast<jdoubleArray>( curEnv->CallStaticObjectMethod(cls, jdoubleArray_getPixelFrom2dViewCoordinatesjintintjdoubleArray_doubledoubleID ,id, coords_));
+ if (res == NULL) { return NULL; }
+ if (curEnv->ExceptionCheck()) {
+throw GiwsException::JniCallMethodException(curEnv);
+}int lenRow;
+ lenRow = curEnv->GetArrayLength(res);
+jboolean isCopy = JNI_FALSE;
+
+/* GetPrimitiveArrayCritical is faster than getXXXArrayElements */
+jdouble *resultsArray = static_cast<jdouble *>(curEnv->GetPrimitiveArrayCritical(res, &isCopy));
+double* myArray= new double[ lenRow];
+
+for (jsize i = 0; i < lenRow; i++){
+myArray[i]=resultsArray[i];
+}
+curEnv->ReleasePrimitiveArrayCritical(res, resultsArray, JNI_ABORT);
+
+ curEnv->DeleteLocalRef(res);
+curEnv->DeleteLocalRef(coords_);
+if (curEnv->ExceptionCheck()) {
+delete[] myArray;
+ throw GiwsException::JniCallMethodException(curEnv);
+}
+return myArray;
+
+}
+
+double* CallRenderer::get2dViewFromPixelCoordinates (JavaVM * jvm_, int id, double const* coords, int coordsSize){
+
+JNIEnv * curEnv = NULL;
+jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+jclass cls = initClass(curEnv);
+if ( cls == NULL) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+
+static jmethodID jdoubleArray_get2dViewFromPixelCoordinatesjintintjdoubleArray_doubledoubleID = curEnv->GetStaticMethodID(cls, "get2dViewFromPixelCoordinates", "(I[D)[D" ) ;
+if (jdoubleArray_get2dViewFromPixelCoordinatesjintintjdoubleArray_doubledoubleID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "get2dViewFromPixelCoordinates");
+}
+
+jdoubleArray coords_ = curEnv->NewDoubleArray( coordsSize ) ;
+
+if (coords_ == NULL)
+{
+// check that allocation succeed
+throw GiwsException::JniBadAllocException(curEnv);
+}
+
+curEnv->SetDoubleArrayRegion( coords_, 0, coordsSize, (jdouble*)(coords) ) ;
+
+
+ jdoubleArray res = static_cast<jdoubleArray>( curEnv->CallStaticObjectMethod(cls, jdoubleArray_get2dViewFromPixelCoordinatesjintintjdoubleArray_doubledoubleID ,id, coords_));
+ if (res == NULL) { return NULL; }
+ if (curEnv->ExceptionCheck()) {
+throw GiwsException::JniCallMethodException(curEnv);
+}int lenRow;
+ lenRow = curEnv->GetArrayLength(res);
+jboolean isCopy = JNI_FALSE;
+
+/* GetPrimitiveArrayCritical is faster than getXXXArrayElements */
+jdouble *resultsArray = static_cast<jdouble *>(curEnv->GetPrimitiveArrayCritical(res, &isCopy));
+double* myArray= new double[ lenRow];
+
+for (jsize i = 0; i < lenRow; i++){
+myArray[i]=resultsArray[i];
+}
+curEnv->ReleasePrimitiveArrayCritical(res, resultsArray, JNI_ABORT);
+
+ curEnv->DeleteLocalRef(res);
+curEnv->DeleteLocalRef(coords_);
+if (curEnv->ExceptionCheck()) {
+delete[] myArray;
+ throw GiwsException::JniCallMethodException(curEnv);
+}
+return myArray;
+
+}
+
+double* CallRenderer::getViewingArea (JavaVM * jvm_, int id){
+
+JNIEnv * curEnv = NULL;
+jvm_->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+jclass cls = initClass(curEnv);
+if ( cls == NULL) {
+throw GiwsException::JniCallMethodException(curEnv);
+}
+
+static jmethodID jdoubleArray_getViewingAreajintintID = curEnv->GetStaticMethodID(cls, "getViewingArea", "(I)[D" ) ;
+if (jdoubleArray_getViewingAreajintintID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "getViewingArea");
+}
+
+ jdoubleArray res = static_cast<jdoubleArray>( curEnv->CallStaticObjectMethod(cls, jdoubleArray_getViewingAreajintintID ,id));
+ if (res == NULL) { return NULL; }
+ if (curEnv->ExceptionCheck()) {
+throw GiwsException::JniCallMethodException(curEnv);
+}int lenRow;
+ lenRow = curEnv->GetArrayLength(res);
+jboolean isCopy = JNI_FALSE;
+
+/* GetPrimitiveArrayCritical is faster than getXXXArrayElements */
+jdouble *resultsArray = static_cast<jdouble *>(curEnv->GetPrimitiveArrayCritical(res, &isCopy));
+double* myArray= new double[ lenRow];
+
+for (jsize i = 0; i < lenRow; i++){
+myArray[i]=resultsArray[i];
+}
+curEnv->ReleasePrimitiveArrayCritical(res, resultsArray, JNI_ABORT);
+
+ curEnv->DeleteLocalRef(res);
+if (curEnv->ExceptionCheck()) {
+delete[] myArray;
+ throw GiwsException::JniCallMethodException(curEnv);
+}
+return myArray;
+
+}
+
+}
diff --git a/modules/renderer/src/jni/CallRenderer.hxx b/modules/renderer/src/jni/CallRenderer.hxx
new file mode 100755
index 000000000..0cf761ff0
--- /dev/null
+++ b/modules/renderer/src/jni/CallRenderer.hxx
@@ -0,0 +1,202 @@
+/* Generated by GIWS (version 2.0.2) with command:
+giws --disable-return-size-array --output-dir src/jni/ --throws-exception-on-error --description-file src/jni/renderer.giws.xml
+*/
+/*
+
+This is generated code.
+
+This software is a computer program whose purpose is to hide the complexity
+of accessing Java objects/methods from C++ code.
+
+This software is governed by the CeCILL-B license under French law and
+abiding by the rules of distribution of free software. You can use,
+modify and/ or redistribute the software under the terms of the CeCILL-B
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info".
+
+As a counterpart to the access to the source code and rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty and the software's author, the holder of the
+economic rights, and the successive licensors have only limited
+liability.
+
+In this respect, the user's attention is drawn to the risks associated
+with loading, using, modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean that it is complicated to manipulate, and that also
+therefore means that it is reserved for developers and experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or
+data to be ensured and, more generally, to use and operate it in the
+same conditions as regards security.
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL-B license and that you accept its terms.
+*/
+
+
+#ifndef __ORG_SCILAB_MODULES_RENDERER_CALLRENDERER__
+#define __ORG_SCILAB_MODULES_RENDERER_CALLRENDERER__
+#include <iostream>
+#include <string>
+#include <string.h>
+#include <stdlib.h>
+#include <jni.h>
+
+#include "GiwsException.hxx"
+
+ #if defined(_MSC_VER) /* Defined anyway with Visual */
+ #include <Windows.h>
+ #else
+ typedef signed char byte;
+ #endif
+
+
+#ifndef GIWSEXPORT
+# if defined(_MSC_VER) || defined(__WIN32__) || defined(__CYGWIN__)
+# if defined(STATIC_LINKED)
+# define GIWSEXPORT
+# else
+# define GIWSEXPORT __declspec(dllexport)
+# endif
+# else
+# if __GNUC__ >= 4
+# define GIWSEXPORT __attribute__ ((visibility ("default")))
+# else
+# define GIWSEXPORT
+# endif
+# endif
+#endif
+
+namespace org_scilab_modules_renderer {
+class GIWSEXPORT CallRenderer {
+
+private:
+JavaVM * jvm;
+
+protected:
+jmethodID voidstartInteractiveZoomjintintID; // cache method id
+jmethodID jdoubleArray_clickRubberBoxjintintjdoubleArray_doubledoubleID; // cache method id
+jmethodID jdoubleArray_dragRubberBoxjintintID; // cache method id
+jmethodID voidupdateTextBoundsjintintID; // cache method id
+jmethodID voidupdateSubwinScalejintintID; // cache method id
+jmethodID jdoubleArray_get2dViewCoordinatesjintintjdoubleArray_doubledoubleID; // cache method id
+jmethodID jdoubleArray_getPixelFrom2dViewCoordinatesjintintjdoubleArray_doubledoubleID; // cache method id
+jmethodID jdoubleArray_get2dViewFromPixelCoordinatesjintintjdoubleArray_doubledoubleID; // cache method id
+jmethodID jdoubleArray_getViewingAreajintintID; // cache method id
+
+
+
+jobject instance;
+jclass instanceClass; // cache class
+
+
+// Caching (if any)
+
+
+/**
+* Get the environment matching to the current thread.
+*/
+virtual JNIEnv * getCurrentEnv();
+
+public:
+// Constructor
+/**
+* Create a wrapping of the object from a JNIEnv.
+* It will call the default constructor
+* @param JEnv_ the Java Env
+*/
+CallRenderer(JavaVM * jvm_);
+
+/**
+* Create a wrapping of an already existing object from a JNIEnv.
+* The object must have already been instantiated
+* @param JEnv_ the Java Env
+* @param JObj the object
+*/
+CallRenderer(JavaVM * jvm_, jobject JObj);
+
+
+/**
+* This is a fake constructor to avoid the constructor
+* chaining when dealing with extended giws classes
+*/
+#ifdef FAKEGIWSDATATYPE
+CallRenderer(fakeGiwsDataType::fakeGiwsDataType /* unused */) {}
+#endif
+
+// Destructor
+~CallRenderer();
+
+// Generic method
+// Synchronization methods
+/**
+* Enter monitor associated with the object.
+* Equivalent of creating a "synchronized(obj)" scope in Java.
+*/
+void synchronize();
+
+/**
+* Exit monitor associated with the object.
+* Equivalent of ending a "synchronized(obj)" scope.
+*/
+void endSynchronize();
+
+// Methods
+static void startInteractiveZoom(JavaVM * jvm_, int id);
+
+static double* clickRubberBox(JavaVM * jvm_, int id, double const* startRectangle, int startRectangleSize);
+
+static double* dragRubberBox(JavaVM * jvm_, int id);
+
+static void updateTextBounds(JavaVM * jvm_, int id);
+
+static void updateSubwinScale(JavaVM * jvm_, int id);
+
+static double* get2dViewCoordinates(JavaVM * jvm_, int id, double const* coords, int coordsSize);
+
+static double* getPixelFrom2dViewCoordinates(JavaVM * jvm_, int id, double const* coords, int coordsSize);
+
+static double* get2dViewFromPixelCoordinates(JavaVM * jvm_, int id, double const* coords, int coordsSize);
+
+static double* getViewingArea(JavaVM * jvm_, int id);
+
+
+ /**
+ * Get class name to use for static methods
+ * @return class name to use for static methods
+ */
+
+ static const std::string className()
+ {
+ return "org/scilab/modules/renderer/CallRenderer";
+ }
+
+
+ /**
+ * Get class to use for static methods
+ * @return class to use for static methods
+ */
+
+ static jclass initClass(JNIEnv * curEnv)
+ {
+ static jclass cls = 0;
+
+ if (cls == 0)
+ {
+ jclass _cls = curEnv->FindClass(className().c_str());
+ if (_cls)
+ {
+ cls = static_cast<jclass>(curEnv->NewGlobalRef(_cls));
+ }
+ }
+
+ return cls;
+ }
+
+};
+
+
+}
+#endif
diff --git a/modules/renderer/src/jni/XlFontManager.cpp b/modules/renderer/src/jni/XlFontManager.cpp
new file mode 100755
index 000000000..ce4754645
--- /dev/null
+++ b/modules/renderer/src/jni/XlFontManager.cpp
@@ -0,0 +1,435 @@
+#include "XlFontManager.hxx"
+/* Generated by GIWS (version 2.0.2) with command:
+giws --disable-return-size-array --output-dir src/jni/ --throws-exception-on-error --description-file src/jni/XlFontManager.giws.xml
+*/
+/*
+
+This is generated code.
+
+This software is a computer program whose purpose is to hide the complexity
+of accessing Java objects/methods from C++ code.
+
+This software is governed by the CeCILL-B license under French law and
+abiding by the rules of distribution of free software. You can use,
+modify and/ or redistribute the software under the terms of the CeCILL-B
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info".
+
+As a counterpart to the access to the source code and rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty and the software's author, the holder of the
+economic rights, and the successive licensors have only limited
+liability.
+
+In this respect, the user's attention is drawn to the risks associated
+with loading, using, modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean that it is complicated to manipulate, and that also
+therefore means that it is reserved for developers and experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or
+data to be ensured and, more generally, to use and operate it in the
+same conditions as regards security.
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL-B license and that you accept its terms.
+*/
+
+namespace org_scilab_modules_renderer_utils_textRendering {
+
+ // Static declarations (if any)
+
+// Returns the current env
+
+JNIEnv * XlFontManager::getCurrentEnv() {
+JNIEnv * curEnv = NULL;
+jint res=this->jvm->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+if (res != JNI_OK) {
+throw GiwsException::JniException(getCurrentEnv());
+}
+return curEnv;
+}
+// Destructor
+
+XlFontManager::~XlFontManager() {
+JNIEnv * curEnv = NULL;
+this->jvm->AttachCurrentThread(reinterpret_cast<void **>(&curEnv), NULL);
+curEnv->DeleteGlobalRef(this->instance);
+curEnv->DeleteGlobalRef(this->instanceClass);
+}
+// Constructors
+XlFontManager::XlFontManager(JavaVM * jvm_) {
+jmethodID constructObject = NULL ;
+jobject localInstance ;
+jclass localClass ;
+
+const std::string construct="<init>";
+const std::string param="()V";
+jvm=jvm_;
+
+JNIEnv * curEnv = getCurrentEnv();
+
+localClass = curEnv->FindClass( this->className().c_str() ) ;
+if (localClass == NULL) {
+ throw GiwsException::JniClassNotFoundException(curEnv, this->className());
+}
+
+this->instanceClass = static_cast<jclass>(curEnv->NewGlobalRef(localClass));
+
+/* localClass is not needed anymore */
+curEnv->DeleteLocalRef(localClass);
+
+if (this->instanceClass == NULL) {
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+}
+
+
+constructObject = curEnv->GetMethodID( this->instanceClass, construct.c_str() , param.c_str() ) ;
+if(constructObject == NULL){
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+}
+
+localInstance = curEnv->NewObject( this->instanceClass, constructObject ) ;
+if(localInstance == NULL){
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+}
+
+this->instance = curEnv->NewGlobalRef(localInstance) ;
+if(this->instance == NULL){
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+}
+/* localInstance not needed anymore */
+curEnv->DeleteLocalRef(localInstance);
+
+ /* Methods ID set to NULL */
+jobjectArray_getInstalledFontsNameID=NULL;
+jintgetSizeInstalledFontsNameID=NULL;
+jintgetSizeAvailableFontsNameID=NULL;
+jobjectArray_getAvailableFontsNameID=NULL;
+jbooleanisAvailableFontNamejstringjava_lang_StringID=NULL;
+jintaddFontjstringjava_lang_StringID=NULL;
+jintchangeFontjintintjstringjava_lang_StringID=NULL;
+jintchangeFontWithPropertyjintintjstringjava_lang_StringjbooleanbooleanjbooleanbooleanID=NULL;
+voidresetXlFontManagerID=NULL;
+jintaddFontFromFilenamejstringjava_lang_StringID=NULL;
+jintchangeFontFromFilenamejintintjstringjava_lang_StringID=NULL;
+
+
+}
+
+XlFontManager::XlFontManager(JavaVM * jvm_, jobject JObj) {
+ jvm=jvm_;
+
+ JNIEnv * curEnv = getCurrentEnv();
+
+jclass localClass = curEnv->GetObjectClass(JObj);
+ this->instanceClass = static_cast<jclass>(curEnv->NewGlobalRef(localClass));
+ curEnv->DeleteLocalRef(localClass);
+
+ if (this->instanceClass == NULL) {
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+ }
+
+ this->instance = curEnv->NewGlobalRef(JObj) ;
+ if(this->instance == NULL){
+throw GiwsException::JniObjectCreationException(curEnv, this->className());
+ }
+ /* Methods ID set to NULL */
+ jobjectArray_getInstalledFontsNameID=NULL;
+jintgetSizeInstalledFontsNameID=NULL;
+jintgetSizeAvailableFontsNameID=NULL;
+jobjectArray_getAvailableFontsNameID=NULL;
+jbooleanisAvailableFontNamejstringjava_lang_StringID=NULL;
+jintaddFontjstringjava_lang_StringID=NULL;
+jintchangeFontjintintjstringjava_lang_StringID=NULL;
+jintchangeFontWithPropertyjintintjstringjava_lang_StringjbooleanbooleanjbooleanbooleanID=NULL;
+voidresetXlFontManagerID=NULL;
+jintaddFontFromFilenamejstringjava_lang_StringID=NULL;
+jintchangeFontFromFilenamejintintjstringjava_lang_StringID=NULL;
+
+
+}
+
+// Generic methods
+
+void XlFontManager::synchronize() {
+if (getCurrentEnv()->MonitorEnter(instance) != JNI_OK) {
+throw GiwsException::JniMonitorException(getCurrentEnv(), "XlFontManager");
+}
+}
+
+void XlFontManager::endSynchronize() {
+if ( getCurrentEnv()->MonitorExit(instance) != JNI_OK) {
+throw GiwsException::JniMonitorException(getCurrentEnv(), "XlFontManager");
+}
+}
+// Method(s)
+
+char** XlFontManager::getInstalledFontsName (){
+
+JNIEnv * curEnv = getCurrentEnv();
+
+if (jobjectArray_getInstalledFontsNameID==NULL) { /* Use the cache */
+ jobjectArray_getInstalledFontsNameID = curEnv->GetMethodID(this->instanceClass, "getInstalledFontsName", "()[Ljava/lang/String;" ) ;
+if (jobjectArray_getInstalledFontsNameID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "getInstalledFontsName");
+}
+}
+ jobjectArray res = static_cast<jobjectArray>( curEnv->CallObjectMethod( this->instance, jobjectArray_getInstalledFontsNameID ));
+ if (curEnv->ExceptionCheck()) {
+throw GiwsException::JniCallMethodException(curEnv);
+}if (res != NULL) { int lenRow;
+ lenRow = curEnv->GetArrayLength(res);
+
+char **arrayOfString;
+arrayOfString = new char *[lenRow];
+for (jsize i = 0; i < lenRow; i++){
+jstring resString = reinterpret_cast<jstring>(curEnv->GetObjectArrayElement(res, i));
+const char *tempString = curEnv->GetStringUTFChars(resString, 0);
+arrayOfString[i] = new char[strlen(tempString) + 1];
+
+strcpy(arrayOfString[i], tempString);
+curEnv->ReleaseStringUTFChars(resString, tempString);
+curEnv->DeleteLocalRef(resString);
+}
+
+curEnv->DeleteLocalRef(res);
+return arrayOfString;
+ } else {
+curEnv->DeleteLocalRef(res);
+return NULL;
+}
+}
+
+int XlFontManager::getSizeInstalledFontsName (){
+
+JNIEnv * curEnv = getCurrentEnv();
+
+if (jintgetSizeInstalledFontsNameID==NULL) { /* Use the cache */
+ jintgetSizeInstalledFontsNameID = curEnv->GetMethodID(this->instanceClass, "getSizeInstalledFontsName", "()I" ) ;
+if (jintgetSizeInstalledFontsNameID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "getSizeInstalledFontsName");
+}
+}
+ jint res = static_cast<jint>( curEnv->CallIntMethod( this->instance, jintgetSizeInstalledFontsNameID ));
+
+return res;
+
+}
+
+int XlFontManager::getSizeAvailableFontsName (){
+
+JNIEnv * curEnv = getCurrentEnv();
+
+if (jintgetSizeAvailableFontsNameID==NULL) { /* Use the cache */
+ jintgetSizeAvailableFontsNameID = curEnv->GetMethodID(this->instanceClass, "getSizeAvailableFontsName", "()I" ) ;
+if (jintgetSizeAvailableFontsNameID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "getSizeAvailableFontsName");
+}
+}
+ jint res = static_cast<jint>( curEnv->CallIntMethod( this->instance, jintgetSizeAvailableFontsNameID ));
+
+return res;
+
+}
+
+char** XlFontManager::getAvailableFontsName (){
+
+JNIEnv * curEnv = getCurrentEnv();
+
+if (jobjectArray_getAvailableFontsNameID==NULL) { /* Use the cache */
+ jobjectArray_getAvailableFontsNameID = curEnv->GetMethodID(this->instanceClass, "getAvailableFontsName", "()[Ljava/lang/String;" ) ;
+if (jobjectArray_getAvailableFontsNameID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "getAvailableFontsName");
+}
+}
+ jobjectArray res = static_cast<jobjectArray>( curEnv->CallObjectMethod( this->instance, jobjectArray_getAvailableFontsNameID ));
+ if (curEnv->ExceptionCheck()) {
+throw GiwsException::JniCallMethodException(curEnv);
+}if (res != NULL) { int lenRow;
+ lenRow = curEnv->GetArrayLength(res);
+
+char **arrayOfString;
+arrayOfString = new char *[lenRow];
+for (jsize i = 0; i < lenRow; i++){
+jstring resString = reinterpret_cast<jstring>(curEnv->GetObjectArrayElement(res, i));
+const char *tempString = curEnv->GetStringUTFChars(resString, 0);
+arrayOfString[i] = new char[strlen(tempString) + 1];
+
+strcpy(arrayOfString[i], tempString);
+curEnv->ReleaseStringUTFChars(resString, tempString);
+curEnv->DeleteLocalRef(resString);
+}
+
+curEnv->DeleteLocalRef(res);
+return arrayOfString;
+ } else {
+curEnv->DeleteLocalRef(res);
+return NULL;
+}
+}
+
+bool XlFontManager::isAvailableFontName (char const* fontname){
+
+JNIEnv * curEnv = getCurrentEnv();
+
+if (jbooleanisAvailableFontNamejstringjava_lang_StringID==NULL) { /* Use the cache */
+ jbooleanisAvailableFontNamejstringjava_lang_StringID = curEnv->GetMethodID(this->instanceClass, "isAvailableFontName", "(Ljava/lang/String;)Z" ) ;
+if (jbooleanisAvailableFontNamejstringjava_lang_StringID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "isAvailableFontName");
+}
+}
+jstring fontname_ = curEnv->NewStringUTF( fontname );
+if (fontname != NULL && fontname_ == NULL)
+{
+throw GiwsException::JniBadAllocException(curEnv);
+}
+
+
+ jboolean res = static_cast<jboolean>( curEnv->CallBooleanMethod( this->instance, jbooleanisAvailableFontNamejstringjava_lang_StringID ,fontname_));
+ curEnv->DeleteLocalRef(fontname_);
+
+return (res == JNI_TRUE);
+
+}
+
+int XlFontManager::addFont (char const* fontName){
+
+JNIEnv * curEnv = getCurrentEnv();
+
+if (jintaddFontjstringjava_lang_StringID==NULL) { /* Use the cache */
+ jintaddFontjstringjava_lang_StringID = curEnv->GetMethodID(this->instanceClass, "addFont", "(Ljava/lang/String;)I" ) ;
+if (jintaddFontjstringjava_lang_StringID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "addFont");
+}
+}
+jstring fontName_ = curEnv->NewStringUTF( fontName );
+if (fontName != NULL && fontName_ == NULL)
+{
+throw GiwsException::JniBadAllocException(curEnv);
+}
+
+
+ jint res = static_cast<jint>( curEnv->CallIntMethod( this->instance, jintaddFontjstringjava_lang_StringID ,fontName_));
+ curEnv->DeleteLocalRef(fontName_);
+
+return res;
+
+}
+
+int XlFontManager::changeFont (int index, char const* fontName){
+
+JNIEnv * curEnv = getCurrentEnv();
+
+if (jintchangeFontjintintjstringjava_lang_StringID==NULL) { /* Use the cache */
+ jintchangeFontjintintjstringjava_lang_StringID = curEnv->GetMethodID(this->instanceClass, "changeFont", "(ILjava/lang/String;)I" ) ;
+if (jintchangeFontjintintjstringjava_lang_StringID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "changeFont");
+}
+}
+jstring fontName_ = curEnv->NewStringUTF( fontName );
+if (fontName != NULL && fontName_ == NULL)
+{
+throw GiwsException::JniBadAllocException(curEnv);
+}
+
+
+ jint res = static_cast<jint>( curEnv->CallIntMethod( this->instance, jintchangeFontjintintjstringjava_lang_StringID ,index, fontName_));
+ curEnv->DeleteLocalRef(fontName_);
+
+return res;
+
+}
+
+int XlFontManager::changeFontWithProperty (int index, char const* fontName, bool isBold, bool isItalic){
+
+JNIEnv * curEnv = getCurrentEnv();
+
+if (jintchangeFontWithPropertyjintintjstringjava_lang_StringjbooleanbooleanjbooleanbooleanID==NULL) { /* Use the cache */
+ jintchangeFontWithPropertyjintintjstringjava_lang_StringjbooleanbooleanjbooleanbooleanID = curEnv->GetMethodID(this->instanceClass, "changeFontWithProperty", "(ILjava/lang/String;ZZ)I" ) ;
+if (jintchangeFontWithPropertyjintintjstringjava_lang_StringjbooleanbooleanjbooleanbooleanID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "changeFontWithProperty");
+}
+}
+jstring fontName_ = curEnv->NewStringUTF( fontName );
+if (fontName != NULL && fontName_ == NULL)
+{
+throw GiwsException::JniBadAllocException(curEnv);
+}
+
+
+jboolean isBold_ = (static_cast<bool>(isBold) ? JNI_TRUE : JNI_FALSE);
+
+jboolean isItalic_ = (static_cast<bool>(isItalic) ? JNI_TRUE : JNI_FALSE);
+
+ jint res = static_cast<jint>( curEnv->CallIntMethod( this->instance, jintchangeFontWithPropertyjintintjstringjava_lang_StringjbooleanbooleanjbooleanbooleanID ,index, fontName_, isBold_, isItalic_));
+ curEnv->DeleteLocalRef(fontName_);
+
+return res;
+
+}
+
+void XlFontManager::resetXlFontManager (){
+
+JNIEnv * curEnv = getCurrentEnv();
+
+if (voidresetXlFontManagerID==NULL) { /* Use the cache */
+ voidresetXlFontManagerID = curEnv->GetMethodID(this->instanceClass, "resetXlFontManager", "()V" ) ;
+if (voidresetXlFontManagerID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "resetXlFontManager");
+}
+}
+ curEnv->CallVoidMethod( this->instance, voidresetXlFontManagerID );
+
+}
+
+int XlFontManager::addFontFromFilename (char const* FontFilename){
+
+JNIEnv * curEnv = getCurrentEnv();
+
+if (jintaddFontFromFilenamejstringjava_lang_StringID==NULL) { /* Use the cache */
+ jintaddFontFromFilenamejstringjava_lang_StringID = curEnv->GetMethodID(this->instanceClass, "addFontFromFilename", "(Ljava/lang/String;)I" ) ;
+if (jintaddFontFromFilenamejstringjava_lang_StringID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "addFontFromFilename");
+}
+}
+jstring FontFilename_ = curEnv->NewStringUTF( FontFilename );
+if (FontFilename != NULL && FontFilename_ == NULL)
+{
+throw GiwsException::JniBadAllocException(curEnv);
+}
+
+
+ jint res = static_cast<jint>( curEnv->CallIntMethod( this->instance, jintaddFontFromFilenamejstringjava_lang_StringID ,FontFilename_));
+ curEnv->DeleteLocalRef(FontFilename_);
+
+return res;
+
+}
+
+int XlFontManager::changeFontFromFilename (int index, char const* FontFilename){
+
+JNIEnv * curEnv = getCurrentEnv();
+
+if (jintchangeFontFromFilenamejintintjstringjava_lang_StringID==NULL) { /* Use the cache */
+ jintchangeFontFromFilenamejintintjstringjava_lang_StringID = curEnv->GetMethodID(this->instanceClass, "changeFontFromFilename", "(ILjava/lang/String;)I" ) ;
+if (jintchangeFontFromFilenamejintintjstringjava_lang_StringID == NULL) {
+throw GiwsException::JniMethodNotFoundException(curEnv, "changeFontFromFilename");
+}
+}
+jstring FontFilename_ = curEnv->NewStringUTF( FontFilename );
+if (FontFilename != NULL && FontFilename_ == NULL)
+{
+throw GiwsException::JniBadAllocException(curEnv);
+}
+
+
+ jint res = static_cast<jint>( curEnv->CallIntMethod( this->instance, jintchangeFontFromFilenamejintintjstringjava_lang_StringID ,index, FontFilename_));
+ curEnv->DeleteLocalRef(FontFilename_);
+
+return res;
+
+}
+
+}
diff --git a/modules/renderer/src/jni/XlFontManager.giws.xml b/modules/renderer/src/jni/XlFontManager.giws.xml
new file mode 100755
index 000000000..86cec0292
--- /dev/null
+++ b/modules/renderer/src/jni/XlFontManager.giws.xml
@@ -0,0 +1,38 @@
+ <package name="org.scilab.modules.renderer.utils.textRendering">
+ <object name="XlFontManager">
+ <method name="getInstalledFontsName" returnType="String[]">
+ </method>
+ <method name="getSizeInstalledFontsName" returnType="int">
+ </method>
+ <method name="getSizeAvailableFontsName" returnType="int">
+ </method>
+ <method name="getAvailableFontsName" returnType="String[]">
+ </method>
+ <method name="isAvailableFontName" returnType="boolean">
+ <param type="String" name="fontname" />
+ </method>
+ <method name="addFont" returnType="int">
+ <param type="String" name="fontName" />
+ </method>
+ <method name="changeFont" returnType="int">
+ <param type="int" name="index" />
+ <param type="String" name="fontName" />
+ </method>
+ <method name="changeFontWithProperty" returnType="int">
+ <param type="int" name="index" />
+ <param type="String" name="fontName" />
+ <param type="boolean" name="isBold" />
+ <param type="boolean" name="isItalic" />
+ </method>
+ <method name="resetXlFontManager" returnType="void">
+ </method>
+ <method name="addFontFromFilename" returnType="int">
+ <param type="String" name="FontFilename" />
+ </method>
+ <method name="changeFontFromFilename" returnType="int">
+ <param type="int" name="index" />
+ <param type="String" name="FontFilename" />
+ </method>
+
+ </object>
+</package>
diff --git a/modules/renderer/src/jni/XlFontManager.hxx b/modules/renderer/src/jni/XlFontManager.hxx
new file mode 100755
index 000000000..daf5ff1c8
--- /dev/null
+++ b/modules/renderer/src/jni/XlFontManager.hxx
@@ -0,0 +1,208 @@
+/* Generated by GIWS (version 2.0.2) with command:
+giws --disable-return-size-array --output-dir src/jni/ --throws-exception-on-error --description-file src/jni/XlFontManager.giws.xml
+*/
+/*
+
+This is generated code.
+
+This software is a computer program whose purpose is to hide the complexity
+of accessing Java objects/methods from C++ code.
+
+This software is governed by the CeCILL-B license under French law and
+abiding by the rules of distribution of free software. You can use,
+modify and/ or redistribute the software under the terms of the CeCILL-B
+license as circulated by CEA, CNRS and INRIA at the following URL
+"http://www.cecill.info".
+
+As a counterpart to the access to the source code and rights to copy,
+modify and redistribute granted by the license, users are provided only
+with a limited warranty and the software's author, the holder of the
+economic rights, and the successive licensors have only limited
+liability.
+
+In this respect, the user's attention is drawn to the risks associated
+with loading, using, modifying and/or developing or reproducing the
+software by the user in light of its specific status of free software,
+that may mean that it is complicated to manipulate, and that also
+therefore means that it is reserved for developers and experienced
+professionals having in-depth computer knowledge. Users are therefore
+encouraged to load and test the software's suitability as regards their
+requirements in conditions enabling the security of their systems and/or
+data to be ensured and, more generally, to use and operate it in the
+same conditions as regards security.
+
+The fact that you are presently reading this means that you have had
+knowledge of the CeCILL-B license and that you accept its terms.
+*/
+
+
+#ifndef __ORG_SCILAB_MODULES_RENDERER_UTILS_TEXTRENDERING_XLFONTMANAGER__
+#define __ORG_SCILAB_MODULES_RENDERER_UTILS_TEXTRENDERING_XLFONTMANAGER__
+#include <iostream>
+#include <string>
+#include <string.h>
+#include <stdlib.h>
+#include <jni.h>
+
+#include "GiwsException.hxx"
+
+ #if defined(_MSC_VER) /* Defined anyway with Visual */
+ #include <Windows.h>
+ #else
+ typedef signed char byte;
+ #endif
+
+
+#ifndef GIWSEXPORT
+# if defined(_MSC_VER) || defined(__WIN32__) || defined(__CYGWIN__)
+# if defined(STATIC_LINKED)
+# define GIWSEXPORT
+# else
+# define GIWSEXPORT __declspec(dllexport)
+# endif
+# else
+# if __GNUC__ >= 4
+# define GIWSEXPORT __attribute__ ((visibility ("default")))
+# else
+# define GIWSEXPORT
+# endif
+# endif
+#endif
+
+namespace org_scilab_modules_renderer_utils_textRendering {
+class GIWSEXPORT XlFontManager {
+
+private:
+JavaVM * jvm;
+
+protected:
+jmethodID jobjectArray_getInstalledFontsNameID; // cache method id
+jmethodID jintgetSizeInstalledFontsNameID; // cache method id
+jmethodID jintgetSizeAvailableFontsNameID; // cache method id
+jmethodID jobjectArray_getAvailableFontsNameID; // cache method id
+jmethodID jbooleanisAvailableFontNamejstringjava_lang_StringID; // cache method id
+jmethodID jintaddFontjstringjava_lang_StringID; // cache method id
+jmethodID jintchangeFontjintintjstringjava_lang_StringID; // cache method id
+jmethodID jintchangeFontWithPropertyjintintjstringjava_lang_StringjbooleanbooleanjbooleanbooleanID; // cache method id
+jmethodID voidresetXlFontManagerID; // cache method id
+jmethodID jintaddFontFromFilenamejstringjava_lang_StringID; // cache method id
+jmethodID jintchangeFontFromFilenamejintintjstringjava_lang_StringID; // cache method id
+
+
+
+jobject instance;
+jclass instanceClass; // cache class
+
+
+// Caching (if any)
+
+
+/**
+* Get the environment matching to the current thread.
+*/
+virtual JNIEnv * getCurrentEnv();
+
+public:
+// Constructor
+/**
+* Create a wrapping of the object from a JNIEnv.
+* It will call the default constructor
+* @param JEnv_ the Java Env
+*/
+XlFontManager(JavaVM * jvm_);
+
+/**
+* Create a wrapping of an already existing object from a JNIEnv.
+* The object must have already been instantiated
+* @param JEnv_ the Java Env
+* @param JObj the object
+*/
+XlFontManager(JavaVM * jvm_, jobject JObj);
+
+
+/**
+* This is a fake constructor to avoid the constructor
+* chaining when dealing with extended giws classes
+*/
+#ifdef FAKEGIWSDATATYPE
+XlFontManager(fakeGiwsDataType::fakeGiwsDataType /* unused */) {}
+#endif
+
+// Destructor
+~XlFontManager();
+
+// Generic method
+// Synchronization methods
+/**
+* Enter monitor associated with the object.
+* Equivalent of creating a "synchronized(obj)" scope in Java.
+*/
+void synchronize();
+
+/**
+* Exit monitor associated with the object.
+* Equivalent of ending a "synchronized(obj)" scope.
+*/
+void endSynchronize();
+
+// Methods
+char** getInstalledFontsName();
+
+int getSizeInstalledFontsName();
+
+int getSizeAvailableFontsName();
+
+char** getAvailableFontsName();
+
+bool isAvailableFontName(char const* fontname);
+
+int addFont(char const* fontName);
+
+int changeFont(int index, char const* fontName);
+
+int changeFontWithProperty(int index, char const* fontName, bool isBold, bool isItalic);
+
+void resetXlFontManager();
+
+int addFontFromFilename(char const* FontFilename);
+
+int changeFontFromFilename(int index, char const* FontFilename);
+
+
+ /**
+ * Get class name to use for static methods
+ * @return class name to use for static methods
+ */
+
+ static const std::string className()
+ {
+ return "org/scilab/modules/renderer/utils/textRendering/XlFontManager";
+ }
+
+
+ /**
+ * Get class to use for static methods
+ * @return class to use for static methods
+ */
+
+ static jclass initClass(JNIEnv * curEnv)
+ {
+ static jclass cls = 0;
+
+ if (cls == 0)
+ {
+ jclass _cls = curEnv->FindClass(className().c_str());
+ if (_cls)
+ {
+ cls = static_cast<jclass>(curEnv->NewGlobalRef(_cls));
+ }
+ }
+
+ return cls;
+ }
+
+};
+
+
+}
+#endif
diff --git a/modules/renderer/src/jni/libscirenderer_la-CallRenderer.lo b/modules/renderer/src/jni/libscirenderer_la-CallRenderer.lo
new file mode 100755
index 000000000..bb81d09ea
--- /dev/null
+++ b/modules/renderer/src/jni/libscirenderer_la-CallRenderer.lo
@@ -0,0 +1,12 @@
+# src/jni/libscirenderer_la-CallRenderer.lo - a libtool object file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/libscirenderer_la-CallRenderer.o'
+
+# Name of the non-PIC object
+non_pic_object=none
+
diff --git a/modules/renderer/src/jni/libscirenderer_la-XlFontManager.lo b/modules/renderer/src/jni/libscirenderer_la-XlFontManager.lo
new file mode 100755
index 000000000..61fed47d9
--- /dev/null
+++ b/modules/renderer/src/jni/libscirenderer_la-XlFontManager.lo
@@ -0,0 +1,12 @@
+# src/jni/libscirenderer_la-XlFontManager.lo - a libtool object file
+# Generated by libtool (GNU libtool) 2.4.2
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/libscirenderer_la-XlFontManager.o'
+
+# Name of the non-PIC object
+non_pic_object=none
+
diff --git a/modules/renderer/src/jni/renderer.giws.xml b/modules/renderer/src/jni/renderer.giws.xml
new file mode 100755
index 000000000..2b1b1866d
--- /dev/null
+++ b/modules/renderer/src/jni/renderer.giws.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<package name="org.scilab.modules.renderer">
+ <object name="CallRenderer">
+ <method name="startInteractiveZoom" returnType="void" modifier="static">
+ <parameter name="id" type="int"/>
+ </method>
+
+ <method name="clickRubberBox" returnType="double[]" modifier="static">
+ <parameter name="id" type="int"/>
+ <parameter name="startRectangle" type="double[]"/>
+ </method>
+
+ <method name="dragRubberBox" returnType="double[]" modifier="static">
+ <parameter name="id" type="int"/>
+ </method>
+
+
+ <method name="updateTextBounds" returnType="void" modifier="static">
+ <parameter name="id" type="int"/>
+ </method>
+ <method name="updateSubwinScale" returnType="void" modifier="static">
+ <parameter name="id" type="int"/>
+ </method>
+ <method name="get2dViewCoordinates" returnType="double[]" modifier="static">
+ <parameter name="id" type="int"/>
+ <parameter name="coords" type="double[]"/>
+ </method>
+ <method name="getPixelFrom2dViewCoordinates" returnType="double[]" modifier="static">
+ <parameter name="id" type="int"/>
+ <parameter name="coords" type="double[]"/>
+ </method>
+ <method name="get2dViewFromPixelCoordinates" returnType="double[]" modifier="static">
+ <parameter name="id" type="int"/>
+ <parameter name="coords" type="double[]"/>
+ </method>
+ <method name="getViewingArea" returnType="double[]" modifier="static">
+ <parameter name="id" type="int"/>
+ </method>
+ </object>
+</package>
diff --git a/modules/renderer/src/norenderer/norenderer.h b/modules/renderer/src/norenderer/norenderer.h
new file mode 100755
index 000000000..1bdc8fac4
--- /dev/null
+++ b/modules/renderer/src/norenderer/norenderer.h
@@ -0,0 +1,18 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2007 - INRIA - Sylvestre LEDRU
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+/**
+ * Fake gateway declaration for rendering function
+ *
+ * @return 0 anyway
+ */
+int gw_renderer(void);
diff --git a/modules/renderer/src/norenderer/norenderer.rc b/modules/renderer/src/norenderer/norenderer.rc
new file mode 100755
index 000000000..6f9f27240
--- /dev/null
+++ b/modules/renderer/src/norenderer/norenderer.rc
@@ -0,0 +1,97 @@
+// Microsoft Visual C++ generated resource script.
+//
+
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+//#include "afxres.h"
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// French (France) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA)
+#ifdef _WIN32
+LANGUAGE LANG_FRENCH, SUBLANG_FRENCH
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 5,5,2,0
+ PRODUCTVERSION 5,5,2,0
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040c04b0"
+ BEGIN
+ VALUE "FileDescription", "norender"
+ VALUE "FileVersion", "5, 5, 2, 0"
+ VALUE "InternalName", "norenderer"
+ VALUE "LegalCopyright", "Copyright (C) 2017"
+ VALUE "OriginalFilename", "noscirenderer.dll"
+ VALUE "ProductName", " norenderer"
+ VALUE "ProductVersion", "5, 5, 2, 0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x40c, 1200
+ END
+END
+
+#endif // French (France) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+