Java and Memory — Yes, it Can Leak

July 29, 2008

Note: I had previously posted this on my SourceForge Diary on 6-18-08 , but after two posts to the diary I decided the blog was a better place :).

I have been keeping up work on Spheriosity lately as I have devoted my summer to it. Normally I spent around 7 or 8 hours a day writing code for it. Then on the weekend I try to give myself a bit of a break from staring at the computer screen 😉

Before I get in to the main point of this entry I will just list a few things I have done with Spheriosity recently:

  • Added the ability to place a point on a line
  • Moved the move point button to the draw section
  • Wrote unit tests for the new code (putting a point on a line)
  • Added a little information section to the bottom of the window which displays area, radius, etc.  so the user has some idea what is going on

There are other small changes and if you really want you can investigate the CVS logs. When I release the next version (hopefully the end of the month) I will introduce a changelog file where I will try to sum up all the new features! As a simple FYI the next feature I plan to work on is parallel transport 🙂  I can’t wait to get this implemented, but I do not think this will be any trivial task so please be patient with me as I work on this.

Anyway the reason I started this journal entry was because I just found a huge memory leak today in Spheriosity. A memory leak!? In Java!? YES! You CAN have memory leaks in Java. This realization hit me pretty hard today when I found out that I was wasting a lot of memory. Before today I had let the lore of Java convince me it was impossible to have memory leaks, but it’s true… you CAN have them.

How is this possible you ask? Well it has to do with how garbage collection works. Yes, in the traditional sense of C/C++ you can not have a memory leak where you personally forget to deallocate a chuck of memory. This still does not explain what I mean by memory leak though. I am talking about what happens when you hold on to a reference of an object long after it is needed. This happens very easily with private class variables and static variables. Lets talk a bit about garbage collection:

(This is simplified and I am sure the Java garbage collector is far from trivial, but I will simply explain what I know) In a nut shell the garbage collector knows it’s time to get rid of an object when there are no more references to it in code. So if you are storing an object in a private class variable and no longer need it you should set that variable to null. Especially if the class is going to be around for most of the life of the program. This is quite plausible with things such as user interfaces. It is also worth mentioning that you can think of this as a tree like structure. If you stop referencing a class at the top of the tree the entire branch will be collected as long as the only references to the sub objects occur within that branch.

In Spheriosity the problem I had was that after a user selected ‘New’ to clear the sphere I simply removed the highest node in the scene graph from the scene graph and did not clear all of the objects out of it. This caused everything in the frontend and backend to be kept around! All it took was a single line to clear out the scene graph. There were issues where I would get rid of some frontend objects but it was still an observer to something in the backend. As such the garbage collector would never collect it.

Now that I have learned all of this I will be extremely careful to avoid any future memory leaks. I am also going to be more careful when I explain memory management in java to people. I hear people say all the time that it is so amazing and they make it sound completely fail proof, but that is NOT the truth. You still need to be careful with how you manage memory. There is an entirely separate issue here known as heap smashing and in short it is caused by calling ‘new’ too much and forcing the garbage collector to work overtime! This is a conversation for another day, however.

I hope that I have enlightened at least one person about some of the pitfalls of Java. I still like the language and the library support is awesome. However I will never again say the memory management is easier than C++. The reality is that you have to be just as careful! Why do I care so much about memory usage? Well, I don’t like programs that are memory hogs so I try to create ones that don’t hog memory in their own right.

Sometimes I start to think Java itself is a memory hog by default because of the virtual machine and I do get concerned about that. However, without Java3D Spheriosity wouldn’t be anything that amazing so for now I will be sticking with Java 🙂

PS: The cross platform support is nice too 😀


Update Slowdown

July 28, 2008

For the next week or two I won’t be writing as much as I normally do. Nothing is wrong, I just won’t be using my computer nearly as much as I won’t come up with any topics worth talking about. I have picked up a book about MySQL and I hope to learn at least the basics about running a MySQL server and how to create and manage a database. It is a shame my college does not offer any courses in database management, but I don’t mind learning about it on my own.

