Java source code of 'jhplot.jadraw.JaObject'

/*

 * Title: japlot.jaxodraw
 * Description: Graphical user interface for drawing Feynman diagrams
 * @author Daniele Binosi 
 * @author Lukas Theussl  

 Copyright (C) 2003-2006,  Daniele Binosi and Lukas Theussl

 See the file LICENSE in the source distribution home directory
 for a full copy of the GPL (GNU General Public License).

    This file is part of japlot.jaxodraw.

    japlot.jaxodraw is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    japlot.jaxodraw 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 program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 */
package jhplot.jadraw;


import japlot.Global;
import japlot.jaxodraw.JaxoPrefs;
import org.freehep.graphics2d.VectorGraphics;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;

import java.io.Serializable;

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;

import java.util.Locale;



/** A general JaObject. */
public abstract class JaObject implements Serializable {
    // These constants will determine what the user does with the JaObject:
    // he can grab the body, not grab anything or grab one of the four handles
    // we will draw around the JaObject when the user select it
    /** An integer that indicates that the user did not grab any object. */
    public static final int SELECT_NONE = 0;

    /** An integer that indicates that the user grabbed the
      * body of an object.
      */
    public static final int SELECT_BODY = 11;

    /** An integer that indicates that the user grabbed the
     * upper left handle of an object.
     */
    public static final int SELECT_UL = 12;

    /** An integer that indicates that the user grabbed the
     * upper right handle of an object.
     */
    public static final int SELECT_UR = 13;

    /** An integer that indicates that the user grabbed the
     * lower right handle of an object.
     */
    public static final int SELECT_LR = 14;

    /** An integer that indicates that the user grabbed the
     * lower left handle of an object.
     */
    public static final int SELECT_LL = 15;

    /** An integer that indicates the current edit mode MOVE. */
    public static final int MOVE = 50;

    /** An integer that indicates the current edit mode RESIZE. */
    public static final int RESIZE = 51;

    /** An integer that indicates the current edit mode COPY. */
    public static final int COPY = 52;

    /** An integer that gives the length of the handle sides. */
    public static final int LENGTH = 8;

    /** An integer that gives the initial size of an object. */
    public static final int INIT_SIZE = 25;

    /** An integer that specifies the first point of an arc object. */
    public static final int SELECT_P1 = 1;

    /** An integer that specifies the second point of an arc object. */
    public static final int SELECT_P2 = 2;

    /** An integer that specifies the third point of an arc object. */
    public static final int SELECT_P3 = 3;

    /** The component of the boundingbox array that contains the
     * lower x value of the boundingbox.
     */
    public static final int BB_MIN_X = 0;

    /** The component of the boundingbox array that contains the
     * lower y value of the boundingbox.
     */
    public static final int BB_MIN_Y = 1;

    /** The component of the boundingbox array that contains the
     * upper x value of the boundingbox.
     */
    public static final int BB_MAX_X = 2;

    /** The component of the boundingbox array that contains the
     * upper y value of the boundingbox.
     */
    public static final int BB_MAX_Y = 3;


    /** The decimal format used for numbers in LaTeX output. */
    public static final DecimalFormat D_FORMAT =
        new DecimalFormat("######.##",
            new DecimalFormatSymbols(new Locale("en", "US")));
    protected static final long serialVersionUID = 314159L;

    static {
        try {
            // Make the BoundingBox and gp properties transient
            BeanInfo info = Introspector.getBeanInfo(JaObject.class);
            PropertyDescriptor[] propertyDescriptors =
                info.getPropertyDescriptors();

            for (int i = 0; i < propertyDescriptors.length; ++i) {
                PropertyDescriptor pd = propertyDescriptors[i];
                if (pd.getName().equals("boundingBox")) {
                    pd.setValue("transient", Boolean.TRUE);
                } else if (pd.getName().equals("gp")) {
                    pd.setValue("transient", Boolean.TRUE);
                }
            }
        } catch (IntrospectionException e) {
            if (JaxoPrefs.verbose()) {
                System.err.println(java.util.ResourceBundle.getBundle(
                        JaxoPrefs.getPref(JaxoPrefs.PREF_LANGUAGE)).getString("IntrospectionException_in_JaxoObject:_")
                    + e);
            }
        }
    }

