How to convert a VTK example from java to clojure?

496 views
Skip to first unread message

Antonio Recio

unread,
Jun 21, 2011, 12:55:38 AM6/21/11
to clo...@googlegroups.com
I have tried to convert the example Cone5.java from VTK to clojure. I have write this ... but it doesn't work. Do you have any suggestion?


The original java:

import vtk.*;

public class Cone5 {
  static {
    System.loadLibrary("vtkCommonJava");
    System.loadLibrary("vtkFilteringJava");
    System.loadLibrary("vtkIOJava");
    System.loadLibrary("vtkImagingJava");
    System.loadLibrary("vtkGraphicsJava");
    System.loadLibrary("vtkRenderingJava");
  }

  public static void main (String []args) throws Exception {
    vtkConeSource cone = new vtkConeSource();
    cone.SetHeight( 3.0 );
    cone.SetRadius( 1.0 );
    cone.SetResolution( 10 );
   
    vtkPolyDataMapper coneMapper = new vtkPolyDataMapper();
    coneMapper.SetInputConnection(cone.GetOutputPort());
   
    vtkActor coneActor = new vtkActor();
    coneActor.SetMapper(coneMapper);

    vtkRenderer ren1 = new vtkRenderer();
    ren1.AddActor(coneActor);
    ren1.SetBackground(0.1, 0.2, 0.4);
   
    vtkRenderWindow renWin = new vtkRenderWindow();
    renWin.AddRenderer( ren1 );
    renWin.SetSize(300, 300);
   
    ren1.ResetCamera();
    ren1.GetActiveCamera().Azimuth(90);
   
    vtkRenderWindowInteractor iren = new vtkRenderWindowInteractor();
    iren.SetRenderWindow(renWin);

    vtkInteractorStyleTrackballCamera style =
        new vtkInteractorStyleTrackballCamera();
    iren.SetInteractorStyle(style);

   
    iren.Initialize();
    iren.Start();
  }
}



My modified version in clojure with errors:


(ns project.core
  (:import (vtk vtkConeSource vtkPolyDataMapper vtkRenderWindow
                vtkRenderWindowInteractor vtkCamera vtkActor vtkRenderer
                vtkInteractorStyleTrackballCamera)))

(defn main []
  (let [cone (doto (vtkConeSource.)
               (.SetHeight 3.0)
               (.SetRadius 1.0)
               (.SetResolution 10))
        coneMapper (doto (vtkPolyDataMapper.)
                     (.SetInputConnection(.GetOutputPort cone)))
        coneActor (doto (vtkActor.)
                    (.SetMapper coneMapper))
        ren (doto (vtkRenderer.)
              (.AddActor coneActor)
              (.SetBackground 0.1 0.2 0.4)
              (.ResetCamera)
              (.GetActiveCamera.Azimuth 90))
        renWin (doto (vtkRenderWindow.)
                 (.AddRenderer ren)
                 (.SetSize 300 300))
        iren (doto (.vtkRenderWindowInteractor.)
               (.SetRenderWindow renWin)
               (.SetInteractorStyle vtkInteractorStyleTrackballCamera.)
               (.Initialize)
               (.Start))
        ]))

Tassilo Horn

unread,
Jun 21, 2011, 7:27:30 AM6/21/11
to clo...@googlegroups.com
Antonio Recio <amdx...@gmail.com> writes:

Hi Antonio,

> My modified version in clojure with errors:*

The errors would be interesting as well. But I found at least two
obvious glitches.

> (defn main []
> (let [cone (doto (vtkConeSource.)
> (.SetHeight 3.0)
> (.SetRadius 1.0)
> (.SetResolution 10))
> coneMapper (doto (vtkPolyDataMapper.)
> (.SetInputConnection(.GetOutputPort cone)))
> coneActor (doto (vtkActor.)
> (.SetMapper coneMapper))
> ren (doto (vtkRenderer.)
> (.AddActor coneActor)
> (.SetBackground 0.1 0.2 0.4)
> (.ResetCamera)
> (.GetActiveCamera.Azimuth 90))

This has to be: (-> (.GetActiveCamera) (.Azimuth 90))

> renWin (doto (vtkRenderWindow.)
> (.AddRenderer ren)
> (.SetSize 300 300))
> iren (doto (.vtkRenderWindowInteractor.)
> (.SetRenderWindow renWin)
> (.SetInteractorStyle vtkInteractorStyleTrackballCamera.)

This has to be: (.SetInteractorStyle (vtkInteractorStyleTrackballCamera.))

> (.Initialize)
> (.Start))
> ]))

HTH,
Tassilo

Antonio Recio

unread,
Jun 21, 2011, 8:48:06 AM6/21/11
to clo...@googlegroups.com
After the corrections I have this:

(ns project.core
  (:import (vtk vtkConeSource vtkPolyDataMapper vtkRenderWindow
                vtkRenderWindowInteractor vtkCamera vtkActor vtkRenderer
                vtkInteractorStyleTrackballCamera)))

(defn main []
  (let [cone (doto (vtkConeSource.)
               (.SetHeight 3.0)
               (.SetRadius 1.0)
               (.SetResolution 10))
        coneMapper (doto (vtkPolyDataMapper.)
                     (.SetInputConnection(.GetOutputPort cone)))
        coneActor (doto (vtkActor.)
                    (.SetMapper coneMapper))
        ren (doto (vtkRenderer.)
              (.AddActor coneActor)
              (.SetBackground 0.1 0.2 0.4)
              (.ResetCamera)
              (-> (.GetActiveCamera) (.Azimuth 90)))

        renWin (doto (vtkRenderWindow.)
                 (.AddRenderer ren)
                 (.SetSize 300 300))
        iren (doto (vtkRenderWindowInteractor.)
               (.SetRenderWindow renWin)

               (.SetInteractorStyle (vtkInteractorStyleTrackballCamera.))
               (.Initialize)
               (.Start))
        ]))



But in the REPL I obtain this error.

user=> (main)
UnsatisfiedLinkError vtk.vtkConeSource.VTKInit()J  vtk.vtkConeSource.VTKInit (vtkConeSource.java:-2)


I can view any gui, do you think that I need to use java swing JFrame JPanel?

Meikel Brandmeyer

unread,
Jun 21, 2011, 9:25:33 AM6/21/11
to clo...@googlegroups.com
Hi,

you are missing the static part from the Java source. Add the (System/loadLibrary "vtkCommonJava") etc. between the ns clause and the definition of main.

Sincerely
Meikel

Antonio Recio

unread,
Jun 21, 2011, 11:01:43 AM6/21/11
to clo...@googlegroups.com
I have added the static libraries in the clojure file:

(ns project.core
  (:import (javax.swing JButton JFrame JPanel)

           (vtk vtkConeSource vtkPolyDataMapper vtkRenderWindow
                vtkRenderWindowInteractor vtkCamera vtkActor vtkRenderer
                vtkInteractorStyleTrackballCamera)))

(System/loadLibrary "vtkCommonJava")
(System/loadLibrary "vtkFilteringJava")
(System/loadLibrary "vtkIOJava")
(System/loadLibrary "vtkImagingJava")
(System/loadLibrary "vtkGraphicsJava")
(System/loadLibrary "vtkRenderingJava")


(defn main []
  (let [cone (doto (vtkConeSource.)
               (.SetHeight 3.0)
               (.SetRadius 1.0)
               (.SetResolution 10))
        coneMapper (doto (vtkPolyDataMapper.)
                     (.SetInputConnection(.GetOutputPort cone)))
        coneActor (doto (vtkActor.)
                    (.SetMapper coneMapper))
        ren (doto (vtkRenderer.)
              (.AddActor coneActor)
              (.SetBackground 0.1 0.2 0.4)
              (.ResetCamera)
              (-> (.GetActiveCamera) (.Azimuth 90)))
        renWin (doto (vtkRenderWindow.)
                 (.AddRenderer ren)
                 (.SetSize 300 300))
        iren (doto (vtkRenderWindowInteractor.)
               (.SetRenderWindow renWin)
               (.SetInteractorStyle (vtkInteractorStyleTrackballCamera.))
               (.Initialize)
               (.Start))
        ]))

(project.core/main)

But I still get the same error. I think that I have problems to add the "LD_LIBRARY_PATH" to my REPL.
user => (project.core/main)

Antonio Recio

unread,
Jun 21, 2011, 11:17:20 AM6/21/11
to clo...@googlegroups.com
I have tried with ... but I get the same error:

(System/setProperty "java.library.path" "/usr/local/lib/vtk-5.9/")

Antonio Recio

unread,
Jun 21, 2011, 11:26:42 AM6/21/11
to clo...@googlegroups.com
I have tried also this:

$ java -Djava.library.path=/usr/local/lib/vtk-5.9/ -Djava.ext.dirs=/usr/share/java -cp clojure.jar:src clojure.main main.clj

