]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.g3d/src/org/simantics/proconf/g3d/base/TransformationTools.java
git-svn-id: https://www.simantics.org/svn/simantics/3d/trunk@22280 ac1ea38d-2e2b...
[simantics/3d.git] / org.simantics.g3d / src / org / simantics / proconf / g3d / base / TransformationTools.java
diff --git a/org.simantics.g3d/src/org/simantics/proconf/g3d/base/TransformationTools.java b/org.simantics.g3d/src/org/simantics/proconf/g3d/base/TransformationTools.java
new file mode 100644 (file)
index 0000000..9ea0cb8
--- /dev/null
@@ -0,0 +1,530 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007- VTT Technical Research Centre of Finland.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.proconf.g3d.base;\r
+\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Tuple3d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.db.Graph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.layer0.utils.EntityFactory;\r
+import org.simantics.layer0.utils.IEntity;\r
+import org.simantics.proconf.g3d.Resources;\r
+import org.simantics.proconf.g3d.stubs.Orientation;\r
+import org.simantics.proconf.g3d.stubs.Position;\r
+\r
+public class TransformationTools {\r
+       \r
+       private static boolean DEBUG = false;\r
+       \r
+       private Resource childRelation;\r
+       private Resource parentRelation;\r
+       \r
+       public TransformationTools(Resource childRelation, Resource parentRelation) {\r
+               this.childRelation = childRelation;\r
+               this.parentRelation = parentRelation;\r
+       }\r
+       \r
+       public IEntity getParent(IEntity node) {\r
+               return node.getAtMostOneRelatedObject(parentRelation);\r
+       }\r
+       \r
+       public Point3d getLocalFromWorld(IEntity node, Point3d worldCoord) {\r
+       IEntity parent = getParent(node);\r
+        if (parent == null) {// this is a rootnode ( has no transformation) \r
+               return worldCoord;\r
+        }\r
+\r
+        Point3d local = getLocalFromWorld2(parent,worldCoord);\r
+        return local;\r
+    }\r
+    \r
+    \r
+    private Point3d getLocalFromWorld2(IEntity node, Point3d worldCoord) {\r
+       IEntity parent = getParent(node);\r
+        if (parent == null) {// this is a root node ( has no transformation) \r
+               return worldCoord;\r
+        }\r
+\r
+        Point3d local = getLocalFromWorld2(parent,worldCoord);\r
+        if (node.hasStatement(Resources.g3dResource.HasLocalPosition))\r
+            local.sub(G3DTools.getPoint(node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition)));\r
+        if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) {\r
+            Quat4d q = new Quat4d();\r
+            q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation)));\r
+            q.inverse();\r
+            MathTools.rotate(q, local, local);\r
+        }\r
+        return local;\r
+    }\r
+    \r
+    public Point3d getWorldFromLocal(IEntity node,Point3d localCoord) {\r
+       IEntity parent = getParent(node);\r
+        if (parent == null) // this is a rootnode ( has no transformation)\r
+            return localCoord;\r
+        return getWorldFromLocal2(parent, localCoord);\r
+    }\r
+    \r
+    private Point3d getWorldFromLocal2(IEntity node,Point3d localCoord) {\r
+       \r
+        if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) {\r
+            Quat4d q = new Quat4d();\r
+            q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation)));\r
+            MathTools.rotate(q, localCoord, localCoord);\r
+        }\r
+        if (node.hasStatement(Resources.g3dResource.HasLocalPosition))\r
+            localCoord.add(G3DTools.getPoint(node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition)));\r
+        \r
+        IEntity parent = getParent(node);\r
+        if (parent == null) // this is a rootnode ( has no transformation)\r
+            return localCoord;\r
+        \r
+        return getWorldFromLocal2(parent,localCoord);\r
+    }\r
+    \r
+    \r
+    public AxisAngle4d getLocalFromWorld(IEntity node, AxisAngle4d worldRot) {\r
+       IEntity parent = getParent(node);\r
+       if (parent == null) // this is a rootnode ( has no transformation)\r
+            return worldRot;\r
+\r
+        AxisAngle4d local = getLocalFromWorld2(parent,worldRot);\r
+\r
+        return local;\r
+    }\r
+    \r
+    private AxisAngle4d getLocalFromWorld2(IEntity node, AxisAngle4d worldRot) {\r
+       IEntity parent = getParent(node);\r
+        if (parent == null) // this is a rootnode ( has no transformation)\r
+            return worldRot;\r
+        AxisAngle4d local  = getLocalFromWorld2(parent,worldRot);\r
+        \r
+        if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) {\r
+            Quat4d q = new Quat4d();\r
+            q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation)));\r
+            q.inverse();\r
+            Quat4d q2 = new Quat4d();\r
+            q2.set(local);\r
+            q.mul(q2);\r
+            local.set(q);\r
+        }\r
+\r
+        return local;\r
+    }\r
+    \r
+    public AxisAngle4d getWorldFromLocal(IEntity node,AxisAngle4d localRot) {\r
+       IEntity parent = getParent(node);\r
+       if (parent == null)\r
+               return localRot;\r
+\r
+        return getWorldFromLocal2(parent,localRot);\r
+    }\r
+    \r
+    private AxisAngle4d getWorldFromLocal2(IEntity node,AxisAngle4d localRot) {\r
+       \r
+        //System.out.print("wtl " + node.getResource() + " " + localCoord);\r
+        if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) {\r
+            Quat4d q = new Quat4d();\r
+            q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation)));\r
+            Quat4d q2 = new Quat4d();\r
+            q2.set(localRot);\r
+            q.mul(q2);\r
+            localRot.set(q);\r
+        }\r
+        \r
+        IEntity parent = getParent(node);\r
+        if (parent == null) // this is a rootnode ( has no transformation)\r
+            return localRot;\r
+        \r
+        //System.out.println(" " + localCoord);\r
+        return getWorldFromLocal2(parent,localRot);\r
+    }\r
+    \r
+    public Point3d getLocalFromWorldR(IEntity node, Point3d worldCoord) {\r
+       \r
+        Point3d local = getLocalFromWorldR(null,worldCoord);\r
+        if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) {\r
+            Quat4d q = new Quat4d();\r
+            q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation)));\r
+            q.inverse();\r
+            MathTools.rotate(q, local, local);\r
+        }\r
+        \r
+        IEntity parent = getParent(node);\r
+        if (parent == null) // this is a rootnode ( has no transformation)\r
+            return worldCoord;\r
+        \r
+        return local;\r
+    }\r
+    \r
+    public Point3d getWorldFromLocalR(IEntity node,Point3d localCoord) {\r
+       \r
+        if (node.hasStatement(Resources.g3dResource.HasLocalOrientation)) {\r
+            Quat4d q = new Quat4d();\r
+            q.set(G3DTools.getOrientation(node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation)));\r
+            MathTools.rotate(q, localCoord, localCoord);\r
+        } \r
+        \r
+        IEntity parent = getParent(node);\r
+        if (parent == null) // this is a rootnode ( has no transformation)\r
+            return localCoord;\r
+        \r
+        return getWorldFromLocalR(parent,localCoord);\r
+    }\r
+    \r
+    /**\r
+     * Updates transformations of all children of given node\r
+     * @param node\r
+     */\r
+    public void propagateTransformChange(IEntity node) {\r
+        Collection<IEntity> children = node.getRelatedObjects(childRelation);\r
+       IEntity wp = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition);\r
+        IEntity wr = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation);\r
+        Quat4d rot = new Quat4d();\r
+        if (wr != null)\r
+            rot.set(G3DTools.getOrientation(wr));\r
+        else\r
+            rot.w = 1.0;\r
+        Point3d pos = new Point3d();\r
+        if (wp != null)\r
+            pos = G3DTools.getPoint(wp);\r
+        if (DEBUG) {\r
+               if (wr != null)\r
+                       System.out.println("propagate transform " + node.getResource() + " " + pos + " " + G3DTools.getOrientation(wr));\r
+               else\r
+                       System.out.println("propagate transform " + node.getResource() + " " + pos);\r
+        }\r
+        for (IEntity n : children) {\r
+            IEntity lPos = n.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalPosition);\r
+            IEntity lRot = n.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation);\r
+            if (DEBUG) System.out.print(n);\r
+            if (lRot != null) {\r
+               AxisAngle4d la = G3DTools.getOrientation(lRot);\r
+                AxisAngle4d wa = getWorldFromLocal(n, la);\r
+                IEntity wo = n.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation);\r
+                G3DTools.setOrientation(wo,wa);\r
+                storeProperty(wo.getResource(), wa);\r
+            }\r
+            if (lPos != null) {\r
+                Point3d lp = G3DTools.getPoint(lPos);\r
+                if (DEBUG) System.out.println(lp);\r
+                MathTools.rotate(rot, lp, lp);\r
+                lp.add(pos);\r
+                IEntity nwp = n.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition);\r
+                G3DTools.setTuple3(nwp, lp);\r
+                if (DEBUG) System.out.print(" " + lp);\r
+                storeProperty(nwp.getResource(), lp);\r
+            }\r
+            if (DEBUG) System.out.println();\r
+            propagateTransformChange(n);\r
+            \r
+        }\r
+    }\r
+    \r
+    /**\r
+     * Updates transformation of one child node without changing its local transformation.\r
+     * @param parent\r
+     * @param node\r
+     */\r
+    public void propagateLocalTransformChange(IEntity parent, IEntity node) {\r
+        //Collection<IEntity> children = parent.getRelatedObjects(childRelation);\r
+       IEntity parentWP = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition);\r
+        IEntity parentWR = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation);\r
+        Quat4d parentWRot = new Quat4d();\r
+        if (parentWR != null) {\r
+            parentWRot.set(G3DTools.getOrientation(parentWR));\r
+           \r
+        } else\r
+            parentWRot.w = 1.0;\r
+        Point3d parentWPos = new Point3d();\r
+        if (parentWP != null) {\r
+            parentWPos = G3DTools.getPoint(parentWP);\r
+        }\r
+        if (DEBUG) {\r
+               if (parentWR != null)\r
+                       System.out.println("propagate transform " + parent.getResource() + " " + parentWPos + " " + G3DTools.getOrientation(parentWR));\r
+               else\r
+                       System.out.println("propagate transform " + parent.getResource() + " " + parentWPos);\r
+        }\r
+        //for (IEntity n : children) {\r
+        //     if (!n.equals(node))\r
+        //             continue;\r
+            IEntity lPos = node.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalPosition);\r
+            IEntity lRot = node.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation);\r
+            if (DEBUG) System.out.print(node);\r
+            if (lRot != null) {\r
+               AxisAngle4d aa = G3DTools.getOrientation(lRot);\r
+               storeProperty(lRot.getResource(), aa);\r
+                AxisAngle4d la = getWorldFromLocal(node, aa);\r
+                IEntity wo = node.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation);\r
+                G3DTools.setOrientation(wo,la);\r
+                storeProperty(wo.getResource(), la);\r
+            }\r
+            if (lPos != null) {\r
+                Point3d lp = G3DTools.getPoint(lPos);\r
+                storeProperty(lPos.getResource(), lp);\r
+                MathTools.rotate(parentWRot, lp, lp);\r
+                lp.add(parentWPos);\r
+                IEntity nwp = node.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition);\r
+                G3DTools.setTuple3(nwp, lp);\r
+                storeProperty(nwp.getResource(), lp);\r
+            }\r
+            if (DEBUG) System.out.println();\r
+            propagateTransformChange(node);\r
+            \r
+        }\r
+//    }\r
+    \r
+    public static void resetTransformation(IEntity shape) {\r
+               Graph graph = shape.getGraph();\r
+               if (shape.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalPosition) == null) {\r
+\r
+                       // LocalPosition p = LocalPosition.createDefault(graph);\r
+                       Position p = Position.createDefault(graph);\r
+                       shape.addStatement(Resources.g3dResource.HasLocalPosition, p);\r
+                       // WorldPosition p2 = WorldPosition.createDefault(graph);\r
+                       Position p2 = Position.createDefault(graph);\r
+                       shape.addStatement(Resources.g3dResource.HasWorldPosition, p2);\r
+                       p.setX(new double[] { 0.0 });\r
+                       p.setY(new double[] { 0.0 });\r
+                       p.setZ(new double[] { 0.0 });\r
+\r
+                       p2.setX(new double[] { 0.0 });\r
+                       p2.setY(new double[] { 0.0 });\r
+                       p2.setZ(new double[] { 0.0 });\r
+\r
+               } else {\r
+                       G3DTools.setTuple3(shape.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition), 0.0, 0.0, 0.0);\r
+                       G3DTools.setTuple3(shape.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition), 0.0, 0.0, 0.0);\r
+               }\r
+               if (shape.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation) == null) {\r
+\r
+                       // LocalOrientation r = LocalOrientationFactory.create(graph);\r
+                       Orientation r = Orientation.createDefault(graph);\r
+                       shape.addStatement(Resources.g3dResource.HasLocalOrientation, r);\r
+                       // WorldOrientation r2 = WorldOrientationFactory.create(graph);\r
+                       Orientation r2 = Orientation.createDefault(graph);\r
+                       shape.addStatement(Resources.g3dResource.HasWorldOrientation, r2);\r
+                       r.setAngle(new double[] { 0.0 });\r
+                       r.setX(new double[] { 1.0 });\r
+                       r.setY(new double[] { 0.0 });\r
+                       r.setZ(new double[] { 0.0 });\r
+                       r2.setAngle(new double[] { 0.0 });\r
+                       r2.setX(new double[] { 1.0 });\r
+                       r2.setY(new double[] { 0.0 });\r
+                       r2.setZ(new double[] { 0.0 });\r
+\r
+               } else {\r
+                       G3DTools.setOrientation(shape.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation),\r
+                                       new AxisAngle4d(0.0, 1.0, 0.0, 0.0));\r
+                       G3DTools.setOrientation(shape.getSingleRelatedObject(Resources.g3dResource.HasWorldOrientation),\r
+                                       new AxisAngle4d(0.0, 1.0, 0.0, 0.0));\r
+               }\r
+       }\r
+    \r
+    /**\r
+     * Updates transformation of one child node without changing its world transformation.\r
+     * @param parent\r
+     * @param node\r
+     */\r
+    public void propagateWorldTransformChange(IEntity parent, IEntity node) {\r
+        //Collection<IEntity> children = parent.getRelatedObjects(childRelation);\r
+       IEntity parentWP = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition);\r
+        IEntity parentWR = parent.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation);\r
+        Quat4d parentWQuat = new Quat4d();\r
+        if (parentWR != null) {\r
+            parentWQuat.set(G3DTools.getOrientation(parentWR));\r
+        }\r
+        else\r
+            parentWQuat.w = 1.0;\r
+        Point3d parentWPos = new Point3d();\r
+        if (parentWP != null) {\r
+            parentWPos = G3DTools.getPoint(parentWP);\r
+        }\r
+        if (DEBUG){\r
+               if (parentWR != null) \r
+                   System.out.println("propagate transform " + parent.getResource() + " " + parentWPos + " " + G3DTools.getOrientation(parentWR));\r
+               else\r
+                       System.out.println("propagate transform " + parent.getResource() + " " + parentWPos);\r
+        }\r
+        //for (IEntity n : children) {\r
+      //       if (!n.equals(node))\r
+      //               continue;\r
+            IEntity wPos = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldPosition);\r
+            IEntity wRot = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation);\r
+            \r
+            if (DEBUG) System.out.print(node);\r
+            if (wRot != null) {\r
+               AxisAngle4d aa = G3DTools.getOrientation(wRot);\r
+               storeProperty(wRot.getResource(), aa);\r
+                AxisAngle4d la = getLocalFromWorld(node, aa);\r
+                IEntity lRot = node.getSingleRelatedObject(Resources.g3dResource.HasLocalOrientation);\r
+                G3DTools.setOrientation(lRot,la);\r
+                storeProperty(lRot.getResource(), la);\r
+            }\r
+            if (wPos != null) {\r
+                Point3d lp = G3DTools.getPoint(wPos);\r
+                storeProperty(wPos.getResource(), lp);\r
+                lp.sub(parentWPos);\r
+                parentWQuat.inverse();     \r
+                MathTools.rotate(parentWQuat, lp, lp);\r
+                IEntity lPos = node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition);\r
+                G3DTools.setTuple3(lPos, lp);\r
+                storeProperty(lPos.getResource(), lp);\r
+            }\r
+            if (DEBUG) System.out.println();\r
+            propagateTransformChange(node);\r
+            \r
+ //       }\r
+    }\r
+        \r
+    public boolean transformationUpdate(Graph graph, Resource resource) {\r
+       \r
+       //resources.startTransaction("transformationUpdate");\r
+       IEntity entity = EntityFactory.create(graph,resource);\r
+       return transformationUpdate(entity);\r
+    }\r
+    \r
+    public boolean transformationUpdate(IEntity node) {\r
+       if (DEBUG) System.out.println("Node transformation update " + node.getResource());\r
+       IEntity worldPos = node.getSingleRelatedObject(Resources.g3dResource.HasWorldPosition);\r
+       IEntity localPos = node.getSingleRelatedObject(Resources.g3dResource.HasLocalPosition);\r
+       IEntity worldOr = node.getAtMostOneRelatedObject(Resources.g3dResource.HasWorldOrientation);\r
+       IEntity localOr = node.getAtMostOneRelatedObject(Resources.g3dResource.HasLocalOrientation);\r
+       \r
+       Tuple3d worldP =G3DTools.getPoint(worldPos);\r
+       Tuple3d localP = G3DTools.getPoint(localPos);\r
+\r
+       AxisAngle4d worldR = null;\r
+       AxisAngle4d localR = null;\r
+       if (worldOr != null) {\r
+               worldR = G3DTools.getOrientation(worldOr);\r
+               localR = G3DTools.getOrientation(localOr);\r
+       }\r
+       \r
+       boolean changed = false;\r
+       if (localP != null && worldP != null) {\r
+               Tuple3d cachedWorldP = (Tuple3d)getProperty(worldPos.getResource());\r
+               Tuple3d cachedLocalP = (Tuple3d)getProperty(localPos.getResource());\r
+               boolean changedLocalP = false;\r
+               boolean changedWorldP = false;\r
+               if (cachedLocalP == null)\r
+                       changedLocalP = true;\r
+               else if (changed(cachedLocalP,localP))\r
+                       changedLocalP = true;\r
+\r
+               if (cachedWorldP == null) {\r
+                       changedWorldP = true;\r
+               } else if (changed(cachedWorldP,worldP)){\r
+                       changedWorldP = true;\r
+               }\r
+               if (changedLocalP) {\r
+                       storeProperty(localPos.getResource(), localP);\r
+                       Tuple3d p = getWorldFromLocal(node, new Point3d(localP));\r
+                       storeProperty(worldPos.getResource(), p);\r
+                       G3DTools.setTuple3(worldPos, p);\r
+                       if (DEBUG) System.out.println("Node changed local: wp " + worldP + " lp " + p + " old " + cachedLocalP);\r
+                       changed = true;\r
+               } else if (changedWorldP) {\r
+                       storeProperty(worldPos.getResource(), worldP);\r
+                       Tuple3d p = getLocalFromWorld(node, new Point3d(worldP));\r
+                       G3DTools.setTuple3(localPos, p);\r
+                       storeProperty(localPos.getResource(), p);\r
+                       if (DEBUG) System.out.println("Node changed world: wp " + worldP + " lp " + p + " old " + cachedWorldP);\r
+                       changed = true;\r
+               }\r
+       }\r
+\r
+       if (localR != null || worldR != null) {\r
+               AxisAngle4d cachedWorldR = (AxisAngle4d)getProperty(worldOr.getResource());\r
+               AxisAngle4d cachedLocalR = (AxisAngle4d)getProperty(localOr.getResource());\r
+               boolean changedLocalR = false;\r
+               boolean changedWorldR = false;\r
+\r
+               if (cachedLocalR == null)\r
+                       changedLocalR = true;\r
+               else if (changed(cachedLocalR,localR))\r
+                       changedLocalR = true;\r
+\r
+               if (cachedWorldR == null) {\r
+                       changedWorldR = true;\r
+               } else if (changed(cachedWorldR,worldR)){\r
+                       changedWorldR = true;\r
+               }\r
+\r
+               if (changedLocalR) {\r
+                       storeProperty(localOr.getResource(), localR);\r
+                       AxisAngle4d p = getWorldFromLocal(node, new AxisAngle4d(localR));\r
+                       G3DTools.setOrientation(worldOr, p);\r
+                       storeProperty(worldOr.getResource(), p);\r
+                       if (DEBUG) System.out.println("Node changed localR: wr " + p + " lr " + localR + " old " + cachedLocalR);\r
+                       changed = true;\r
+               } else if (changedWorldR) {\r
+                       storeProperty(worldOr.getResource(), worldR);\r
+                       AxisAngle4d p = getLocalFromWorld(node, new AxisAngle4d(worldR));\r
+                       G3DTools.setOrientation(localOr, p);\r
+                       storeProperty(localOr.getResource(), p);\r
+                       if (DEBUG) System.out.println("Node changed worldR: wr " + worldR + " lr " + p + " old " + cachedWorldR);\r
+                       changed = true;\r
+               } \r
+       }\r
+\r
+       if (changed)\r
+               propagateTransformChange(node);\r
+       else if (DEBUG)\r
+               System.out.println("No Node transformation change detected " + node.getResource());\r
+       return changed;\r
+    }\r
+    \r
+    public static boolean changed(Tuple3d v1, Tuple3d v2) {\r
+        Vector3d t = new Vector3d(v1);\r
+        t.sub(v2);\r
+        return t.lengthSquared() > 0.00001;\r
+    }\r
+    \r
+    public static boolean changed (double d1 , double d2) {\r
+       return (Math.abs(d1 - d2) > 0.00001 );\r
+               \r
+    }\r
+    \r
+    public static boolean changed(AxisAngle4d aa1, AxisAngle4d aa2) {\r
+        if (Math.abs(aa1.angle - aa2.angle) > 0.00001)\r
+            return true;\r
+        Vector3d t1 = new Vector3d(aa1.x-aa2.x,aa1.y-aa2.y,aa1.z-aa2.z);\r
+        if (t1.lengthSquared() > 0.00001) {\r
+               if (Math.abs(aa1.angle) < 0.0001)\r
+                       return false;\r
+               return true;\r
+        }\r
+        return false;\r
+    }\r
+\r
+    \r
+    private HashMap<Object, Object> properties = new HashMap<Object, Object>();\r
+    \r
+    public Object getProperty(Object key) {\r
+        return properties.get(key);\r
+    }\r
+    \r
+    public void storeProperty(Object key, Object value) {\r
+        properties.put(key, value);\r
+    }\r
+    \r
+    \r
+    \r
+    \r
+}\r