    // bean properties: to be serialized to XML

    /** The x coordinate of this JaObject. */
    private int x;

    /** The y coordinate of this JaObject. */
    private int y;

    /** The relative width of this JaObject.*/
    private int relw;

    /** The relative height of this JaObject.*/
    private int relh;


   /** The x coordinate in NDC . */
    private float xx;

    /** The y coordinate in NDC. */
    private float yy;

    
    /** The x coordinate in USER . */
    private double xu;

    /** The y coordinate in USER. */
    private double yu;
    
    // indicate: is it USER coordinate?
    private boolean isUser;
    
    /** The relative width in NDC.*/
    private float rrelw;

    /** The relative height in NDC.*/
    private float rrelh;

    
    /** The relative width in USER.*/
    private double urelw;

    /** The relative height in USER.*/
    private double urelh;

    
    

    /** The color of this JaObject.*/
    private Color color;

    // these ones should not be serialized to XML!
    private GeneralPath gp = new GeneralPath();

    /** The bounding box of this JaObject.*/
    private double[] boundingbox = {0.d, 0.d, 0.d, 0.d};

    /** Determines whether this JaObject is part of a group or not */
    private boolean marked = false;

    /** Returns the GeneralPath that draws this JaObject.
     * @return The  GeneralPath of this JaObject.
     */
    public final GeneralPath getGeneralPath() {
        return gp;
    }


    public void updateCoor() {
      x= Global.fromX(xx);
      y= Global.fromY(yy);
      relw= Global.fromX( rrelw );
      relh= Global.fromY( rrelh );
    }

    public void updateNDC() {
      xx= Global.toX(x);
      yy= Global.toY(y);
      rrelw= Global.toX( relw );
      rrelh= Global.toY( relh );
    }


    /** Returns the bounding box of this JaObject.
     * @return The bounding box of this JaObject.
     */
    public double[] getBoundingBox() {
        int length = boundingbox.length;
        double[] newArray = new double[length];
        System.arraycopy(boundingbox, 0, newArray, 0, length);
        return newArray;
        //return boundingbox;
    }

    /** Sets the bounding box of this JaObject.
     * @param bb The bounding box to be set for this JaObject.
     */
    public final void setBoundingBox(double[] bb) {
        this.boundingbox[BB_MIN_X] = bb[BB_MIN_X];
        this.boundingbox[BB_MIN_Y] = bb[BB_MIN_Y];
        this.boundingbox[BB_MAX_X] = bb[BB_MAX_X];
        this.boundingbox[BB_MAX_Y] = bb[BB_MAX_Y];
    }

    /** Sets this JaObject as element of a group.
     * @param mark A boolean variable indicating whether this
     * JaObject should be set as an element of a group or not.
     */
    public final void setAsMarked(boolean mark) {
        this.marked = mark;
    }

    /** Determines whether this JaObject is marked as an element
     * of a group or not.
     * @return Boolean variable telling whether this JaObject is part
     * of a group or not
     */
    public final boolean isMarked() {
        return marked;
    }

    
    /**
     * Set to true if coordinates were set using USER coordinate system
     * attached to axes
     * @return true if user
     */
    public boolean isUser() {
		return isUser;
	}
    
    
    
    // Bean getter and setter methods

    /** Returns the x coordinate of this object.
     * @return The x coordinate of this object.
     */
    public final int getX() {
        return x;
    }

    /** Returns the NDC x coordinate of this object.
     * @return The x coordinate of this object.
     */
    public final double  getXndc() {
        return xx;
    }

    /** Returns the USER x coordinate of this object.
     * @return The x coordinate of this object in the current axes frame
     */
    public final double  getXuser() {
        return xu;
    }
    
    /** Sets the x coordinate of this object.
     * @param newX The x coordinate of this object.
     */
    public final void setX(int newX) {
        this.x = newX;
        xx= Global.toX(this.x);
    }

    /** Returns the y coordinate of this object.
     * @return The y coordinate of this object.
     */
    public final int getY() {
        return y;
    }

    /** Returns the NDC y coordinate of this object.
     * @return The NDC y coordinate of this object.
     */
    public final double getYndc() {
        return yy;
    }

