001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.math.geometry.point;
031
032import java.io.DataInput;
033import java.io.DataOutput;
034import java.io.IOException;
035import java.io.PrintWriter;
036import java.util.Random;
037import java.util.Scanner;
038
039import Jama.Matrix;
040
041/**
042 * Simple concrete implementation of a two dimensional point.
043 *
044 * @author Jonathon Hare
045 */
046public class Point2dImpl implements Point2d, Cloneable {
047        /**
048         * The x-coordinate
049         */
050        public float x;
051
052        /**
053         * The y-coordinate
054         */
055        public float y;
056
057        /**
058         * Construct a Point2dImpl with the given (x, y) coordinates
059         *
060         * @param x
061         *            x-coordinate
062         * @param y
063         *            y-coordinate
064         */
065        public Point2dImpl(float x, float y)
066        {
067                this.x = x;
068                this.y = y;
069        }
070
071        /**
072         * Construct a Point2dImpl with the (x,y) coordinates given via another
073         * point.
074         *
075         * @param p
076         *            The point to copy from.
077         */
078        public Point2dImpl(Point2d p)
079        {
080                this.copyFrom(p);
081        }
082
083        /**
084         * Construct a Point2dImpl at the origin.
085         */
086        public Point2dImpl()
087        {
088                // do nothing
089        }
090
091        /**
092         * Construct a {@link Point2dImpl} using the first two ordinates of a
093         * {@link Coordinate}.
094         *
095         * @param coord
096         *            the {@link Coordinate}
097         */
098        public Point2dImpl(Coordinate coord) {
099                x = coord.getOrdinate(0).floatValue();
100                y = coord.getOrdinate(1).floatValue();
101        }
102
103        /**
104         * Construct a Point2dImpl with the given (x, y) coordinates. The values
105         * will be cast to single precision.
106         *
107         * @param x
108         *            x-coordinate
109         * @param y
110         *            y-coordinate
111         */
112        public Point2dImpl(double x, double y)
113        {
114                this.x = (float) x;
115                this.y = (float) y;
116        }
117
118        @Override
119        public float getX() {
120                return x;
121        }
122
123        @Override
124        public void setX(float x) {
125                this.x = x;
126        }
127
128        @Override
129        public float getY() {
130                return y;
131        }
132
133        @Override
134        public void setY(float y) {
135                this.y = y;
136        }
137
138        @Override
139        public void copyFrom(Point2d p)
140        {
141                this.x = p.getX();
142                this.y = p.getY();
143        }
144
145        @Override
146        public String toString() {
147                return "(" + x + "," + y + ")";
148        }
149
150        @Override
151        public Point2dImpl clone() {
152                Point2dImpl clone;
153                try {
154                        clone = (Point2dImpl) super.clone();
155                } catch (final CloneNotSupportedException e) {
156                        return null;
157                }
158                return clone;
159        }
160
161        @Override
162        public Float getOrdinate(int dimension) {
163                if (dimension == 0)
164                        return x;
165                return y;
166        }
167
168        @Override
169        public int getDimensions() {
170                return 2;
171        }
172
173        @Override
174        public void translate(float x, float y) {
175                this.x += x;
176                this.y += y;
177        }
178
179        @Override
180        public void translate(Point2d v) {
181                this.x += v.getX();
182                this.y += v.getY();
183        }
184
185        @Override
186        public Point2dImpl transform(Matrix transform) {
187                if (transform.getRowDimension() == 3) {
188                        float xt = (float) transform.get(0, 0) * getX() + (float) transform.get(0, 1) * getY()
189                                        + (float) transform.get(0, 2);
190                        float yt = (float) transform.get(1, 0) * getX() + (float) transform.get(1, 1) * getY()
191                                        + (float) transform.get(1, 2);
192                        final float zt = (float) transform.get(2, 0) * getX() + (float) transform.get(2, 1) * getY()
193                                        + (float) transform.get(2, 2);
194
195                        xt /= zt;
196                        yt /= zt;
197
198                        return new Point2dImpl(xt, yt);
199                } else if (transform.getRowDimension() == 2 && transform.getColumnDimension() == 2) {
200                        final float xt = (float) transform.get(0, 0) * getX() + (float) transform.get(0, 1) * getY();
201                        final float yt = (float) transform.get(1, 0) * getX() + (float) transform.get(1, 1) * getY();
202
203                        return new Point2dImpl(xt, yt);
204                } else if (transform.getRowDimension() == 2 && transform.getColumnDimension() == 3) {
205                        final float xt = (float) transform.get(0, 0) * getX() + (float) transform.get(0, 1) * getY()
206                                        + (float) transform.get(0, 2);
207                        final float yt = (float) transform.get(1, 0) * getX() + (float) transform.get(1, 1) * getY()
208                                        + (float) transform.get(1, 2);
209
210                        return new Point2dImpl(xt, yt);
211                }
212                throw new IllegalArgumentException("Transform matrix has unexpected size");
213        }
214
215        @Override
216        public boolean equals(Object o) {
217                if (!(o instanceof Point2d))
218                        return false;
219                final Point2d p = (Point2d) o;
220                return p.getX() == this.x && p.getY() == this.y;
221        }
222
223        @Override
224        public int hashCode()
225        {
226                return toString().hashCode();
227        }
228
229        @Override
230        public Point2d minus(Point2d a) {
231                return new Point2dImpl(this.x - a.getX(), this.y - a.getY());
232        }
233
234        @Override
235        public void readASCII(Scanner in) throws IOException {
236                x = in.nextFloat();
237                y = in.nextFloat();
238        }
239
240        @Override
241        public String asciiHeader() {
242                return "Point2d";
243        }
244
245        @Override
246        public void readBinary(DataInput in) throws IOException {
247                x = in.readFloat();
248                y = in.readFloat();
249        }
250
251        @Override
252        public byte[] binaryHeader() {
253                return "PT2D".getBytes();
254        }
255
256        @Override
257        public void writeASCII(PrintWriter out) throws IOException {
258                out.format("%f %f", x, y);
259        }
260
261        @Override
262        public void writeBinary(DataOutput out) throws IOException {
263                out.writeFloat(x);
264                out.writeFloat(y);
265        }
266
267        @Override
268        public Point2dImpl copy() {
269                return clone();
270        }
271
272        /**
273         * Create a random point in ([0..1], [0..1]).
274         *
275         * @return random point.
276         */
277        public static Point2d createRandomPoint() {
278                return new Point2dImpl((float) Math.random(), (float) Math.random());
279        }
280
281        /**
282         * Create a random point in ([0..1], [0..1]) with the given random number
283         * generator.
284         *
285         * @param rng
286         *            the random number generator
287         * @return random point.
288         */
289        public static Point2d createRandomPoint(Random rng) {
290                return new Point2dImpl(rng.nextFloat(), rng.nextFloat());
291        }
292
293        /**
294         * @param calculateCentroid
295         * @return a point from a double array
296         */
297        public static Point2d fromDoubleArray(double[] calculateCentroid) {
298                return new Point2dImpl((float) calculateCentroid[0], (float) calculateCentroid[1]);
299        }
300
301        @Override
302        public void setOrdinate(int dimension, Number value) {
303                if (dimension == 0)
304                        x = value.floatValue();
305                if (dimension == 1)
306                        y = value.floatValue();
307        }
308}