All I will be doing with Spheriosity is updating the comments and working on some of the documentation 🙂


Gradius V — Finally, I beat the dang game!

July 26, 2008

Lately I have had some more time to enjoy the occasional video game. For a few years now I have had an obsession with being able to beat Gradius V. For those who don’t know Gradius V is one of the more popular titles in side scrolling shooters. The game requires you to be able to watch many bullets flying around your ship which being able to take down the necessary enemies. In order to make the game more manageable the hit box for your ship is insanely small. Gradius V could almost be considered a Maniac Shooter, but it falls short in that category because there simply aren’t enough bullets on screen (if you have ever played a true maniac shooter… then you would know).

Even though this game can be insanely frustrating at times it is well worth playing if you can stick with it. When you beat a level it is quite an awesome feeling because of the shear difficulty involved. If you can beat a level without losing a single life, that is even more incredible. I really enjoy challenging my ability to move the ship just tiny bits in order to avoid tight obstacles and swarms of bullets/lasers. It is a true test of one’s ability to have precise control. It is games like this that still bring glory to the standard video game controller. Even though I am a huge fan of the Wii, I can’t see any of the motion sensing features of the Wiimote being used in a Gradius type shooter.

After finishing a game like Gradius V it makes me think there is still a place for the traditional video game controller. I hope to continue playing Gradius V and maybe, some day, I will be able to beat it on a difficulty other than ‘very easy’ (which is anything but… IMO).


Intersection of Spherical Circles (Finally!)

July 23, 2008

For the past two weeks I have been pondering on and off how I would calculate the location of the intersection of two spherical circles. I really want Spheriosity to be as complete as possible and having the intersection tool only work on Spherical lines/line segments seems like a real lame idea. So I have finally devised an algorithm which can correctly determine the intersection points. I will give a brief overview of it here. I will leave out details about different parts of the algorithm which I feel are either trivial or would need their own blog post to explain ;).

So we start with two circles… What are the possibilities for their arrangements in terms of intersections:

  1. The most simple is if the circles are not anywhere near each other and don’t intersect.
  2. One circle could be “inside” the other. In this case the circles obviously do not intersect.

    One circle inside the other

    One circle inside the other

  3. The two circles could intersect only in one spot. This could happen in a number of ways:
    • Case 1:

      First Intersection Case

      First Intersection Case

    • Case 2:

      Intersection Case 2

      Intersection Case 2

  4. Then there is the case where the circles intersect twice. This is perhaps the most common case in terms of what users will see, but since the other cases are easy to construct we must also deal with them.

So that loosely describes my problem and the different scenarios that need to be considered. So… on to the solution! Much of this boils down to finding the intersection of two planes. Each circle on the sphere defines it’s own plane which basically slices the sphere, and the intersection of that plane and the sphere could also be used to form the circle. So the intersection of the planes formed by both circles forms a line which, if it goes through the sphere, can be used to find our points of intersection.

Defining that line of intersection turned out to be the largest problem. It was easy enough to get a vector going in the correct direction but I still needed a point to form the line and perform any sort of calculation on it. Here are the steps I take to find the intersection and make sure one actually exists:

  1. Consider two circles AB and CD (defined by center point and radius point).
  2. Find the normal vector to the planes formed by each circle. We will call these vectors a and c
  3. Take a x c if the magnitude squared of the resulting vector is 0 you can stop now because the planes are parallel, and the circles could not possibly intersect (or are coincident).
  4. Form an axis of rotation, r, between points A and C.
  5. For both circles form lines by rotating their respective center points forward and back by the angle formed between their center points, the center of the sphere, and their radius points. (call these lines l and m.
  6. Find the intersection of lines l and m and call this point I
  7. Find the intersection of the line formed by using point I and the cross product of a and c with the sphere.
  8. Consider the following cases:
    • Case 1: Line does not intersect the sphere: no intersection points
    • Case 2: Line intersects once with the sphere: one intersection point
    • Case 3: Line intersects twice with the sphere: two intersection points

There you have it! I know I left some details out, but writing out every single step would make this a really long post ;).


