History
Programmers use vectors (in different spaces) for so many things it’s important foundation for many applications in respect to performance and maintainability. Java does not have operator overloading like in C++. It also doesn’t have macros (#define), so many packages have a delicate role to play in balancing maintainability and performance. Obviously this isn’t the first package for working with vectors for Java. The most used for 2D and 3D applications are:
The javax.vecmath package gets the job done, but it has some problems:
- Too many classes. They balanced performance by providing a different implementation for each space and precision with over 30 class/interfaces.
- Each implementation is blind to another. This forces you to write the glue between different spaces or precisions, which there is plenty to write because of how many different objects there are.
- It has an odd blend of procedural and object-oriented style. For example, the
addoperation can be invoked in many ways, some which mutate the object and some that mutate a parameter.
While these are specific to their package and how it was implemented, it’s also very similar to other solutions written in object-oriented languages. Typically we’re given an x and y member variable and some primitive operations that mutate them or compute and return the result. Allocating objects for these elementary operations isn’t ideal, which is a performance issue, but there is a glaring maintainability issue as well. Take a simple vector expression like a + b * 0.5 involving scaling an object and adding it. If you’re okay with being able to destroy the contents of these vectors it can be done by simply:
b.scale(0.5); a.add(b);
However, if the contents of these vectors can’t be destroyed it could introduce some intermediate objects that are used for storage. What this is basically doing is forcing you to work backwards, basically by turning your inflix expressions into postfix and tasking you with maintaining them. Also consider that if you want to return a vector to an untrusted source you’ll have to clone that object to protect it. For real-time applications the balance between performance and maintainability is like a broken seesaw.
Power of Immutability
Java programmers are familiar with the awesomeness of immutability, since the java.lang.String is used by everyone from their first "Hello World". Doesn’t matter if you’re trimming a String or scaling a Vector, the general rule is operations don’t mutate an object. We can imagine that the String does this by creating new objects that point to different areas of the same char[] array, and the result is that derivative strings don’t take up additional memmory (other than for references). In a similar fashion Vector references inputs for evaluating an output. A great reference is provided in the documentation for what each class does, but here is a quick list of neat things:
- A Normal object can
return thisfor it’snormal(). - An Inverse object can
return Vector.this(it’s parent) for it’snegate(). - An
Inversesimply “flips” how theeval()methods are invoked. Sometimes the negation is performed as part of another operation, such as scaling by a uniform scalar. (In this case by negating the scalar) - A
Normalgets toreturn 1.0for it’slength(), so you can do simple comparisons with that.
Power of Mutability
While not as important as immutability, there is an exception for the Vector.Mutable object. This object provides direct access to applications that reference it as mutable. For example, this avoids creating a new vector everytime the position of the mouse changes, but doesn’t allow another application to change the position of the mouse without deep inspection (using instanceof
).
Runtime Inspection
You can do special analysis of Vector objects at run-time to take advantage of hardware or API integration. A great example is OpenGL”„¢. For example, you could inspect the usage of Vector.Sum and use glTranslate with it’s inputs. This would perform the operation on the GPU. This is nice in scenarios where logically that object hasn’t been re-evaluated, but graphically it needs to be evaluated.
Matrices
Support for square (n×n) matrices is implemented with bindings for Vector. It may seem odd that Matrix doesn’t directly use the Vector implementation to perform it’s operations, but this decided to improve memory without sacraficing performance in the Vector object. Similar to the advantages in the Vector with Normal and Inverse, the Matrix object has a Transpose and Minor nested classes. This also is nice because Minor makes det() calculation easier and shares more code for better overall performance.
License
Licensed under the LGPL version 3 or later. This is an Open Source license, and simply requires you to release all changes you make to the public domain.
Source Code
Source code is included in jives.jar, but you can also grab the source code from our Bazaar repository:
bzr pull http://santiance.com/bzr/jives/
This includes project files for Eclipse, and build files for generating the javadoc and JAR files. Please e-mail patches or branch locations for merging to kristopher.ives@gmail.com.