/*
 * @(#)PlotMarkAlgorithm.java    1.0  17 February 2001
 *
 * Copyright 2005
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.gui;

import edu.neu.ccs.*;

import java.awt.*;
import java.awt.geom.*;

/**
 * <p>Class <code>PlotMarkAlgorithm</code> defines the requirements for an
 * algorithm that will produce a scalable shape defined in the neighborhood
 * of a given point.  This class is intended to be used in constructors for
 * the class <code>PlotMark</code>.</p>
 *
 * <p>This class provides several static instances of itself.</p>
 *
 * @author  Richard Rasala
 * @version 2.4.0
 * @since   2.4.0
 */
public abstract class PlotMarkAlgorithm
{
    
    /**
     * <p>Returns a shape constructed in the neighborhood of the given point
     * and scaled with the given size.</p>
     *
     * <p>If the given point is <code>null</code>, returns an empty shape.</p>
     *
     * <p>Otherwise calls <code>makeShape(double, double, int)</code>.</p>
     *
     * @param p the point defining where to place the shape
     * @param size the scale size
     */
    public final Shape makeShape(Point2D p, int size) {
        if (p == null)
            return new GeneralPath();
        
        return makeShape(p.getX(), p.getY(), size);
    }
    
    
    /**
     * <p>Returns a shape constructed in the neighborhood of the given point
     * and scaled with the given size.</p>
     *
     * <p>When defined this method may return an empty shape but should not
     * return <code>null</code>.</p>
     *
     * <p>The scale size should be forced to at least 1 before building the
     * shape.</p>
     *
     * @param x the x-coordinate of the point defining where
     *          to place the shape
     * @param y the y-coordinate of the point defining where
     *          to place the shape
     * @param size the scale size
     */
    public abstract Shape makeShape(double x, double y, int size);
    
    
    /**
     * <p>The horizontal bar algorithm.</p>
     *
     * <p>Produces the line segment path (x-size,y) to (x+size,y).</p>
     *
     * <p>When used in a <code>PlotMark</code>, the fill setting should
     * be <code>false</code>.</p>
     */
    public static final PlotMarkAlgorithm HBar = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) (x - size), (float) y);
            path.lineTo((float) (x + size), (float) y);
            
            return path;
        }
    };
    
    
    /**
     * <p>The vertical bar algorithm.</p>
     *
     * <p>Produces the line segment path (x,y-size) to (x,y+size).</p>
     *
     * <p>When used in a <code>PlotMark</code>, the fill setting should
     * be <code>false</code>.</p>
     */
    public static final PlotMarkAlgorithm VBar = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) (y - size));
            path.lineTo((float) x, (float) (y + size));
            
            return path;
        }
    };
    
    
    /**
     * <p>The plus sign algorithm.</p>
     *
     * <p>Produces the combined path with 2 line segments:</p>
     *
     * <ul>
     *   <li>(x-size,y) to (x+size,y)</li>
     *   <li>(x,y-size) to (x,y+size)</li>
     * </ul>
     *
     * <p>When used in a <code>PlotMark</code>, the fill setting should
     * be <code>false</code>.</p>
     */
    public static final PlotMarkAlgorithm Plus = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) (x - size), (float) y);
            path.lineTo((float) (x + size), (float) y);
            
            path.moveTo((float) x, (float) (y - size));
            path.lineTo((float) x, (float) (y + size));
            
            return path;
        }
    };
    
    
    /**
     * <p>The cross sign algorithm.</p>
     *
     * <p>Produces the combined path with 2 line segments:</p>
     *
     * <ul>
     *   <li>(x-size,y-size) to (x+size,y+size)</li>
     *   <li>(x+size,y-size) to (x-size,y+size)</li>
     * </ul>
     *
     * <p>When used in a <code>PlotMark</code>, the fill setting should
     * be <code>false</code>.</p>
     */
    public static final PlotMarkAlgorithm Cross = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) (x - size), (float) (y - size));
            path.lineTo((float) (x + size), (float) (y + size));
            
            path.moveTo((float) (x + size), (float) (y - size));
            path.lineTo((float) (x - size), (float) (y + size));
            
            return path;
        }
    };
    
    
    /**
     * <p>The asterisk algorithm.</p>
     *
     * <p>Produces the combined path with 4 line segments:</p>
     *
     * <ul>
     *   <li>(x-size,y) to (x+size,y)</li>
     *   <li>(x,y-size) to (x,y+size)</li>
     *   <li>(x-size,y-size) to (x+size,y+size)</li>
     *   <li>(x+size,y-size) to (x-size,y+size)</li>
     * </ul>
     *
     * <p>When used in a <code>PlotMark</code>, the fill setting should
     * be <code>false</code>.</p>
     */
    public static final PlotMarkAlgorithm Asterisk = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) (x - size), (float) y);
            path.lineTo((float) (x + size), (float) y);
            
            path.moveTo((float) x, (float) (y - size));
            path.lineTo((float) x, (float) (y + size));
            
            path.moveTo((float) (x - size), (float) (y - size));
            path.lineTo((float) (x + size), (float) (y + size));
            
            path.moveTo((float) (x + size), (float) (y - size));
            path.lineTo((float) (x - size), (float) (y + size));
            
            return path;
        }
    };
    
    
    /**
     * <p>The square algorithm.</p>
     *
     * <p>Returns new XSquare(x, y, size).</p>
     */
    public static final PlotMarkAlgorithm Square = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            return new XSquare(x, y, size);
        }
    };
    
    
    /**
     * <p>The circle algorithm.</p>
     *
     * <p>Returns new XCircle(x, y, size).</p>
     */
    public static final PlotMarkAlgorithm Circle = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            return new XCircle(x, y, size);
        }
    };
    
    
    /**
     * <p>The diamond algorithm.</p>
     *
     * <p>Produces the closed path with 4 vertices:</p>
     *
     * <ul>
     *   <li>(x,y-size)</li>
     *   <li>(x+size,y)</li>
     *   <li>(x,y+size)</li>
     *   <li>(x-size,y)</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm Diamond = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) (y - size));
            path.lineTo((float) (x + size), (float) y);
            path.lineTo((float) x, (float) (y + size));
            path.lineTo((float) (x - size), (float) y);
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The wedge-facing-north algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x+size,y+(2*size))</li>
     *   <li>(x-size,y+(2*size))</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm WedgeN = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            int d = 2 * size;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x + size), (float) (y + d));
            path.lineTo((float) (x - size), (float) (y + d));
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The wedge-facing-east algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x-(2*size),y+size)</li>
     *   <li>(x-(2*size),y-size)</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm WedgeE = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            int d = 2 * size;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x - d), (float) (y + size));
            path.lineTo((float) (x - d), (float) (y - size));
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The wedge-facing-south algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x-size,y-(2*size))</li>
     *   <li>(x+size,y-(2*size))</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm WedgeS = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            int d = 2 * size;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x - size), (float) (y - d));
            path.lineTo((float) (x + size), (float) (y - d));
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The wedge-facing-west algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x+(2*size),y-size)</li>
     *   <li>(x+(2*size),y+size)</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm WedgeW = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            int d = 2 * size;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x + d), (float) (y - size));
            path.lineTo((float) (x + d), (float) (y + size));
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The blunt-wedge-facing-north algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x+size,y+size)</li>
     *   <li>(x-size,y+size)</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm BluntWedgeN = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x + size), (float) (y + size));
            path.lineTo((float) (x - size), (float) (y + size));
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The blunt-wedge-facing-east algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x-size,y+size)</li>
     *   <li>(x-size,y-size)</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm BluntWedgeE = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x - size), (float) (y + size));
            path.lineTo((float) (x - size), (float) (y - size));
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The blunt-wedge-facing-south algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x-size,y-size)</li>
     *   <li>(x+size,y-size)</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm BluntWedgeS = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x - size), (float) (y - size));
            path.lineTo((float) (x + size), (float) (y - size));
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The blunt-wedge-facing-west algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x+size,y-size)</li>
     *   <li>(x+size,y+size)</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm BluntWedgeW = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x + size), (float) (y - size));
            path.lineTo((float) (x + size), (float) (y + size));
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The sharp-wedge-facing-north algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x+size,y+(3*size))</li>
     *   <li>(x-size,y+(3*size))</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm SharpWedgeN = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            int d = 3 * size;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x + size), (float) (y + d));
            path.lineTo((float) (x - size), (float) (y + d));
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The sharp-wedge-facing-east algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x-(3*size),y+size)</li>
     *   <li>(x-(3*size),y-size)</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm SharpWedgeE = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            int d = 3 * size;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x - d), (float) (y + size));
            path.lineTo((float) (x - d), (float) (y - size));
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The sharp-wedge-facing-south algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x-size,y-(3*size))</li>
     *   <li>(x+size,y-(3*size))</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm SharpWedgeS = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            int d = 3 * size;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x - size), (float) (y - d));
            path.lineTo((float) (x + size), (float) (y - d));
            
            path.closePath();
            
            return path;
        }
    };
    
    
    /**
     * <p>The sharp-wedge-facing-west algorithm.</p>
     *
     * <p>Produces the closed path with 3 vertices:</p>
     *
     * <ul>
     *   <li>(x,y)</li>
     *   <li>(x+(3*size),y-size)</li>
     *   <li>(x+(3*size),y+size)</li>
     * </ul>
     */
    public static final PlotMarkAlgorithm SharpWedgeW = new PlotMarkAlgorithm() {
        public Shape makeShape(double x, double y, int size) {
            if (size < 1)
                size = 1;
            
            int d = 3 * size;
            
            GeneralPath path = new GeneralPath();
            
            path.moveTo((float) x, (float) y);
            path.lineTo((float) (x + d), (float) (y - size));
            path.lineTo((float) (x + d), (float) (y + size));
            
            path.closePath();
            
            return path;
        }
    };
    
    
}