Python 2.5 and encryption — PyCrypto under Windows

July 20, 2008

[Edit: 8-13-08] – Upon request I have provided a link to an installer for PyCrypto-2.0.1 that is compiled for Python 2.5. You can download it here . I didn’t post it originally because I was not sure how long I could provide a link for. This one should be good for about a year … 🙂 .

Note: The steps listed here will only work on Python 2.5 and above as that is when they added support for allowing MinGW to compile code

I mentioned in a previous post that I was looking for a way to get public/private key encryption in Python and I was having a bugger of a time until I found ezPyCrypto. I don’t know if I have mentioned this before, but I have been an Linux user for about 4 years now. Specifically Gentoo Linux ,and I would never run another OS now that I have been a Linux user. At any rate that’s not the point of this post. Since the script I was developing had to run on Windows I needed to install PyCrypto (it’s a dependency for ezPyCrypto). Well this would be trivial except that PyCrypto has C code that needs to be compiled. There are binary builds on the PyCrypto site for both Python 2.3 and 2.4, but not 2.5 which I am running. I wasn’t going to let this stop me however. The rest of this post will explain what you need to do in order to get PyCrypto working under Windows with Python 2.5. After completing this you will also be able to build your own installer that you could package with your scripts to let people who don’t want to install a C compiler run your code 🙂

The first thing you are going to want to do is install MinGW . MinGW will give you a nice C and C++ compiler for Windows. Just follow the instructions on their site and you will be good to go. After you have MinGW installed you will probably want to add entries to the Windows PATH variable so that when you are in a terminal you will be able to directly access MinGW. [As a note I still run Windows XP so these instructions will be done with that in mind] Doing this is quite simple:

  1. Right Click My Computer –> Properties –> Advanced –> Environment Variables.
  2. You will see User and System variables. If you want all users to use MinGW edit the Path entry in there. Otherwise add a Path variable under User variables.
  3. Go to the Path variable from step 2. Add an entry to the Path that points to MinGW’s bin directory. For me this was “C:\MinGW\bin” but it all depends on where you installed MinGW. Note: Entires in Windows Environment variables are separated by ‘;’
  4. Click ok a bunch of times

While you are changing environment variables you will want to add the main directory for Python to your path. For me this was: “C:\Python25”. This made my final User Path entry: “C:\MinGW\bin;C:\Python25”

Now that you are done changing environment variables you will want to reboot your computer so that Windows gets your changes. Really… you will regret it if you don’t reboot!

Now download PyCrypto and unpackage it. This turned out to be problem enough because not many people keep programs around that open .tar.gz files. Since am a Linux user I just unpacked them in Linux and transferred them to Windows (I run Windows XP under VirtualBox ). However, if that is not an option you can download and install IZarc Archiver. IZarc has been my favorite [Windows] extraction tool for a long time and it supports just about every archive format imaginable.I would recommend extracting the contents of PyCrypto to your desktop. Now is when the first starts!

First, open up a terminal. We will only be using a few commands and you don’t have to be a terminal wiz kid to do this. I normally open a terminal by going: Start –> Run –> “cmd” –> Press Enter

Now that you have a terminal up you want get to the PyCrypto directory. To move between directories in the terminal we use the “cd” command.

cd PATH-GOES-HERE

So, for example here is the command I used to get to where I had PyCrypto:

cd C:\Documents and Settings\Jinto\Desktop\pycrypto-2.0.1

Of course that command will only work for you if your user name is Jinto and you extracted it to the desktop exactly like I did 😉 So modify it to fit your needs. Once you are in the pycrypto directory do a quick:

dir /w

To make sure you see files. Specially make sure setup.py is there. We need to run that setup script and tell it to build the libraries. To do this issue the following command:

python setup.py build -c mingw32