    /** Returns the USER y coordinate of this object.
     * @return The USER y coordinate of this object in the current axis frame
     */
    public final double getYuser() {
        return yu;
    }
    
    
    /** Sets the y coordinate of this object.
     * @param newY The y coordinate of this object.
     */
    public final void setY(int newY) {
        this.y = newY;
        yy= Global.toY(this.y);
    }


    /**
     * Set location of the object in the NDC or USER coordinates.
     * @param xc  X location
     * @param yc  Y location
     * @param what if "NDC", coordinate in NDC (from 0 to 1), if "USER" coordinates are 
     *                        in the user system given by the axes.
     */
    
    public void setLocation(double xc, double yc, String what) {
  
    	
    	
    	
    if (what.equals("NDC")) {
    this.xx=(float)xc;
    this.yy=(float)yc;
    x= Global.fromX( this.xx );
    y= Global.fromY( this.yy );
    isUser=false;
    
    
    } else if (what.equals("USER")) {
    	
    	xu=xc;
    	yu=yc;
    	isUser = true;
    	
    } else {
    	
    	isUser=false;
    	x=(int)xc;
    	y=(int)yc;
    	isUser=false;
    	
    }
    
    
    
    }


    /**
     * Set relative size in the NDC or USER coordinates
     * @param w  width of the object
     * @param h  height of the object
     * @param what if "NDC", coordinate in NDC (from 0 to 1), if "USER" coordinates are 
     *                        in the user system given by the axes.
      */
    
   public void setRelWH(double w, double h, String what) {
      if (what.equals("NDC")) {
      this.rrelw= (float)w;
      this.rrelh= (float)h;
      relw = Global.fromX( this.rrelw );
      relh= Global.fromY(  this.rrelh );
      }  else if (what.equals("USER")) {
    	  
    	urelw=w;
      	urelh=h;
      	isUser = true;
    	  
      }

    }


    /** Returns the width of this object.
     * @return The width of this object.
     */
    public final int getWidth() {
        return Math.abs(getRelw());
    }

    /** Returns the height of this object.
     * @return The height of this object.
     */
    public final int getHeight() {
        return Math.abs(getRelh());
    }

    /** Returns the relative width of this object.
     * @return The relative width of this object.
     */
    public final int getRelw() {
        return relw;
    }

    /** Sets the relative width of this object.
     * @param newRelw The relative width of this object.
     */
    public final void setRelw(int newRelw) {
        this.relw = newRelw;
        rrelw= Global.toX( this.relw );
    }

    /** Returns the relative height of this object.
     * @return The relative height of this object.
     */
    public final int getRelh() {
        return relh;
    }

    /** Returns the relative height of this object in NDC.
     * @return The relative height of this object.
     */
    public final double getRelHndc() {
        return rrelh;
    }

    
    /** Returns the relative height of this object in USER.
     * @return The relative height of this object.
     */
    public final double getRelHuser() {
        return urelh;
    }

    
    
    /** Returns the relative width of this object in NDC.
     * @return The relative height of this object.
     */
    public final double getRelWndc() {
        return rrelw;
    }
    
    
    /** Returns the relative width of this object in USER.
     * @return The relative height of this object.
     */
    public final double getRelWuser() {
        return urelw;
    }
    
    
    
    
    /** Sets the relative height of this object.
     * @param newRelh The relative height of this object.
     */
    public final void setRelh(int newRelh) {
        this.relh = newRelh;
        rrelh= Global.toY( this.relh );
    }

    /** Returns the color of this object.
     * @return The color of this object.
     */
    public final Color getColor() {
        return color;
    }

    /** Sets the color of this object.
     * @param c The color of this object.
     */
    public final void setColor(Color c) {
        this.color = c;
    }

    /** Sets the relative width and height of this object.
     * @param w The relative width of this object.
     * @param h The relative height of this object.
     */
    public final void setRelWAndH(int w, int h) {
        setRelw(w);
        setRelh(h);
    }

    /** Sets the x and y coordinate of this object.
     * @param newX The x coordinate of this object.
     * @param newY The y coordinate of this object.
     */
    public final void setLocation(int newX, int newY) {
        setX(newX);
        setY(newY);
    }