Exception in thread "main" java.lang.ClassNotFoundException: vtk.vtkConeSource (main.clj:1)
        at clojure.lang.Compiler.eval(Compiler.java:5440)
        at clojure.lang.Compiler.eval(Compiler.java:5415)
        at clojure.lang.Compiler.load(Compiler.java:5857)
        at clojure.lang.Compiler.loadFile(Compiler.java:5820)
        at clojure.main$load_script.invoke(main.clj:221)
        at clojure.main$script_opt.invoke(main.clj:273)
        at clojure.main$main.doInvoke(main.clj:354)
        at clojure.lang.RestFn.invoke(RestFn.java:409)
        at clojure.lang.Var.invoke(Var.java:365)
        at clojure.lang.AFn.applyToHelper(AFn.java:163)
        at clojure.lang.Var.applyTo(Var.java:482)
        at clojure.main.main(main.java:37)
Caused by: java.lang.ClassNotFoundException: vtk.vtkConeSource
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at clojure.lang.DynamicClassLoader.findClass(DynamicClassLoader.java:58)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:169)
        at project.core$eval3$loading__4410__auto____4.invoke(main.clj:1)
        at project.core$eval3.invoke(main.clj:1)
        at clojure.lang.Compiler.eval(Compiler.java:5424)
        ... 11 more

Aaron Cohen

unread,
Jun 21, 2011, 11:57:03 AM6/21/11
to clo...@googlegroups.com
It appears that you need to have the VTK *.class or *.jar files on you
classpath as well.

Add the path to your VTK java files to the "cp" parameter you are
invoking clojure with.

Antonio Recio

unread,
Jun 21, 2011, 12:17:08 PM6/21/11
to clo...@googlegroups.com
Aaron, thanks. You are right I had forgotten the vtk.jar, but I still obtain errors:

My /usr/local/bin/clojure:

#!/bin/sh
export JAVA_HOME=/usr/lib/jvm/java-6-sun/
export LD_LIBRARY_PATH=/usr/lib/jvm/java-6-sun-1.6.0.26/jre/lib/amd64/:/usr/local/lib/:/usr/local/lib/vtk-5.9/:/usr/local/lib/cmake/ITK-4.0/WrapITK/lib/
export CLASSPATH=/usr/share/java/clojure-contrib.jar:/usr/local/lib/vtk-5.9/java/vtk.jar:.

if [ "x$CLASSPATH" = "x" ] ; then
    extra_classpath=""
else
    extra_classpath=":$CLASSPATH"
fi

while true ; do
    case "$1" in
        -cp | -classpath)
            extra_classpath=":$2"
            shift 2 ;;
        --)
            shift
            break ;;
        *)
            break ;;
    esac
done

if [ "x$1" = "x" -a "x`which rlwrap`" != "x" ] ; then
    rlwrap="rlwrap -r -c -C clojure -f /etc/rlwrap/clojure-b (){}[],^%\$#@\"\";:''|\\"
fi

exec rlwrap --complete-filenames --quote-characters='"' --prompt-colour=Red java -cp /usr/share/java/clojure.jar"$extra_classpath" clojure.main "$@"




When I execute the application:

$ clojure main.clj

Exception in thread "main" java.lang.RuntimeException: java.lang.UnsatisfiedLinkError: vtk.vtkConeSource.VTKInit()J
        at clojure.lang.Util.runtimeException(Util.java:153)
        at clojure.lang.Compiler.eval(Compiler.java:6417)
        at clojure.lang.Compiler.load(Compiler.java:6843)
        at clojure.lang.Compiler.loadFile(Compiler.java:6804)
        at clojure.main$load_script.invoke(main.clj:282)
        at clojure.main$script_opt.invoke(main.clj:342)
        at clojure.main$main.doInvoke(main.clj:426)
        at clojure.lang.RestFn.invoke(RestFn.java:408)
        at clojure.lang.Var.invoke(Var.java:401)
        at clojure.lang.AFn.applyToHelper(AFn.java:161)
        at clojure.lang.Var.applyTo(Var.java:518)
        at clojure.main.main(main.java:37)
Caused by: java.lang.UnsatisfiedLinkError: vtk.vtkConeSource.VTKInit()J
        at vtk.vtkConeSource.VTKInit(Native Method)
        at vtk.vtkObject.<init>(vtkObject.java:96)
        at vtk.vtkAlgorithm.<init>(vtkAlgorithm.java:794)
        at vtk.vtkPolyDataAlgorithm.<init>(vtkPolyDataAlgorithm.java:163)
        at vtk.vtkConeSource.<init>(vtkConeSource.java:114)
        at project.core$main.invoke(main.clj:14)
        at project.core$eval26.invoke(main.clj:38)
        at clojure.lang.Compiler.eval(Compiler.java:6406)
        ... 10 more