If all goes well it should build without any troubles and all that is left is to install it by issuing the following command:

python setup.py install

You should be all set to use PyCrypto now, or to install ezPyCrypto which uses PyCrypto. As a bonus feature if you are looking to make an executable installer for PyCrypto you can run the following command:

python setup.py bdist_wininst

This will leave you with a .exe file located in the “dist” folder.

I hope this helps everyone get PyCrypto running under Windows. For those of you Linux users who think I am leaving you out check your distro specific respository system they probably already have a package for PyCrypto!


Reading all the Documentation…

July 19, 2008

So apparently when people the time to write something down they wrote it down for a reason. I happened to have missed this simple fact recently when I was working on some Python scripts. I was trying to separate the scripts into different folders based on what they did. Simple enough, but then I ran into the issue of certain scripts needing to go around folder boundries. Of course, Python supports this feature using it’s import system.

This is where my trouble was. I was reading the article about how import works from the standard Python docs. So I read as much as I thought I needed and skipped over, what I thought at the time, to be unimportant. As it turns out the ability to do relative imports using ‘..’ is a feature of only Python 2.5 *sigh*. Alright, so I could have just installed Python 2.5, but I didn’t want to limit this code to running on Python 2.5 for no good reason. So I went back and changed the code to using absolute imports which took around 30 minutes because there were a decent number of files to play with.

So how did I miss this in the documentation? Well I managed to skim over the part which mentions this is only for Python 2.5 (I blame myself for this, btw). I take this as a lesson to pay closer attention when reading documentation. It may have taken me an extra 5 or 10 minutes to read all the documentation about imports and Python… but I will would have saved half an hour of my time if I had taken the extra effort 🙂


The Importance of White Space in Code

July 18, 2008

For almost as long as I have been writing code I have tried my best to improve upon my coding style. This is, of course, an area of much controversy among computer scientists. What makes “good” style? Sometimes its purely a matter of opinion. What I find easy to read might not be so easy for someone else. I suppose this is one reason you might argue that programmers should all try and adhere to similar styles. This way any code would be just as readable to anyone.

Almost every language I have ever used allows you to put in more white space than you need, and anywhere you want to. I find this to be quite a useful feature. Not because I think it allows me to write better algorithms, but because it helps me organize the code and suggest certain things to the reader. To some degree making readable code is very much an art [one that I do not claim to have mastered]. I think adding white space in blocks of code to segment it into different sections is good practice. Lets take the following C code for example. Keep in mind that this could be any language and the same concepts apply:

#include <stdio.h>
#include <stdlib.h>
int main(int argv,char** argc)
{
  int x;
  int y;
  int sum;
  for(x=0;x<10;x++)
  {
    for(y=0;y<10;y++)
    {
      sum=x+y;
      sum=sum+x*x+y*y;
      printf("Random number is %d\n",sum);
      printf("yay for loops\n");
    }
  }
  exit(0);
}

Now, I will be the first to admit that this code is fairly random and doesn’t do anything of extreme usefulness, but that is not the point here. Notice this same program with a little extra white space added:

#include <stdio.h>
#include <stdlib.h>

int main(int argv, char** argc)
{
  int x;
  int y;
  int sum;

  for(x = 0 ; x < 10; x++)
  {
    for(y = 0; y < 10; y++)
    {
      sum = x+y;
      sum = sum + x*x + y*y;

      printf("Random number is %d\n", sum);
      printf("yay for loops\n");
    }
  }

  exit(0);
}

To me, this now really pops out at you, and it is much easier to see the different “areas” of this code. You have the #includes which are separated from main. This lets you know when the real code begins and puts a break between the includes and the actual code. It suggests a change in context! The next place I added white space was between the arguments in the header to main. This allows the variables (argc and argv) to stick out more to the eye.

In the actual function I put a space after I declared all the variables. Again, I use the idea that with the return we will have a change of context going from variable definitions to more concrete code. In each for loop I separated the different parts of the loop constraints to make them a tad easier to read.