    /** Reset the x, and y coordinates of the object when it is moved
     * by deltaX and deltaY.
     * @param deltaX The x displacement.
     * @param deltaY The y displacement.
     */
    public void moveBy(int deltaX, int deltaY) {
        setX(x + deltaX);
        setY(y + deltaY);
    }

    /** Reset the size (width, height, relative width and height)
     * of this object.
     * @param w The width of this object.
     * @param h The heightof this object.
     * @param rw The relative width of this object.
     * @param rh The relative height of this object.
     */
    public final void setSize(int w, int h, int rw, int rh) {
        setRelw(rw);
        setRelh(rh);
    }

    /** Returns the width and height of this object.
     * @return A dimension with the size of the object.
     */
    public final Dimension getSize() {
        return new Dimension(getWidth(), getHeight());
    }

    /** Returns the relative width and height of this object.
     * @return A dimension with the relative size of the object.
     */
    public final Dimension getRelSize() {
        return new Dimension(relw, relh);
    }

    /** Draws a visual aid for the user during dragging of certain JaxoObjects.
     * Currently applies for JaxoArcs (draws the center point and a
     * radius line), JaxoLoops, JaxoBlobs and JaxoVertices
     * (draws the center point in each case).
     * @param g2 The graphics context to draw the visual aid.
     */
    public void drawVisualAid(VectorGraphics  g2) {
        // By default, do nothing.
        // The objects that do draw a visual aid override this method.
    }

    /** Translates the given general path to the current location of this
     * JaObject, rotates it by an angle determined by the relative width and
     * height and scales it by the given scale factor.
     * @param path The GeneralPath object to be transformed.
     * @param scale An overall scale factor.
     * @return The transformed GeneralPath object.
     */
    protected GeneralPath trans(GeneralPath path, double scale) {
        AffineTransform at = new AffineTransform();

        double theta = (double) Math.atan2((float) relh, (float) relw);
        int width = getWidth();
        int height = getHeight();

        if ((relw > 0) && (relh >= 0)) {
            at.translate(x, y);
            at.rotate(theta, 0.d, 0.d);
            at.scale(scale, scale);
            path.transform(at);
        }

        if ((relw >= 0) && (relh < 0)) {
            at.translate(x, y + height);
            at.rotate(theta, 0.d, 0.d);
            at.scale(scale, scale);
            path.transform(at);
        }

        if ((relw < 0) && (relh <= 0)) {
            at.translate(x + width, y + height);
            at.rotate(theta, 0.d, 0.d);
            at.scale(scale, scale);
            path.transform(at);
        }

        if ((relw <= 0) && (relh > 0)) {
            at.translate(x + width, y);
            at.rotate(theta, 0.d, 0.d);
            at.scale(scale, scale);
            path.transform(at);
        }

        return path;
    }

    /** Translates the given general path to the current location of this
     * JaObject, rotates it by an angle determined by the relative width and
     * height and scales it by the given scale factor.
     * @param path The GeneralPath object to be transformed.
     * @param scale An overall scale factor.
     * @return The transformed GeneralPath object.
     */
    protected GeneralPath transdl(GeneralPath path, double scale) {
        AffineTransform at = new AffineTransform();

        double theta = (double) Math.atan2((float) relh, (float) relw);
        int width = getWidth();
        int height = getHeight();

        if ((relw > 0) && (relh >= 0)) {
            at.translate(x, y);
            at.rotate(theta - 0.01, 0.d, 0.d);
            at.scale(scale, scale);
            path.transform(at);
        }

        if ((relw >= 0) && (relh < 0)) {
            at.translate(x, y + height);
            at.rotate(theta + 0.01, 0.d, 0.d);
            at.scale(scale, scale);
            path.transform(at);
        }

        if ((relw < 0) && (relh <= 0)) {
            at.translate(x + width, y + height);
            at.rotate(theta + 0.01, 0.d, 0.d);
            at.scale(scale, scale);
            path.transform(at);
        }

        if ((relw <= 0) && (relh > 0)) {
            at.translate(x + width, y);
            at.rotate(theta + 0.01, 0.d, 0.d);
            at.scale(scale, scale);
            path.transform(at);
        }

        return path;
    }