Aaron Cohen

unread,
Jun 21, 2011, 12:26:15 PM6/21/11
to clo...@googlegroups.com
Your LD_LIBRARY_PATH is quite extensive there, is that all required or
is this just a bunch of stuff you've been trying?

I usually just use -Djava.library.path=<whatever>. On linux you also
may have to be sure that your shared libraries are +x for your user.

--Aaron

> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

Antonio Recio

unread,
Jun 21, 2011, 12:38:07 PM6/21/11
to clo...@googlegroups.com
java -Djava.library.path=/usr/local/lib/vtk-5.9/ -cp /usr/share/java/clojure.jar:/usr/local/lib/vtk-5.9/java/vtk.jar clojure.main main.clj

Aaron Cohen

unread,
Jun 21, 2011, 12:53:00 PM6/21/11
to clo...@googlegroups.com
On Tue, Jun 21, 2011 at 12:38 PM, Antonio Recio <amdx...@gmail.com> wrote:
> java -Djava.library.path=/usr/local/lib/vtk-5.9/

This is the directory that contains: libvtkCommonJava.so,
libvtkFilteringJava.so, libvtkIOJava.so, libvtkImagingJava.so,
libvtkGraphicsJava.so, and libvtkRenderingJava.so ?

They all are executable for the user you are running your program as?

Does the Java example in your initial mail actually run for you?

--Aaron

Antonio Recio

unread,
Jun 21, 2011, 4:10:01 PM6/21/11
to clo...@googlegroups.com
All the vtk libraries that I need are in /usr/local/lib/vtk-5.9/ and are executable.
Java and c++ examples work fine.

Aaron Cohen

unread,
Jun 21, 2011, 5:19:44 PM6/21/11
to clo...@googlegroups.com
OK, I've gotten it working on my computer, and it turns out to be a
slightly complicated problem.

What is happening is that the vtk java files and your clojure code are
using different classloaders (clojure uses its own classloader).

System/loadLibrary is kind of crippled in that it always loads the
library into the ClassLoader of the _invoking class's_ classLoader. I
was hoping it would use the Thread's context classloader, but it does
not.

There isn't any straightforward way to load a library using a
particular classloader either, so you have 2 options.

1) Make a java class that exposes a "loadLibrary" method. This java
class will be in the same classLoader as VTK and as a result,
loadLibrary calls from there will be visible to VTK.

public class Loader {

public static void loadLibrary(String lib) {
// Hack to load a library outside of Clojure's classloader
System.loadLibrary(lib);
}

}

2) Expose the package-private "Runtime/loadLibrary0" method and call it.

; This function is in clojure-contrib, reproduced here for convenience
(defn wall-hack-method
"Calls a private or protected method.
params is a vector of class which correspond to the arguments to the method
obj is nil for static methods, the instance object otherwise
the method name is given as a symbol or a keyword (something Named)"
[class-name method-name params obj & args]
(-> class-name (.getDeclaredMethod (name method-name) (into-array
Class params))
(doto (.setAccessible true))
(.invoke obj (into-array Object args))))

(defn load-lib [class lib]
"Loads a native library in the same classLoader as \"class\" was
loaded in. \"lib\" is a string with the OS-appropriate name of the
library. For instance, to load libvtk.so on Linux, lib should be
\"vtk\""
(wall-hack-method java.lang.Runtime "loadLibrary0" [Class String]
(Runtime/getRuntime) class lib))

; Load vtkCommonJava library in the same classLoader as vtkConeSource
(load-lib vtkConeSource "vtkCommonJava")

--------

I actually think clojure should probably add a method to its RT class
that does option 1 above, that way there's a straightforward way to
load native libraries in the correct classloader.

--Aaron

Antonio Recio

unread,
Jun 21, 2011, 8:00:47 PM6/21/11
to clo...@googlegroups.com
I have tried to use wall-hack-method but I still obtain the error: UnsatisfiedLinkError vtk.vtkConeSource.VTKInit()J  vtk.vtkConeSource.VTKInit (vtkConeSource.java:-2). What I am doing wrong?

(ns project.core
  (:import (javax.swing JButton JFrame JPanel)
           (vtk vtkConeSource vtkPolyDataMapper vtkRenderWindow
                vtkRenderWindowInteractor vtkCamera vtkActor vtkRenderer
                vtkInteractorStyleTrackballCamera)))