Within in the inner for loop I added the most space. First I separated the mathematical statements from the print statements. You may not always want to do this because sometimes you might group a print statement for a specific calculation with the rest of the calculation, it all depends on what you are trying to say. Next I separated the different parts of the second equation to bring out the more
interesting parts. Sometimes I will add parenthesis to really be explicit as to what I am trying to do, but this didn’t see to warrant that.

Finally at the end I separated the exit(0) from the end of the for loops because it is not really part of that block of code.

So there you have it. This is a bit of a trivial example, but I think it shows that a little white space can go a long way in bringing things out to a foreign reader. Remember, the new person who reads your code will be looking for any hints they can get as to its functionality. When you are writing the code you may not need the white space to understand what is going on. However, 6 months later it
could even help you figure out what was originally intended as well as the newcomer to the code base! There’s plenty of other tricks to help make code more readable: descriptive variables, good function names, good functional decomposition, etc. I just wanted to point out one area that I think can be easily overlooked 🙂


Java3D, the PickRay, and the PickCylinderRay

July 14, 2008

Today I was struggling to figure out why I could not highlight a line segment in Spheriosity. After much fiddling around I discovered that the problem only occurred when I was using a PickRay to select objects instead of my normal PickCanvas. For those that don’t know a PickCanvas is made to pick objects based on the x and y coordinates of the cursor and a PickRay has to be defined with a starting point and vector indicating its direction. I was a bit disappointed because I thought I had already solved this problem. The general problem here is: ‘How do I take the cursor location and select something in a Java3D BranchGroup?’

My final solution to this problem was to use a PickCylinderRay, which defines an infinite cylinder going in a defined direction from a defined starting point and with a defined radius. Switching to the PickCylinderRay actually solved more than one of my problems. Previously when I was using the PickCanvas I found it very difficult to select objects at times. Especially the line segments (LineStripArrays) . I know that you can set different tolerances to the PickCanvas but I was having a heck of a time getting that happy. The only problem I ran in to with the PickCylinderRay was that if the radius was too large it would pick objects that weren’t even close to the cursor. However, this makes sense 🙂 Here is what the code looks like to define the vector from the camera to the cursor:

public void getCameraToMouseVec(Canvas3D myCanvas, Point clickPos,
                                Point3d cameraPoint, Vector3d dir)
{
     Point3d mousePos = new Point3d();

     //Getting current mouse and camera locations
     myCanvas.getPixelLocationInImagePlate(clickPos.x, clickPos.y, mousePos);
     myCanvas.getCenterEyeInImagePlate(cameraPoint);

     //This block of code converts our image plate coordinates out to virtual world coordinates because
     //that's ultimately what we care about.
     Transform3D motion = new Transform3D();
     myCanvas.getImagePlateToVworld(motion);

     //We do this convertion for both the camera and for the mouse position.
     motion.transform(mousePos);
     motion.transform(cameraPoint);

     //Get the three components of the vector going from the camera location to the eye
     dir.x = (mousePos.x - cameraPoint.x);
     dir.y = (mousePos.y - cameraPoint.y);
     dir.z = (mousePos.z - cameraPoint.z);
}

So after this function completes the variables cameraPoint and dir will be set to the correct values to call .setShapeCylinderRay() of the PickTool class . Here is a sample of the code which takes the output of the previously displayed function and uses it to make a selection:

public void mousePressed(MouseEvent arg0) //Called be Java through MouseListener interface
{
     //In Spheriosity I actually declare these once for the class and reuse them
     Point3d tmpPoint = new Point3d();
     Vector3d tmpVec  = new Vector3d();

     //I assume that 'myMainBranchGroup' is a member of the class that this function is in
     //and is the BranchGrounp we want to be picking from.
     PickTool myPicker = new PickTool(myMainBranchGroup);

     //I also assume that 'myCanvas' is a member of this class
     getCameraToMouseVec(this.myCanvas, arg0.getPoint(), tmpPoint, tmpVec);

     //Use the data gathered from getCameraToMouseVec to make the PickCylinderRay
     myPicker.setShapeCylinderRay(tmpPoint, tmpVec, .1f);

     PickResult result = myPicker.pickClosest();

     ... code to handle what was selected ...
}

