view dwtx/draw2d/geometry/PointList.d @ 98:95307ad235d9

Added Draw2d code, still work in progress
author Frank Benoit <benoit@tionex.de>
date Sun, 03 Aug 2008 00:52:14 +0200
parents
children
line wrap: on
line source

/*******************************************************************************
 * Copyright (c) 2000, 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 * Port to the D programming language:
 *     Frank Benoit <benoit@tionex.de>
 *******************************************************************************/
module dwtx.draw2d.geometry.PointList;

import dwt.dwthelper.utils;
import tango.text.convert.Format;

import dwtx.draw2d.geometry.Translatable;
import dwtx.draw2d.geometry.Rectangle;
import dwtx.draw2d.geometry.Point;
import dwtx.draw2d.geometry.Geometry;

/**
 * Represents a List of Points. This class is used for building an <code>int[]</code>.
 * The array is internal, and is constructed and queried by the client using
 * {@link Point Points}. DWT uses integer arrays when painting polylines and polygons.
 */
public class PointList
    : /+java.io.Serializable,+/ Translatable
{

private int[] points;
private Rectangle bounds;
private int size_ = 0;

static const long serialVersionUID = 1;

/**
 * Constructs an empty PointList.
 *
 * @since 2.0
 */
public this() { }

/**
 * Constructs a PointList with the given points.
 * @param points int array where two consecutive ints form the coordinates of a point
 * @since 3.1
 */
public this(int points[]) {
    this.points = points;
    this.size_ = points.length / 2;
}

/**
 * Constructs a PointList with initial capacity <i>size</i>, but no points.
 *
 * @param size  Number of points to hold.
 * @since 2.0
 */
public this(int size_) {
    points = new int[size_ * 2];
}

/**
 * Appends all of the given points to this PointList.
 * @param source the source pointlist
 */
public void addAll(PointList source) {
    ensureCapacity(size_ + source.size_);
    System.arraycopy(source.points, 0, points, size_ * 2, source.size_ * 2);
    size_ += source.size_;
}

/**
 * Adds Point <i>p</i> to this PointList.
 * @param p the point to be added
 * @see  #removePoint(int)
 * @since 2.0
 */
public void addPoint(Point p) {
    addPoint(p.x, p.y);
}

/**
 * Adds the input point values to this PointList.
 * @param x  X value of a point to add
 * @param y  Y value of a point to add
 * @since 2.0
 */
public void addPoint(int x, int y) {
    bounds = null;
    int index = size_ * 2;
    ensureCapacity(size_ + 1);
    points[index] = x;
    points[index + 1] = y;
    size_++;
}

private void ensureCapacity(int newSize) {
    newSize *= 2;
    if (points.length < newSize) {
        int old[] = points;
        points = new int[Math.max(newSize, size_ * 4)];
        System.arraycopy(old, 0, points, 0, size_ * 2);
    }
}

/**
 * Returns the smallest Rectangle which contains all Points.
 * @return The smallest Rectangle which contains all Points.
 * @since 2.0
 */
public Rectangle getBounds() {
    if (bounds !is null)
        return bounds;
    bounds = new Rectangle();
    if (size_ > 0) {
        bounds.setLocation(getPoint(0));
        for (int i = 0; i < size_; i++)
            bounds.union_(getPoint(i));
    }
    return bounds;
}

/**
 * Creates a copy
 * @return PointList A copy of this PointList
 */
public PointList getCopy() {
    PointList result = new PointList(size_);
    System.arraycopy(points, 0, result.points, 0, size_ * 2);
    result.size_ = size_;
    result.bounds = null;
    return result;
}

/**
 * Returns the first Point in the list.
 * @return  The first point in the list.
 * @throws IndexOutOfBoundsException if the list is empty
 * @since 2.0
 */
public Point getFirstPoint() {
    return getPoint(0);
}

/**
 * Returns the last point in the list.
 * @throws IndexOutOfBoundsException if the list is empty
 * @return  The last Point in the list
 * @since 2.0
 */
public Point getLastPoint() {
    return getPoint(size_ - 1);
}

/**
 * Returns the midpoint of the list of Points. The midpoint is the median of the List,
 * unless there are 2 medians (size is even), then the middle of the medians is returned.
 * @return The midpoint
 * @throws IndexOutOfBoundsException if the list is empty
 */
public Point getMidpoint() {
    if (size() % 2 is 0)
        return getPoint(size() / 2 - 1).
            getTranslated(getPoint(size() / 2)).
            scale(0.5f);
    return getPoint(size() / 2);
}

/**
 * Returns the Point in the list at the specified index.
 * @param index Index of the desired Point
 * @return  The requested Point
 * @throws IndexOutOfBoundsException If the specified index is out of range
 * @since 2.0
 */
public Point getPoint(int index) {
    if (index < 0 || index >= size_)
        throw new IndexOutOfBoundsException( Format(
            "Index: {}, Size: {}", index, //$NON-NLS-1$
            size_)); //$NON-NLS-1$
    index *= 2;
    return new Point(points[index], points[index + 1]);
}

/**
 * Copies the x and y values at given index into a specified Point.
 * This method exists to avoid the creation of a new <code>Point</code>.
 * @see #getPoint(int)
 * @param p The Point which will be set with the &lt;x, y&gt; values
 * @param index The index being requested
 * @return The parameter <code>p</code> is returned for convenience
 * @since 2.0
 */
public Point getPoint(Point p, int index) {
    if (index < 0 || index >= size_)
        throw new IndexOutOfBoundsException( Format(
            "Index: {}, Size: {}", index, //$NON-NLS-1$
            size_)); //$NON-NLS-1$
    index *= 2;
    p.x = points[index];
    p.y = points[index + 1];
    return p;
}

/**
 * Inserts a given point at a specified index.
 * @param p  Point to be inserted.
 * @param index  Position where the point is to be inserted.
 * @exception IndexOutOfBoundsException  if the index is invalid
 * @see  #setPoint(Point, int)
 * @since 2.0
 */
public void insertPoint(Point p, int index) {
    if (bounds !is null && !bounds.contains(p))
        bounds = null;
    if (index > size_ || index < 0)
        throw new IndexOutOfBoundsException( Format(
            "Index: {}, Size: {}", index, //$NON-NLS-1$
            size_)); //$NON-NLS-1$
    index *= 2;

    int length = points.length;
    int old[] = points;
    points = new int[length + 2];
    System.arraycopy(old, 0, points, 0, index);
    System.arraycopy(old, index, points, index + 2, length - index);

    points[index] = p.x;
    points[index + 1] = p.y;
    size_++;
}

/**
 * Determines whether any of the line segments represented by this PointList intersect
 * the given Rectangle.  If a segment touches the given rectangle, that's considered
 * intersection.
 *
 * @param r the rectangle
 * @return <code>true</code> if the given rectangle intersects any of the line segments
 *         represented by this PointList
 * @since 3.1
 */
public bool intersects(Rectangle r) {
    if (r.isEmpty())
        return false;
    for (int i = 0; i < size_ * 2; i += 2) {
        if (r.contains(points[i], points[i + 1]))
            return true;
    }
    int diagonal1x1 = r.x,
        diagonal1y1 = r.y,
        diagonal1x2 = r.x + r.width - 1,
        diagonal1y2 = r.y + r.height - 1,
        diagonal2x1 = r.x + r.width - 1,
        diagonal2y1 = r.y,
        diagonal2x2 = r.x,
        diagonal2y2 = r.y + r.height - 1;
    for (int i = 0; i < (size_ - 1) * 2; i += 2) {
        if (Geometry.linesIntersect(diagonal1x1, diagonal1y1, diagonal1x2,
                diagonal1y2, points[i], points[i + 1], points[i + 2], points[i + 3])
                || Geometry.linesIntersect(diagonal2x1, diagonal2y1, diagonal2x2,
                diagonal2y2, points[i], points[i + 1], points[i + 2], points[i + 3]))
            return true;
    }
    return false;
}

/**
 * @see dwtx.draw2d.geometry.Translatable#performScale(double)
 */
public void performScale(double factor) {
    for (int i = 0; i < points.length; i++)
        points[i] = cast(int)Math.floor(points[i] * factor);
    bounds = null;
}

/**
 * @see dwtx.draw2d.geometry.Translatable#performTranslate(int, int)
 */
public void performTranslate(int dx, int dy) {
    for (int i = 0; i < size_ * 2; i += 2) {
        points[i] += dx;
        points[i + 1] += dy;
    }
    if (bounds !is null)
        bounds.translate(dx, dy);
}

/**
 * Removes all the points stored by this list. Resets all
 * the properties based on the point information.
 *
 * @since 2.0
 */
public void removeAllPoints() {
    bounds = null;
    size_ = 0;
}

/**
 * Removes the point at the specified index from the PointList, and
 * returns it.
 * @since 2.0
 * @see  #addPoint(Point)
 * @param index   Index of the point to be removed.
 * @return  The point which has been removed
 * @throws IndexOutOfBoundsException if the removal index is beyond the list capacity
 */
public Point removePoint(int index) {
    bounds = null;
    if (index < 0 || index >= size_)
        throw new IndexOutOfBoundsException( Format(
            "Index: {}, Size: {}", index, //$NON-NLS-1$
            size_)); //$NON-NLS-1$

    index *= 2;
    Point pt = new Point(points[index], points[index + 1]);
    if (index !is size_ * 2 - 2)
        System.arraycopy(points, index + 2, points, index, size_ * 2 - index - 2);
    size_--;
    return pt;
}

/**
 * Reverses the order of the points in the list.
 * @since 3.2
 */
public void reverse() {
    int temp;
    for (int i = 0, j = size_ * 2 - 2; i < size_; i += 2 , j -= 2) {
        temp = points[i];
        points[i] = points[j];
        points[j] = temp;
        temp = points[i + 1];
        points[i + 1] = points[j + 1];
        points[j + 1] = temp;
    }
}

/**
 * Overwrites a point at a given index in the list with the specified Point.
 * @param pt  Point which is to be stored at the index.
 * @param index  Index where the given point is to be stored.
 * @since 2.0
 */
public void setPoint(Point pt, int index) {
    if (index < 0 || index >= size_)
        throw new IndexOutOfBoundsException( Format(
            "Index: {}, Size: {}", index, //$NON-NLS-1$
            size_)); //$NON-NLS-1$
    if (bounds !is null && !bounds.contains(pt))
        bounds = null;
    points[index * 2] = pt.x;
    points[index * 2 + 1] = pt.y;
}

/**
 * Sets the size of this PointList.
 * @param newSize the new size
 */
public void setSize(int newSize) {
    if (points.length > newSize * 2) {
        size_ = newSize;
        return;
    }
    int[] newArray = new int[newSize * 2];
    System.arraycopy(points, 0, newArray, 0, points.length);
    points = newArray;
    size_ = newSize;
}

/**
 * Returns the number of points in this PointList.
 * @return  The number of points
 * @since 2.0
 */
public int size() {
    return size_;
}

/**
 * Returns the contents of this PointList as an integer array.  The returned array is by
 * reference.  Any changes made to the array will also be changing the original PointList.
 *
 * @return the integer array of points by reference
 * @since 2.0
 */
public int[] toIntArray() {
    if (points.length !is size_ * 2) {
        int[] old = points;
        points = new int[size_ * 2];
        System.arraycopy(old, 0, points, 0, size_ * 2);
    }
    return points;
}

/**
 * Moves the origin (0,0) of the coordinate system of all
 * the points to the Point <i>pt</i>. This updates the position
 * of all the points in this PointList.
 *
 * @param pt  Position by which all the points will be shifted.
 * @see #translate(int,int)
 * @since 2.0
 */
public final void translate(Point pt) {
    translate(pt.x, pt.y);
}

/**
 * Moves the origin (0,0) of the coordinate system of all
 * the points to the Point (x,y). This updates the position
 * of all the points in this PointList.
 *
 * @param x  Amount by which all the points will be shifted on the X axis.
 * @param y  Amount by which all the points will be shifted on the Y axis.
 * @see  #translate(Point)
 * @since 2.0
 */
public void translate(int x, int y) {
    if (x is 0 && y is 0)
        return;
    if (bounds !is null)
        bounds.translate(x, y);
    for (int i = 0; i < size_ * 2; i += 2) {
        points[i] += x;
        points[i + 1] += y;
    }
}

/**
 * Transposes all x and y values. Useful for orientation changes.
 * @since 3.2
 */
public void transpose() {
    int temp;
    if (bounds !is null)
        bounds.transpose();
    for (int i = 0; i < size_ * 2; i += 2) {
        temp = points[i];
        points[i] = points[i + 1];
        points[i + 1] = temp;
    }
}

}