(System/loadLibrary "vtkCommonJava")
(System/loadLibrary "vtkFilteringJava")
(System/loadLibrary "vtkIOJava")
(System/loadLibrary "vtkImagingJava")
(System/loadLibrary "vtkGraphicsJava")
(System/loadLibrary "vtkRenderingJava")

(defn wall-hack-method
  [class-name method-name params obj & args]
  (-> class-name (.getDeclaredMethod (name method-name) (into-array Class params))
    (doto (.setAccessible true))
    (.invoke obj (into-array Object args))))

(defn load-lib [class vtk]
    (wall-hack-method java.lang.Runtime "vtkCommonJava" [Class String]
(Runtime/getRuntime) class vtk))

(load-lib vtkConeSource "vtkCommonJava")

Aaron Cohen

unread,
Jun 21, 2011, 8:34:18 PM6/21/11
to clo...@googlegroups.com
On Tue, Jun 21, 2011 at 8:00 PM, Antonio Recio <amdx...@gmail.com> wrote:
> I have tried to use wall-hack-method but I still obtain the
> error: UnsatisfiedLinkError vtk.vtkConeSource.VTKInit()J
>  vtk.vtkConeSource.VTKInit (vtkConeSource.java:-2). What I am doing wrong?
> (ns project.core
>   (:import (javax.swing JButton JFrame JPanel)
>            (vtk vtkConeSource vtkPolyDataMapper vtkRenderWindow
>                 vtkRenderWindowInteractor vtkCamera vtkActor vtkRenderer
>                 vtkInteractorStyleTrackballCamera)))
> (System/loadLibrary "vtkCommonJava")
> (System/loadLibrary "vtkFilteringJava")
> (System/loadLibrary "vtkIOJava")
> (System/loadLibrary "vtkImagingJava")
> (System/loadLibrary "vtkGraphicsJava")
> (System/loadLibrary "vtkRenderingJava")

You need to replace all of these with the appropriate (load-lib
vtkConeSource "libraryName"). The vtkConeSource there is fairly
arbitrary, it's just any class that was loaded by the correct
ClassLoader.

> (defn wall-hack-method
>   [class-name method-name params obj & args]
>   (-> class-name (.getDeclaredMethod (name method-name) (into-array Class
> params))
>     (doto (.setAccessible true))
>     (.invoke obj (into-array Object args))))
> (defn load-lib [class vtk]
>     (wall-hack-method java.lang.Runtime "vtkCommonJava" [Class String]


Where did this "vtkCommonJava" come from? It must be "loadLibrary0".
You're trying to call a method that doesn't exist.

To be clear, the top of your file should look like:


(defn wall-hack-method
"Calls a private or protected method.
params is a vector of class which correspond to the arguments to the method
obj is nil for static methods, the instance object otherwise
the method name is given as a symbol or a keyword (something Named)"

[class-name method-name params obj & args]
(-> class-name (.getDeclaredMethod (name method-name) (into-array
Class params))
(doto (.setAccessible true))
(.invoke obj (into-array Object args))))

(defn load-lib [class lib]


"Loads a native library in the same classLoader as class was

loaded in, lib is a string with the OS-appropriate name of the


library. For instance, to load libvtk.so on Linux, lib should be
\"vtk\""
(wall-hack-method java.lang.Runtime "loadLibrary0" [Class String]
(Runtime/getRuntime) class lib))

(load-lib vtkConeSource "vtkCommonJava")
(load-lib vtkConeSource "vtkFilteringJava")
(load-lib vtkConeSource "vtkIOJava")
(load-lib vtkConeSource "vtkImagingJava")
(load-lib vtkConeSource "vtkGraphicsJava")
(load-lib vtkConeSource "vtkRenderingJava")

Antonio Recio

unread,
Jun 21, 2011, 9:34:50 PM6/21/11
to clo...@googlegroups.com
Aaron Cohen, thank you! It works !!!

Nils Blum-Oeste

unread,
Apr 26, 2013, 3:46:44 AM4/26/13
to clo...@googlegroups.com
Great, thanks a lot. Fixed the issues I had.
However I wonder where 'wall-hack-method' lives now, as clojure-contrib has been split.
This (old) thread suggests it has also been renamed to call-method https://groups.google.com/forum/?fromgroups=#!topic/clojure-dev/tKzqnJWpz-k

So is this still included in one of the clojure-contrib libraries?

Aaron Cohen

unread,
Apr 26, 2013, 9:33:25 AM4/26/13
to clo...@googlegroups.com
You no longer need any of this. All you should need is to use (clojure.lang.RT/loadLibrary "vtk<whatever>")

That will ensure that the native libs end up in the correct classloader.


--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Reply all
Reply to author
Forward
0 new messages