There you have it! That is how I solved my little problem with PickRays not working. I’m glad I stumbled upon the original problem because I truly think this solution works much better given the rest of the code base in Spheriosity.

There are a few things to note here. One is that the .1f in the .setShapeCylinderRay() function should be changed depending on your needs (it determines the radius of the cylinder). Lower values mean the cursor has to be closer to the object higher values mean the cursor can be further away. Also the output of the getCameraToMouseVec() function could also be used to define a PickRay if that is truly what you want.

Hopefully this was able to help one or two people trying to select things in Java3D. If not… well at least it serves as a bit of rationale for some of what I have done with Spheriosity 😀


Spheriosity and Efficiency

July 12, 2008

I spent some time today trying to add, what I think, would be a neat feature in Spheriosity. The feature would let you see the line or circle you are about to create when you are trying to make new lines and circles. Currently you just select the end points and then the program draws the line. With this feature, after you select the first point Spheriosity will show you were the line or circle will end up after you place the second point.

I figured this would be pretty simple and that I wouldn’t run into any of the efficiency issues I constantly worry about. Unfortunately I did… This took me completely by surprise because with the point moving feature everything seems to happen quite smoothly! So it was tough for me to believe that now this feature was slow.

I further inspected the code to find that the difference was in how point moving vs. how this feature was implemented. The way the code is currently structured is that all user related activities are fed through a state machine. The different states are like MovePointState , DrawPointState etc.. Each state extends a base class with 6 or 7 (can’t remember exact number) abstract functions. The class which receives all mouse related events then forwards the appropriate data to the functions of the current. Any given state can ignore functions it does not need by simply implementing them as an empty function block:

public void addPoint(Point3f newPt) {}

The function I currently use to get data from the mouse have the following function headers:

/*
 * @param mouseEvent - MouseEvent sent by Java
 * @param worldLoc   - Pointer location mapped to the surface of the sphere
 */
public void newMouseLoc(MouseEvent mouseEvent, Point3f worldLoc);

Java can give you the new location of the mouse in one of two different ways, but now both at once. By implementing the MouseMotionListener interface there are two functions. mouseDragged and mouseMoved. Even though the mouse is being moved while you are dragging in Java choose to implement it such that only one function or the other is called at once. So both mouseMoved and mouseDragged call my function [newMouseLoc]  . In mouseMoved I house the code which determines what lines or points get highlighted depending on the current state. In mouse dragged I simply pass right along the data to newMouseLoc.

So, the MovePointState gets the data from mouseDragged where the only overhead is the calculation I have to do in order to convert the mouse location to the surface of the sphere (quite a large calculation…) Where as in mouseMoved I did the same calculation as in mouseDragged and also did an intersection test with Java3D to see what, if anything, needed to be highlighted. Since part of that intersection test probably involved math that was already done to map the the user click to the sphere… Now… if this calculation was just happening once or twice I’m sure you would never notice. Unfortunately it happens every time the cursor moves. That in itself doesn’t make the the program lag though. Also added to the mix is that to draw each line we really make a bunch of small lines (100 to be exact) because a line on the sphere isn’t the same as the Euclidean version Java3D provides. So now we have that calculation coupled with the code that figures out the end points for the 100 lines and at the very least a for loop with 100 iterations … all each time the cursor moves!

This is why I worry about optimizing Spheriosity. I do my best to keep the code clean, but no one wants to use a slow program.

In terms of a solution to this problem… I moved some of the calculations around so I am doing less math to figure out what to highlight or not, and that seems to solve most of the issues. I still want to optimize it some more as I think I am approaching a dangerous threshold for minimum requirements 🙂 to run the program.


Spheriosty and Parallel Transport on the Sphere

July 11, 2008

