[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Newsgroup Home]
[news.eclipse.gef3d] Draft: org.eclipse.draw3d.geometry

Hi all,

I have created a new plug-in project "org.eclipse.draw3d.geometry" at the SVN repository of GEF3D at FernUni Hagen (As long as GEF3D has not passed the legal review process, it is still hosted at FernUni Hagen). Due to server capability restrictions, the SVN (at FernUni Hagen) is not publicly available. I'll be happy to send you the information on your request, simply write me a mail.

This project is an internal incubator project (not the Eclipse incubtor!) for the design and implementation of 3D geometry classes such as Vector3f. For that, Math3D in project org.eclipse.draw3d (.geomerty) was renamed to TempVectors.

Cheers,

Jens


Background:

We are trying to remove all LWJGL dependencies from o.e.draw3d (and move them into a new project to be created called o.e.draw3d.lwjgl). That is all GLx-methods will be replaced in future versions by methods defined in an interface (to be created) called Graphics3D. Besides that, we have to remove all dependencies fromÂorg.lwjgl.util.vector. Thus we have to create our own 3D geometry classes. Both refactorings will be done by Matthias as part of his bachelor thesis. We start with the geometry classes and then the Graphics3D stuff will be changed.
For the geometry classes, I have created this new project. Matthias can implement the new geometry classes in this project, we can also easily change the design there and add test cases. When the package is finished, it will be moved into o.e.draw3d and all LWJGL geometry classes will be replaced by out own classes. The current project contains some example interfaces and classes, and most important a package-info.java documentation. In this documentation I have explained the design of our geometry classes. This design is a result of _my_ experiences with several other geometry packages (Java3D and LWJGL) and it is a suggestion or draft.Â
Math3D has been renamed in the current version since this class is expected to be implemented again in the new version. Since the new geometry classes are to be thread-safe, the temporary vectors are to be removed from the geometry package (they will be used by draw3d in future versions, too).
Currently the new project isn't used by Draw3D or GEF3D.


After a short discussion phase we will implement the geometry package. I expect this geometry package to be designed and implemented within 3 weeks.

Package org.eclipse.draw3d.geometry Description
===============================================
3D geometry classes. These classes are used with GEF3D, their functionality is very similar to Java3D's vecmath package or LWJGL's vector package.


Contained Classes
-----------------
This package contains 3D geometry classes such as
- Vector3fImpl
- Vector4f
- Matrix3f
- Matrix4f
Each item is represented by
- an immutable interface I..., e.g. IVector3f
- an mutable interface with the name of the item, e.g. Vector3fImpl
- an implementation ...Impl, e.g. Vector3fImpl
All these classes implement the Serializable and Cloneable interfaces. There is no Vector2f, class org.eclipse.draw2d.geometry.Ray should be used instead.
We do not distinguish between tuple, vector, dimension, or point.


These classes define only constructors, getters and setters, cast operations, and some basic methods; most mathematical operations are defined in Math3D.

Explanation: This design was chosen to avoid too much operations: In other frameworks several variants of basically the same operation is defined, with confusing semantics. E.g. in Java3D's vecmath, Tuple3f.absolute() makes all values of a vector absolute, Tuple3f.absolute(Tuple3f) sets the values of the given tuple. In Draw2D, Point.negate() negates the values of the object itself, while Point.getNegated() returns a new instance with negated values. In Draw3D we simply provide a single operation, that is Math3D.abs(IVector3f, Vector3f) (or Math3D.negate(IVector3f, Vector3f) resp.), see below for further details.