    /** Translates the given general path to the current location of this
     * JaObject and scales it by the given scale factor.
     * @param path The GeneralPath object to be transformed.
     * @param scale An overall scale factor.
     * @return The transformed GeneralPath object.
     */
    protected GeneralPath transv(GeneralPath path, double scale) {
        AffineTransform at = new AffineTransform();
        int width = getWidth();
        int height = getHeight();

        if ((relw > 0) && (relh >= 0)) {
            at.translate(x, y);
            at.scale(scale, scale);
            path.transform(at);
        }

        if ((relw >= 0) && (relh < 0)) {
            at.translate(x, y + height);
            at.scale(scale, scale);
            path.transform(at);
        }

        if ((relw < 0) && (relh <= 0)) {
            at.translate(x + width, y + height);
            at.scale(scale, scale);
            path.transform(at);
        }

        if ((relw <= 0) && (relh > 0)) {
            at.translate(x + width, y);
            at.scale(scale, scale);
            path.transform(at);
        }

        return path;
    }

    /** Returns a point that is obtained from a point (px, py) after a scale
     * transformation scale, keeping the point (orx, ory) fixed.
     * @param orx The x-coordinate of the fixed point.
     * @param ory The y-coordinate of the fixed point.
     * @param scale The scale factor.
     * @param px The x-coordinate of the point to be transformed.
     * @param py The y-coordinate of the point to be transformed.
     * @return A Point2D containing the x- and y-coordinate of the new point.
     */
    public Point2D scalePoint(double orx, double ory, double scale, double px,
        double py) {
        Point2D newP =
            new Point2D.Double((scale * (px - orx)) + orx,
                (scale * (py - ory)) + ory);

        return newP;
    }

    // These methods are abstract and all subclasses must implement
    // them to be instantiated.

    /** The method that draws the JaObject.
     * @param g2 The graphics context where the object has to be drawn.
     * @param drawToScreen A boolean variable that indicates whether
     * the drawing is done on the screen or somewhere else. This is used
     * for exporting/printing, where the object handles should not be painted,
     * even if they are visible on the screen.
     */
    public abstract void jaxoDraw(VectorGraphics g2, boolean drawToScreen);

    /** Draws the handles of this JaObject that allow
     * to move/resize/edit it.
     * @param g2 The corresponding graphics context.
     */
    public abstract void drawHandles(VectorGraphics g2);

    /** Determines which handle the user has selected to move/resize/edit
     * an object.
     * @param clickX The x coordinate where the mouse click has ocurred.
     * @param clickY The y coordinate where the mouse click has ocurred.
     * @param editmode The current edit mode.
     * @return One of the static variables SELECT_* defined in JaObject
     * that specifies the handle which the user has clicked.
     */
    public abstract int getGrabbedHandle(int clickX, int clickY, int editmode);

    /** Returns an exact copy of the given JaObject.
     * @return The copy of the given JaObject.
     */
    public abstract JaObject copy();

    /** Determines if this JaObject is a copy of the specified one.
     * @param testObject The JaObject to compare against.
     * @return True if the JaxoObjects are identical.
     */
    public abstract boolean isCopy(JaObject testObject);

    /** The LaTeX command that is necessary to draw the given JaObject
     * using the axodraw.sty package.
     * @param scale A scale factor to translate Java coordinates to
     * LaTeX coordinates.
     * @param canvasDim The current dimension of the canvas.
     * @return The corresponding axodraw LaTeX command.
     */
    public abstract String latexCommand(float scale, Dimension canvasDim);

    /** The LaTeX command that sets the width for this JaObject,
     * using the axodraw.sty package.
     * @return The corresponding LaTeX command.
     */
    public abstract String latexWidth();

    /** Abstract class to rescale this JaObject by the scale factor scale,
     * keeping the point (orx, ory) fixed.
     * @param orx The x-coordinate of the fixed point.
     * @param ory The y-coordinate of the fixed point.
     * @param scale The scale parameter.
     */
    public abstract void rescaleObject(int orx, int ory, float scale);

    /** Brings up the edit panel that allows to change the parameters of
     * this object.
     * @return True if the editing actually changed the object, false if
     * the object has not been changed.
     */
    public abstract boolean editPanel();
}