Today I was writing some unit tests for Spheriosity and I discovered a flaw with the code that currently handles parallel transported lines. For those of you who are unfamiliar with the concept of parallel transport I will do my best at describing this to you.

Basically start with any two intersecting lines:

Two intersecting lines

Two intersecting lines

Now, slide the first line along the second keeping the angle between the two lines the same. You have just parallel transported your first line! By definition parallel transport merely keeps the angle between those two lines the same as they move.

Parallel transported line

Parallel transported line

Why is that so dang special? But wait! Isn’t that just a fancy way to say “keep the lines parallel”? Well, on the Euclidean plane, yes. However on a sphere there is no such thing as parallel. Two straight lines [known as great circles on a sphere] will always intersect. If you don’t believe me you can always try it out for yourself. Any true mathematician probably doesn’t believe me, as I have not provided a proof 🙂 .

Parallel transport of a great circle

Parallel transport of a great circle

Notice in the above picture that we have transported along the horizontal line. It is obvious that the original line (right line) and the transported line (left line) will intersect.

It is also interesting to note that on a sphere parallel transport is really the same as rotation! (Awesome… I know!) So where to rotate… well you can probably figure it out by simply looking at the sphere, but we want to try and put it in writing.  In order to find the axis to rotate on we have to imagine vectors going from the center of our sphere to the two end points that define our line of transport. Lets call those vectors a and b. Then, we take do: a x b (a cross b) and get some vector c. If we place vector c at the center of the sphere then we get our axis of rotation. Let call this primary axis just so we have name for it

So in the context of Spheriosity I want to take a line of transport, a line to transport and a cursor location and transport the ‘line to transport’ to where the cursor is, but making sure it is with respect to the ‘line of transport’. Translating the cursor location to a line parallel transporting is not a one step process, sadly. Since I don’t know where the cursor will be I had to find a way to map out the cursor location to the line being transported. [A big thanks to my professor who figured this one out]

  1. We use the point provided by the user and the axis of rotation for the line of transport to give us a new axis of rotation. Just to have some order here lets call the user point U, the first axis of rotation primary axis, the line of transport line AB, original line we are transporting line CD, and the new axis of rotation secondary axis
  2. Next we measure the angle between the primary axis and the vector defined from the center of the sphere to point C
  3. Now plot the point which is the intersection of the axis of rotation with the sphere. There are two poential points, so plot whichever one you wish. We will call this point E. Rotate point E with the secondary axis by the angle computed from step 2
  4. Now the first point is in place. We will call this point F. We measure the angle between the vectors defined by going from the center of the sphere to point F and point C.
  5. Using the angle from step 4 we rotate point D using the primary axis
  6. Enjoy the glory of seeing the line parallel transported

There are actually some problems with that method. The first of which is figuring out which direction to rotate point D. The .angle() function of the Vector3f class in Java3D only returns an angle from 0 to PI. The way I figure this out is actually by use of tangent vectors and dot products. To get the tangent vector I actually cheat and only approximate the angle vector by rotating the point C a very small amount (.0001 radians) with the primary axis and use the original point C and the rotated point C to make my vector (vector t). Yes, a crude trick, but it’s quick and easy. Next I define a vector from the center of the sphere to the point the cursor is at (vector c). I take the dot product of t and c,  and if the dot product is negative I know to take the angle from .angle() and rotate that in the opposite direction. Perhaps I will write a separate entry and how the dot product is my hero, but for now you will have to trust that it makes sense 🙂 .

The last issue, which I just discovered today, is that if the line we want to transport has one of it’s endpoints as the axis of rotation the aforementioned method does not work. So I simply special case this, and rotate the end point which isn’t the axis of rotation(point D) by the angle formed by the vectors made from the center of the sphere to the cursor point, and point D. Then I use the same tangent vector trick to figure out which way to rotate.

That’s all for now. Hopefully you at least understand parallel transport a little better :). Please let me know if some of that was unclear and I will do my best to make it sound better.