Especially for use within Draw3D, the following classes are defined:
- SyncedVector3f -- a vector3f based on a
- BoundingBox3f (with immutable and mutable interfaces)
- SyncedBounds -- a bounding box based on
The synchronized classes only stores the delta of a 3D vector and a 2D vector, that is the floating values of the x and y attributes and the z value.
The synchronized classes do not store a reference to the 2D object with which they are synchronized. This is not possible in many situations, since the clients may not only modify the values of the 2D object (which would cause no problem), but the reference (of the attribute) is also changed (see org.eclipse.draw3d.Figure3D#getPreferredSize3D() and its implementation, especially org.eclipse.draw2d.Figure#getPreferredSize(int, int) Thus, the synced classes cannot implement the mutable interface!


All these upper mutable classes (and interfaces) implement the interface
- Transformable, 3D version of org.eclipse.draw2d.geometry.Translatable

Operations
----------
Most 3D operations are defined in the following class:
- Math3D -- Basic operations (such as add, mult), and 3D versions of operations defined in Math
The vector and matrix operations are provided as static methods. For performance reasons, these method signatures all follow this pattern:
- static MT operation(IT inParameter1, IT inParameter2, MT outParameter)
MT is to be replaced by the immutable interface, IT by the mutable interface respectively. Simply spoken inParameter1 and inParameter2 are handled confirming the operation, e.g. added or multiplied, and the result is stored in outParameter. The result is also returned by the method. If the outParameter is null, a new instance of type T is created. There is a trap which is handled by the operations: The outParameter can also be passed as an inParameter. In this case it may be possible that a value of the in/out-Parameter is overwritten by a result value -- the methods take care that the operation is correctly calculated by using temporary variables.
All methods and classes of this package are tested using JUnit tests.


Usage
-----
Since all classes are defined by immutable and mutable interfaces, classes using these 3D geometry classes should use the immutable interface where ever possible. org.eclipse.draw2d doesn't distinguish between immutable and mutable, thus always the mutable version is returned and we find comments such as "callers of this method must not modify the returned Rectangle." (from org.eclipse.draw2d.Figure#getBounds(). This problem is solved in Draw3D by using two kind of interfaces.


Most render frameworks such as LWJGL provide their own implementations of 3D geometry classes. Within the Draw3D adapters (e.g. org.eclipse.draw3d.lwjgl) special adapter classes are implemented for easily casting a draw3d 3D geometry object into an render framework specific ones.

Performance Issues
------------------
A discussion about performance issues can be found at http://lwjgl.org/forum/index.php/topic,2456.0.html. Here is a test I have implemented during this discussion.


The Test

Tested were two classes (or interfaces) implementing a Vector3f version. The first class (or interface) provides a read-only access while the second read-write access. Additional, a static method "add" is introduced as implemented in the current Vector3f class. Three different design alternatives were implemented:

- Concrete: The first one (called "Concrete") implements a concrete readable
class with final getters and protected fields. The writable class extends
this class providing setters.
- Abstract: The second version (called "Abstract") implements an abstract
readable class with abstract getters and no fields. The writable class
extends this class, defining the fields (public) and implementing final
getters and setters.
- Interface: The third version (called "Interface") defines a read-only
interfaces with getters, the writable class implements this interface and
defines all fields (public) and final getters and setters.
The static add method has a similar signature in all three versions: left and right vector are passed as read-only instances, the result is a writable instance. If the passed result is null, a temporary variable is constructed and returned, otherwise the result is filled.


The benchmark was executed 4 times, two times with a server VM and two times with a client VM. For each VM, 1000000 calls of the add method and a setter were repeated 100 and 1000 times. The result are shown below and illustrated in the image.

The Result

On OS X 10.4, the last version using interfaces is the slowest one in all tests. Using an abstract class is more or less as fast as using a concrete readable class. Interestingly it is even sometimes a little bit slower! Also surprising is the fact that in some tests (with the server VM) creating new temporary instances (i.e. passing null as result parameter) is faster than using an in-out parameter. The server VM is in all tests much faster than the client VM. in some cases about 5 times. Even the slowest server tests is nearly as fast as the fastest client test!

On other machines with different JDKs and OS, different results were determined!

Conclusion

Using abstract readable base classes is the winner on OS X, but not on all machines. It is just as fast as using concrete classes. On the other hand, interfaces are very useful if adapters are to be implemented and may reduce the need for copying data. Since GEF3D is not a Gaming engine, interfaces may be good enough.