/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.display3d.simple3d; import java.util.ArrayList; import java.util.Iterator; import org.opensourcephysics.controls.XMLControl; import org.opensourcephysics.display3d.core.interaction.InteractionEvent; import org.opensourcephysics.display3d.core.interaction.InteractionListener; import org.opensourcephysics.numerics.Matrix3DTransformation; import org.opensourcephysics.numerics.Quaternion; import org.opensourcephysics.numerics.Transformation; /** * * <p>Title: Element</p> * * <p>Interaction: An Element includes the following targets:</p> * <ul> * <li> TARGET_POSITION : Allows the element to be repositioned * <li> TARGET_SIZE : Allows the element to be resized * </ul> * The actual position (and implementation) of the target depends on the * element. * * <p>Copyright: Open Source Physics project</p> * * @author Francisco Esquembre * @version June 2005 */ public abstract class Element implements org.opensourcephysics.display3d.core.Element { static final int SENSIBILITY = 5; // The accuracy for the mouse to find a point on the screen // Configuration variables private boolean visible = true; // is the object visible? private double x = 0.0, y = 0.0, z = 0.0; // position of the element private double sizeX = 1.0, sizeY = 1.0, sizeZ = 1.0; // the size of the element in each dimension private String name = ""; //$NON-NLS-1$ private Transformation transformation = null; private Style style = new Style(this); private Group group = null; private double factorX = 1.0; private double factorY = 1.0; private double factorZ = 1.0; // Implementation variables private boolean elementChanged = true, needsToProject = true; private DrawingPanel3D panel; // Variables for interaction private ArrayList<InteractionListener> listeners = new ArrayList<InteractionListener>(); protected final InteractionTarget targetPosition = new InteractionTarget(this, TARGET_POSITION); protected final InteractionTarget targetSize = new InteractionTarget(this, TARGET_SIZE); /** * Returns the DrawingPanel3D in which it (or its final ancestor group) * is displayed. * @return DrawingPanel3D */ final public DrawingPanel3D getDrawingPanel3D() { Element el = this; while(el.group!=null) { el = el.group; } return el.panel; } /** * To be used internally by DrawingPanel3D only! Sets the panel for this element. * @param _panel DrawingPanel3D */ void setPanel(DrawingPanel3D _panel) { this.panel = _panel; this.factorX = _panel.getScaleFactorX(); this.factorY = _panel.getScaleFactorY(); this.factorZ = _panel.getScaleFactorZ(); elementChanged = true; } /** * Returns the group to which the element belongs * @return Group Returns null if it doesn't belong to a group */ final Group getGroup() { return group; } /** * Returns the top group to which the element belongs * @return Group Returns null if it doesn't belong to a group * final Group getTopGroup() { Group gr = group; if(gr==null) { return null; } while(gr.getGroup()!=null) { gr = gr.getGroup(); } return gr; } */ /** * To be used internally by Group only! Sets the group of this element. * @param _group Group */ void setGroup(Group _group) { this.group = _group; elementChanged = true; } protected int getAxesMode() { if(panel!=null) { return panel.getAxesMode(); } return org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XYZ; } // ---------------------------------------- // Name of the element // ---------------------------------------- public void setName(String aName) { this.name = aName; } final public String getName() { return this.name; } // ---------------------------------------- // Position of the element // ---------------------------------------- public void setX(double x) { switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YXZ : this.y = x*this.factorX; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : this.z = x*this.factorZ; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : this.y = x*this.factorY; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZYX : this.z = x*this.factorZ; break; default : this.x = x*this.factorX; } elementChanged = true; } final public double getX() { return this.x/this.factorX; } public void setY(double y) { switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XZY : this.z = y*this.factorZ; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YXZ : this.x = y*this.factorX; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : this.x = y*this.factorX; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : this.z = y*this.factorZ; break; default : this.y = y*this.factorY; } elementChanged = true; } final public double getY() { return this.y/this.factorY; } public void setZ(double z) { switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XZY : this.y = z*this.factorY; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : this.y = z*this.factorY; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : this.x = z*this.factorX; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZYX : this.x = z*this.factorX; break; default : this.z = z*this.factorZ; } elementChanged = true; } final public double getZ() { return this.z/this.factorZ; } public void setXYZ(double x, double y, double z) { switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XZY : this.x = x*this.factorX; this.z = y*this.factorZ; this.y = z*this.factorY; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YXZ : this.y = x; this.x = y; this.z = z; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : this.z = x*this.factorZ; this.x = y*this.factorX; this.y = z*this.factorY; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : this.y = x*this.factorY; this.z = y*this.factorZ; this.x = z*this.factorX; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZYX : this.z = x*this.factorZ; this.y = y*this.factorY; this.x = z*this.factorX; break; default : this.x = x*this.factorX; this.y = y*this.factorY; this.z = z*this.factorZ; } elementChanged = true; } public void setXYZ(double[] pos) { switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XZY : this.x = pos[0]*this.factorX; this.z = pos[1]*this.factorZ; if(pos.length>=3) { this.y = pos[2]*this.factorY; } break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YXZ : this.y = pos[0]*this.factorY; this.x = pos[1]*this.factorX; if(pos.length>=3) { this.z = pos[2]*this.factorZ; } break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : this.z = pos[0]*this.factorZ; this.x = pos[1]*this.factorX; if(pos.length>=3) { this.y = pos[2]*this.factorY; } break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : this.y = pos[0]*this.factorY; this.z = pos[1]*this.factorZ; if(pos.length>=3) { this.x = pos[2]*this.factorX; } break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZYX : this.z = pos[0]*this.factorZ; this.y = pos[1]*this.factorY; if(pos.length>=3) { this.x = pos[2]*this.factorX; } break; default : this.x = pos[0]*this.factorX; this.y = pos[1]*this.factorY; if(pos.length>=3) { this.z = pos[2]*this.factorZ; } } elementChanged = true; } /** * Returns the extreme points of a box that contains the element. * @param min double[] A previously allocated double[3] array that will hold * the minimum point * @param max double[] A previously allocated double[3] array that will hold * the maximum point */ void getExtrema(double[] min, double[] max) { min[0] = -0.5; max[0] = 0.5; min[1] = -0.5; max[1] = 0.5; min[2] = -0.5; max[2] = 0.5; sizeAndToSpaceFrame(min); sizeAndToSpaceFrame(max); } // ---------------------------------------- // Size of the element // ---------------------------------------- public void setSizeX(double sizeX) { switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YXZ : this.sizeY = sizeX*this.factorY; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : this.sizeZ = sizeX*this.factorZ; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : this.sizeY = sizeX*this.factorY; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZYX : this.sizeZ = sizeX*this.factorZ; break; default : this.sizeX = sizeX*this.factorY; } elementChanged = true; } final public double getSizeX() { return this.sizeX; } public void setSizeY(double sizeY) { switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XZY : this.sizeZ = sizeY*this.factorZ; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YXZ : this.sizeX = sizeY*this.factorX; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : this.sizeX = sizeY*this.factorX; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : this.sizeZ = sizeY*this.factorZ; break; default : this.sizeY = sizeY*this.factorY; } elementChanged = true; } final public double getSizeY() { return this.sizeY; } public void setSizeZ(double sizeZ) { switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XZY : this.sizeY = sizeZ*this.factorY; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : this.sizeY = sizeZ*this.factorY; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : this.sizeX = sizeZ*this.factorX; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZYX : this.sizeX = sizeZ*this.factorX; break; default : this.sizeZ = sizeZ*this.factorZ; } elementChanged = true; } final public double getSizeZ() { return this.sizeZ; } public void setSizeXYZ(double sizeX, double sizeY, double sizeZ) { switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XZY : this.sizeX = sizeX*this.factorX; this.sizeZ = sizeY*this.factorY; this.sizeY = sizeZ*this.factorZ; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YXZ : this.sizeY = sizeX*this.factorY; this.sizeX = sizeY*this.factorX; this.sizeZ = sizeZ*this.factorZ; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : this.sizeZ = sizeX*this.factorZ; this.sizeX = sizeY*this.factorX; this.sizeY = sizeZ*this.factorY; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : this.sizeY = sizeX*this.factorY; this.sizeZ = sizeY*this.factorZ; this.sizeX = sizeZ*this.factorX; break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZYX : this.sizeZ = sizeX*this.factorZ; this.sizeY = sizeY*this.factorY; this.sizeX = sizeZ*this.factorX; break; default : this.sizeX = sizeX*this.factorX; this.sizeY = sizeY*this.factorY; this.sizeZ = sizeZ*this.factorZ; } elementChanged = true; } public void setSizeXYZ(double[] size) { switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XZY : this.sizeX = size[0]*this.factorX; this.sizeZ = size[1]*this.factorZ; if(size.length>=3) { this.sizeY = size[2]*this.factorY; } break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YXZ : this.sizeY = size[0]*this.factorY; this.sizeX = size[1]*this.factorX; if(size.length>=3) { this.sizeZ = size[2]*this.factorZ; } break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : this.sizeZ = size[0]*this.factorZ; this.sizeX = size[1]*this.factorX; if(size.length>=3) { this.sizeY = size[2]*this.factorY; } break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : this.sizeY = size[0]*this.factorY; this.sizeZ = size[1]*this.factorZ; if(size.length>=3) { this.sizeX = size[2]*this.factorX; } break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZYX : this.sizeZ = size[0]*this.factorZ; this.sizeY = size[1]*this.factorY; if(size.length>=3) { this.sizeX = size[2]*this.factorX; } break; default : this.sizeX = size[0]*this.factorX; this.sizeY = size[1]*this.factorY; if(size.length>=3) { this.sizeZ = size[2]*this.factorZ; } } elementChanged = true; } /** * Returns the diagonal size of the element, i.e., Math.sqrt(sizeX*sizeX+sizeY*sizeY+sizeZ*sizeZ) * @return double */ final double getDiagonalSize() { return Math.sqrt(sizeX*sizeX+sizeY*sizeY+sizeZ*sizeZ); } /** * Returns whether the element has changed significantly. * This can be used by implementing classes to help improve performance. * @return boolean */ final boolean hasChanged() { Element el = this; while(el!=null) { if(el.elementChanged) { return true; } el = el.group; } return false; } /** * Whether this element has changed position, size, transformation or style * since the last time it was displayed. * @return boolean */ boolean getElementChanged() { return elementChanged; } /** * Tells the element whether it has a change that demands some * kind of computation or, the other way round, someone took * care of all possible changes. * Typically used by subclasses when they change something or * make all needed computations. * @param change Whether the element has changed */ final void setElementChanged(boolean change) { elementChanged = change; } // ------------------------------------- // Visibility and style // ------------------------------------- public void setVisible(boolean _visible) { this.visible = _visible; } final public boolean isVisible() { return this.visible; } /** * Returns the real visibility status of the element, which will be false if * it belongs to an invisible group * @return boolean */ final protected boolean isReallyVisible() { Element el = this.group; while(el!=null) { if(!el.visible) { return false; } el = el.group; } return this.visible; } final public org.opensourcephysics.display3d.core.Style getStyle() { return this.style; } /** * Gets the real Style. This is more convenient and improves performance (a liiittle bit) * @return Style */ final Style getRealStyle() { return this.style; } /** * Used by Style to notify possible changes. * @param styleThatChanged int */ final void styleChanged(int styleThatChanged) { elementChanged = true; } // ---------------------------------------- // Transformation of the element // ---------------------------------------- public Transformation getTransformation() { if(transformation==null) { return null; } return(Transformation) transformation.clone(); } public void setTransformation(org.opensourcephysics.numerics.Transformation transformation) { if(transformation==null) { this.transformation = null; } else { this.transformation = (Transformation) transformation.clone(); if(transformation instanceof Quaternion) { Quaternion q = (Quaternion) this.transformation; double[] coordsBuffer = q.getCoordinates(); //Switch the Axis Mode switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XYZ : q.setCoordinates(coordsBuffer[0], coordsBuffer[1], coordsBuffer[2], coordsBuffer[3]); break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XZY : q.setCoordinates(coordsBuffer[0], coordsBuffer[1], coordsBuffer[3], coordsBuffer[2]); break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YXZ : q.setCoordinates(coordsBuffer[0], coordsBuffer[2], coordsBuffer[1], coordsBuffer[3]); break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : q.setCoordinates(coordsBuffer[0], coordsBuffer[2], coordsBuffer[3], coordsBuffer[1]); break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : q.setCoordinates(coordsBuffer[0], coordsBuffer[3], coordsBuffer[1], coordsBuffer[2]); break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZYX : q.setCoordinates(coordsBuffer[0], coordsBuffer[3], coordsBuffer[2], coordsBuffer[1]); break; default : q.setCoordinates(coordsBuffer[0], coordsBuffer[1], coordsBuffer[2], coordsBuffer[3]); } this.transformation = new Quaternion(q); } else { Matrix3DTransformation mt = (Matrix3DTransformation) this.transformation; double[] q = new double[4]; mt.toQuaternion(q); Quaternion qf = new Quaternion(q); //Switch the Axis Mode switch(getAxesMode()) { case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XYZ : qf.setCoordinates(q[0], q[1], q[2], q[3]); break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_XZY : qf.setCoordinates(q[0], q[1], q[3], q[2]); break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YXZ : qf.setCoordinates(q[0], q[2], q[1], q[3]); break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_YZX : qf.setCoordinates(q[0], q[2], q[3], q[1]); break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZXY : qf.setCoordinates(q[0], q[3], q[1], q[2]); break; case org.opensourcephysics.display3d.core.DrawingPanel3D.MODE_ZYX : qf.setCoordinates(q[0], q[3], q[2], q[1]); break; default : qf.setCoordinates(q[0], q[1], q[2], q[3]); } this.transformation = new Quaternion(qf); } } elementChanged = true; } public double[] toSpaceFrame(double[] vector) { if(transformation!=null) { transformation.direct(vector); } vector[0] += x; vector[1] += y; vector[2] += z; Element el = group; while(el!=null) { vector[0] *= el.sizeX; vector[1] *= el.sizeY; vector[2] *= el.sizeZ; if(el.transformation!=null) { el.transformation.direct(vector); } vector[0] += el.x; vector[1] += el.y; vector[2] += el.z; el = el.group; } return vector; } public double[] toBodyFrame(double[] vector) throws UnsupportedOperationException { java.util.ArrayList<Element> elList = new java.util.ArrayList<Element>(); Element el = this; do { elList.add(el); el = el.group; } while(el!=null); for(int i = elList.size()-1; i>=0; i--) { // Done in the reverse order el = elList.get(i); vector[0] -= el.x; vector[1] -= el.y; vector[2] -= el.z; if(el.transformation!=null) { el.transformation.inverse(vector); } if(el!=this) { if(el.sizeX!=0.0) { vector[0] /= el.sizeX; } if(el.sizeY!=0.0) { vector[1] /= el.sizeY; } if(el.sizeZ!=0.0) { vector[2] /= el.sizeZ; } } } return vector; } /** * Translates a point of the standard (0,0,0) to (1,1,1) element * to its real spatial coordinate. Thus, if the point has a coordinate of 1, * the result will be the size of the element. * @param vector the vector to be converted */ final void sizeAndToSpaceFrame(double[] vector) { vector[0] *= sizeX; vector[1] *= sizeY; vector[2] *= sizeZ; toSpaceFrame(vector); } // ---------------------------------------------------- // Needed by the drawing mechanism // ---------------------------------------------------- /** * Returns an array of Objects3D to sort according to its distance and draw. */ abstract Object3D[] getObjects3D(); /** * Draws a given Object3D (indicated by its index). */ abstract void draw(java.awt.Graphics2D g, int index); /** * Sketches the drawable */ abstract void drawQuickly(java.awt.Graphics2D g); /** * Tells the element whether it should reproject its points because the panel * has changed its projection parameters. Or, the other way round, * if someone (typically methods in subclasses) took care of this already. */ void setNeedToProject(boolean _need) { needsToProject = _need; } /** * Whether the element needs to project * @return boolean * @see #setNeedToProject(boolean) */ final boolean needsToProject() { return needsToProject; } // --------------------------------- // Implementation of core.InteractionSource // --------------------------------- public org.opensourcephysics.display3d.core.interaction.InteractionTarget getInteractionTarget(int target) { switch(target) { case TARGET_POSITION : return targetPosition; case TARGET_SIZE : return targetSize; } return null; } public void addInteractionListener(InteractionListener listener) { if((listener==null)||listeners.contains(listener)) { return; } listeners.add(listener); } public void removeInteractionListener(InteractionListener listener) { listeners.remove(listener); } /** * Invokes the interactionPerformed() methods on the registered * interaction listeners. * @param event InteractionEvent */ final void invokeActions(InteractionEvent event) { Iterator<InteractionListener> it = listeners.iterator(); while(it.hasNext()) { it.next().interactionPerformed(event); } } // TODO : make this method abstract /** * Gets the target that is under the (x,y) position of the screen * @param x int * @param y int * @return InteractionTarget */ protected InteractionTarget getTargetHit(int x, int y) { return null; } /** * Returns the body coordinates of the specified hotspot * @return double[] */ protected double[] getHotSpotBodyCoordinates(InteractionTarget target) { if(target==targetPosition) { return new double[] {0, 0, 0}; } if(target==targetSize) { double[] c = new double[] {1, 1, 1}; if(sizeX==0) { c[0] = 0.0; } if(sizeY==0) { c[1] = 0.0; } if(sizeZ==0) { c[2] = 0.0; } return c; } return null; } /** * This method returns the coordinates of the given target. * @param target InteractionTarget * @return double[] */ final double[] getHotSpot(InteractionTarget target) { double[] coordinates = getHotSpotBodyCoordinates(target); if(coordinates!=null) { sizeAndToSpaceFrame(coordinates); } return coordinates; } /** * This method updates the position or size of the element * according to the position of the 3D cursor during the interaction. * Notice that, for targetSize, if any of the sizes of the element * is zero, this dimension cannot be changed. * @param target InteractionTarget The target interacted * @param point double[] The position of the cursor during the interaction */ final void updateHotSpot(InteractionTarget target, double[] point) { Element gr = this.group; //getTopGroup(); switch(target.getType()) { case org.opensourcephysics.display3d.core.Element.TARGET_POSITION : if(target.getAffectsGroup()&&(gr!=null)) { // Move the whole group double[] origin = getHotSpot(target); gr.setXYZ(gr.x+point[0]-origin[0], gr.y+point[1]-origin[1], gr.z+point[2]-origin[2]); } else { // Move only the element double[] coordinates = new double[] {point[0], point[1], point[2]}; groupInverseTransformations(coordinates); double[] origin = getHotSpotBodyCoordinates(target); origin[0] *= sizeX; origin[1] *= sizeY; origin[2] *= sizeZ; if(transformation!=null) { transformation.direct(origin); } setXYZ(coordinates[0]-origin[0], coordinates[1]-origin[1], coordinates[2]-origin[2]); } break; case org.opensourcephysics.display3d.core.Element.TARGET_SIZE : if(target.getAffectsGroup()&&(gr!=null)) { // Resize the whole group double[] coordinates = new double[] {point[0], point[1], point[2]}; coordinates[0] -= gr.x; coordinates[1] -= gr.y; coordinates[2] -= gr.z; if(gr.transformation!=null) { gr.transformation.inverse(coordinates); } double[] origin = getHotSpotBodyCoordinates(target); elementDirectTransformations(origin); // If any of the dimensions is zero, a division by zero would occur. // Not dividing is not enough. if(origin[0]!=0) { coordinates[0] /= origin[0]; } else { coordinates[0] = gr.sizeX; } if(origin[1]!=0) { coordinates[1] /= origin[1]; } else { coordinates[1] = gr.sizeY; } if(origin[2]!=0) { coordinates[2] /= origin[2]; } else { coordinates[2] = gr.sizeZ; } gr.setSizeXYZ(coordinates); } else { // Resize only the element double[] coordinates = new double[] {point[0], point[1], point[2]}; groupInverseTransformations(coordinates); coordinates[0] -= x; coordinates[1] -= y; coordinates[2] -= z; if(transformation!=null) { transformation.inverse(coordinates); } double[] origin = getHotSpotBodyCoordinates(target); for(int i = 0; i<3; i++) { if(origin[i]!=0) { coordinates[i] /= origin[i]; } } setSizeXYZ(coordinates); } } } /** * All the inverse transformations of toBodyFrame except that of the * element itself * @param vector double[] * @throws UnsupportedOperationException */ private final void groupInverseTransformations(double[] vector) throws UnsupportedOperationException { java.util.ArrayList<Element> elList = new java.util.ArrayList<Element>(); Element el = this.group; while(el!=null) { elList.add(el); el = el.group; } for(int i = elList.size()-1; i>=0; i--) { // Done in the reverse order el = elList.get(i); vector[0] -= el.x; vector[1] -= el.y; vector[2] -= el.z; if(el.transformation!=null) { el.transformation.inverse(vector); } if(el.sizeX!=0.0) { vector[0] /= el.sizeX; } if(el.sizeY!=0.0) { vector[1] /= el.sizeY; } if(el.sizeZ!=0.0) { vector[2] /= el.sizeZ; } } } /** * All the direct transformations of sizeAndToSpaceFrame except that of the * top group * @param vector double[] */ private final void elementDirectTransformations(double[] vector) { Element el = this; do { if(el.sizeX!=0) { vector[0] *= el.sizeX; } if(el.sizeY!=0) { vector[1] *= el.sizeY; } if(el.sizeZ!=0) { vector[2] *= el.sizeZ; } if(el.transformation!=null) { el.transformation.direct(vector); } vector[0] += el.x; vector[1] += el.y; vector[2] += el.z; el = el.group; } while((el!=null)&&(el.group!=null)); } // ---------------------------------------------------- // XML loader // ---------------------------------------------------- public void loadUnmutableObjects(XMLControl control) { style = (Style) control.getObject("style"); //$NON-NLS-1$ style.setElement(this); elementChanged = true; } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */