Java source code of 'jhplot.jadraw.JaPArc'

/*

 * 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.jaxodraw.JaxoColor;

import java.awt.BasicStroke;
import java.awt.Dimension;
import org.freehep.graphics2d.VectorGraphics;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.FlatteningPathIterator;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;


/** A photon arc. */
public class JaPArc extends JaArcObject {
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/** Constructor: calls super() and initializes the stangle to 0.*/
    public JaPArc() {
        super();
        setStangle(0);
    }

    /** Returns an exact copy of this JaPArc.
     * @return A copy of this JaPArc.
     */
    public final JaObject copy() {
        JaPArc temp = new JaPArc();

        temp.setArcPts(getX1(), getY1(), getX2(), getY2(), getX(), getY());
        temp.setX(getX());
        temp.setY(getY());
        temp.setAmp(getAmp());
        temp.setFreq(getFreq());
        temp.setColor(getColor());
        temp.setStroke(getStroke());
        temp.setDoubleLine(getDoubleLine());
        temp.setDLSeparation(getDLSeparation());
        temp.setSize(getWidth(), getHeight(), getRelw(), getRelh());
        temp.setBoundingBox(getBoundingBox());

        return temp;
    }

    /** Returns true if all serializable variables of this JaObject
     *  and those of the specified one are equal.
     * @param comp A JaObject to compare with.
     * @return True if the objects are equal, false otherwise.
     */
    public final boolean isCopy(JaObject comp) {
        boolean isCopy = false;

        if (comp instanceof JaPArc) {
            JaPArc arc = (JaPArc) comp;
            if ((arc.getX1() == getX1()) && (arc.getX2() == getX2())
                    && (arc.getY1() == getY1()) && (arc.getY2() == getY2())
                    && (arc.getX() == getX()) && (arc.getY() == getY())
                    && (arc.getAmp() == getAmp())
                    && (arc.getFreq() == getFreq())
                    && (arc.getColor().equals(getColor()))
                    && (arc.getStroke() == getStroke())
                    && (arc.getDoubleLine() == getDoubleLine())
                    && (arc.getDLSeparation() == getDLSeparation())
                    && (arc.getRelw() == getRelw())
                    && (arc.getRelh() == getRelh())) {
                isCopy = true;
            }
        }

        return isCopy;

    }

    /** The method that draws this JaPArc.
     * @param g2 The graphics context where the JaPArc 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 final void jaxoDraw(VectorGraphics g2, boolean drawToScreen) {
        GeneralPath gp = getGeneralPath();
        if (testArea()) {
            return;
        } else {
            gp.reset();
            gp.moveTo(0.f, 0.f);

            double[] par = getArcParameters();

            if (isResizing()) {
                g2.setStroke(new BasicStroke(1.f));
                g2.setColor(JaxoColor.RED);

                Arc2D arc = new Arc2D.Float();
                if (getDoubleLine()) {
                    arc.setArc(-par[2] - getDLSeparation(),
                        -par[2] - getDLSeparation(),
                        2 * (par[2] + getDLSeparation()),
                        2 * (par[2] + getDLSeparation()), 0,
                        Math.toDegrees(par[3]), Arc2D.OPEN);
                    gp.append(arc, false);
                    arc.setArc(-par[2] + getDLSeparation(),
                        -par[2] + getDLSeparation(),
                        2 * (par[2] - getDLSeparation()),
                        2 * (par[2] - getDLSeparation()), 0,
                        Math.toDegrees(par[3]), Arc2D.OPEN);
                } else {
                    arc.setArc(-par[2], -par[2], 2 * par[2], 2 * par[2], 0,
                        Math.toDegrees(par[3]), Arc2D.OPEN);
                }
                gp.append(arc, false);
                gp = newtransarc(gp, par[0], par[1], par[4], 1.f);
                g2.draw(gp);
            } else {
                g2.setColor(getColor());
                g2.setStroke(new BasicStroke(getStroke()));

                int a = getAmp();
                int n;
                float ts;

                double arcLength = 2 * par[2] * Math.abs(par[3] / 2.d);
                n = (2 * ((int) Math.round(arcLength / getFreq()))) + 1;
                ts = (float) arcLength / n;

                if (getDoubleLine()) {
                    //gp.reset();
                    gp.moveTo(0.f, getDLSeparation());

                    for (int i = 1; i <= n; i++) {
                        gp.quadTo((((2 * i) - 1) * ts) / 2.f,
                            -a + getDLSeparation(), i * ts, getDLSeparation());
                        a = -a;
                    }

                    //gp.reset();
                    gp.moveTo(0.f, -getDLSeparation());

                    for (int i = 1; i <= n; i++) {
                        gp.quadTo((((2 * i) - 1) * ts) / 2.f,
                            a - getDLSeparation(), i * ts, -getDLSeparation());
                        a = -a;
                    }
                } else {
                    for (int i = 1; i <= n; i++) {
                        gp.quadTo((((2 * i) - 1) * ts) / 2.f, (float) -a,
                            i * ts, 0.f);
                        a = -a;
                    }
                }

                gp = conformalGP(gp, arcLength, -par[3]);

                AffineTransform at = new AffineTransform();
                at.translate(-par[2], 0.f);
                at.scale(1 / (Math.abs(par[3]) / 2.d),
                    1 / (Math.abs(par[3]) / 2.d));
                gp.transform(at);

                gp = newtransarc(gp, par[0], par[1], par[4], 1.d);

                g2.draw(gp);
            }

            Rectangle2D bb = gp.getBounds2D();

            double[] bbox =
            {bb.getMinX(), bb.getMinY(), bb.getMaxX(), bb.getMaxY()};
            setBoundingBox(bbox);
        }
    }

    /** The LaTeX command that is necessary to draw this JaPArc
     * 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 final String latexCommand(float scale, Dimension canvasDim) {
        double[] par = getArcParameters();
        double cx = par[0] / scale;
        double cy = (canvasDim.height - par[1]) / scale;
        double r = par[2] / scale;
        double ea = Math.toDegrees(par[3] - par[4]);
        double sa = -Math.toDegrees(par[4]);
        double amp = getAmp() / (2.d * scale);
        double nwig =
            (double) Math.round((2 * par[2] * Math.abs(par[3] / 2.d)) / getFreq())
            + 0.5;

        String command = "";
        String base = "\\PhotonArc";

        if (getDoubleLine()) {
            float offSet = getDLSeparation() / scale;

            String command1 =
                base + "(" + D_FORMAT.format(cx) + "," + D_FORMAT.format(cy)
                + ")" + "(" + D_FORMAT.format(r + offSet) + ","
                + D_FORMAT.format(sa) + "," + D_FORMAT.format(ea) + ")" + "{"
                + D_FORMAT.format(amp) + "}" + "{" + D_FORMAT.format(nwig)
                + "}";

            String command2 =
                base + "(" + D_FORMAT.format(cx) + "," + D_FORMAT.format(cy)
                + ")" + "(" + D_FORMAT.format(r - offSet) + ","
                + D_FORMAT.format(sa) + "," + D_FORMAT.format(ea) + ")" + "{"
                + D_FORMAT.format(amp) + "}" + "{" + D_FORMAT.format(nwig)
                + "}";

            command =
                command1.concat(command2.concat("%%JaxoDrawID:DoubleLine"
                        + "(" + D_FORMAT.format(getDLSeparation()) + ")"));
        } else {
            command =
                base + "(" + D_FORMAT.format(cx) + "," + D_FORMAT.format(cy)
                + ")" + "(" + D_FORMAT.format(r) + "," + D_FORMAT.format(sa)
                + "," + D_FORMAT.format(ea) + ")" + "{" + D_FORMAT.format(amp)
                + "}" + "{" + D_FORMAT.format(nwig) + "}";
        }

        return command;
    }

    /////////////////////////////////////////////////////////////////////////
    //
    //   private auxiliary methods                                         //
    //
    /////////////////////////////////////////////////////////////////////////
    private Point2D conformal(float px, float py, double length, double angle) {
        float nx =
            (float) (
                length / 2 * (
                    1
                    + (
                        Math.exp((py * angle) / length) * Math.cos((
                                px * angle
                            ) / length)
                    )
                )
            );
        float ny =
            (float) (
                -length / 2 * Math.exp((py * angle) / length) * Math.sin((
                        -px * angle
                    ) / length)
            );

        return new Point2D.Float(nx, ny);
    }

    private GeneralPath conformalGP(GeneralPath gpp, double length,
        double angle) {
        GeneralPath gp2 = new GeneralPath();
        FlatteningPathIterator pi =
            new FlatteningPathIterator(gpp.getPathIterator(null), 0.05);

        float[] segm = new float[6];
        int type;
        float corr = (1.f - (20.f / (float) length));

        gp2.moveTo(0.f, 0.f);

        while (!pi.isDone()) {
            type = pi.currentSegment(segm);

            float px1 =
                (float) conformal(segm[0], segm[1], length, angle).getX();
            float py1 =
                (float) conformal(segm[0], segm[1], length, angle).getY();
            float px2 =
                (float) conformal(segm[2], segm[3], length, angle).getX();
            float py2 =
                (float) conformal(segm[2], segm[3], length, angle).getY();
            float px3 =
                (float) conformal(segm[4], segm[5], length, angle).getX();
            float py3 =
                (float) conformal(segm[4], segm[5], length, angle).getY();

            if (type == PathIterator.SEG_MOVETO) {
                gp2.moveTo(px1, py1);
            } else if (type == PathIterator.SEG_LINETO) {
                gp2.lineTo(px1, py1);
            } else if (type == PathIterator.SEG_QUADTO) {
                px1 = (float) conformal(segm[0], corr * segm[1], length, angle)
                                  .getX();
                py1 = (float) conformal(segm[0], corr * segm[1], length, angle)
                                  .getY();
                gp2.quadTo(px1, py1, px2, py2);
            } else if (type == PathIterator.SEG_CUBICTO) {
                gp2.curveTo(px1, py1, px2, py2, px3, py3);
            } else {
                gp2.closePath();
            }

            pi.next();
        }

        return gp2;
    }
}