/*
* Copyright (C) 2011-2015, Peter Abeles. All Rights Reserved.
*
* This file is part of Geometric Regression Library (GeoRegression).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package georegression.geometry;
import georegression.struct.GeoTuple2D_F64;
import georegression.struct.point.Point2D_F64;
import georegression.struct.shapes.Rectangle2D_F64;
import georegression.struct.shapes.RectangleLength2D_F64;
import org.ddogleg.sorting.QuickSort_F64;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
*
*
*/
public class UtilPoint2D_F64 {
public static List<Point2D_F64> copy( List<Point2D_F64> pts ) {
List<Point2D_F64> ret = new ArrayList<Point2D_F64>();
for( Point2D_F64 p : pts ) {
ret.add( p.copy() );
}
return ret;
}
public static void noiseNormal( List<Point2D_F64> pts, double sigma, Random rand ) {
for( Point2D_F64 p : pts ) {
p.x += rand.nextGaussian() * sigma;
p.y += rand.nextGaussian() * sigma;
}
}
public static double distance( double x0, double y0, double x1, double y1 ) {
double dx = x1 - x0;
double dy = y1 - y0;
return Math.sqrt( dx * dx + dy * dy );
}
public static double distanceSq( double x0, double y0, double x1, double y1 ) {
double dx = x1 - x0;
double dy = y1 - y0;
return dx * dx + dy * dy;
}
/**
* Finds the point which has the mean location of all the points in the list. This is also known
* as the centroid.
*
* @param list List of points
* @param mean Storage for mean point. If null then a new instance will be declared
* @return The found mean
*/
public static Point2D_F64 mean( List<Point2D_F64> list , Point2D_F64 mean ) {
if( mean == null )
mean = new Point2D_F64();
double x = 0;
double y = 0;
for( Point2D_F64 p : list ) {
x += p.getX();
y += p.getY();
}
x /= list.size();
y /= list.size();
mean.set(x, y);
return mean;
}
/**
* Finds the point which has the mean location of all the points in the array. This is also known
* as the centroid.
*
* @param list List of points
* @param offset First index in list
* @param length Length of elements in list
* @param mean Storage for mean point. If null then a new instance will be declared
* @return The found mean
*/
public static Point2D_F64 mean( Point2D_F64[] list , int offset , int length , Point2D_F64 mean ) {
if( mean == null )
mean = new Point2D_F64();
double x = 0;
double y = 0;
for (int i = 0; i < length; i++) {
Point2D_F64 p = list[offset+i];
x += p.getX();
y += p.getY();
}
x /= length;
y /= length;
mean.set(x, y);
return mean;
}
/**
* Computes the mean/average of two points.
*
* @param a (input) Point A
* @param b (input) Point B
* @param mean (output) average of 'a' and 'b'
*
*/
public static Point2D_F64 mean( Point2D_F64 a , Point2D_F64 b, Point2D_F64 mean ) {
if( mean == null )
mean = new Point2D_F64();
mean.x = (a.x + b.x)/2.0;
mean.y = (a.y + b.y)/2.0;
return mean;
}
public static List<Point2D_F64> random( double min, double max, int num, Random rand ) {
List<Point2D_F64> ret = new ArrayList<Point2D_F64>();
double d = max - min;
for( int i = 0; i < num; i++ ) {
Point2D_F64 p = new Point2D_F64();
p.x = rand.nextDouble() * d + min;
p.y = rand.nextDouble() * d + min;
ret.add( p );
}
return ret;
}
public static boolean isEquals( GeoTuple2D_F64 a, GeoTuple2D_F64 b, double tol ) {
return ( Math.abs( a.x - b.x ) <= tol && Math.abs( a.x - b.x ) <= tol );
}
/**
* Finds the minimal volume {@link georegression.struct.shapes.RectangleLength2D_F64} which contains all the points.
*
* @param points Input: List of points.
* @param bounding Output: Bounding rectangle
*/
public static RectangleLength2D_F64 bounding(List<Point2D_F64> points, RectangleLength2D_F64 bounding) {
if( bounding == null )
bounding = new RectangleLength2D_F64();
double minX=Double.MAX_VALUE,maxX=-Double.MAX_VALUE;
double minY=Double.MAX_VALUE,maxY=-Double.MAX_VALUE;
for( int i = 0; i < points.size(); i++ ) {
Point2D_F64 p = points.get(i);
if( p.x < minX )
minX = p.x;
if( p.x > maxX )
maxX = p.x;
if( p.y < minY )
minY = p.y;
if( p.y > maxY )
maxY = p.y;
}
bounding.x0 = minX;
bounding.y0 = minY;
bounding.width = maxX-minX;
bounding.height = maxY-minY;
// make sure rounding doesn't cause a point to be out of bounds
bounding.width += Math.max(0,(maxX-(bounding.x0+bounding.width ))*10.0);
bounding.height += Math.max(0,(maxY-(bounding.y0+bounding.height))*10.0);
return bounding;
}
/**
* Finds the minimal volume {@link georegression.struct.shapes.RectangleLength2D_F64} which contains all the points.
*
* @param points Input: List of points.
* @param bounding Output: Bounding rectangle
*/
public static Rectangle2D_F64 bounding(List<Point2D_F64> points, Rectangle2D_F64 bounding) {
if( bounding == null )
bounding = new Rectangle2D_F64();
double minX=Double.MAX_VALUE,maxX=-Double.MAX_VALUE;
double minY=Double.MAX_VALUE,maxY=-Double.MAX_VALUE;
for( int i = 0; i < points.size(); i++ ) {
Point2D_F64 p = points.get(i);
if( p.x < minX )
minX = p.x;
if( p.x > maxX )
maxX = p.x;
if( p.y < minY )
minY = p.y;
if( p.y > maxY )
maxY = p.y;
}
bounding.set(minX,minY,maxX,maxY);
return bounding;
}
/**
* Puts the points into counter-clockwise order around their center.
*
* @param points List of points. Not modified.
* @return ordered list
*/
public static List<Point2D_F64> orderCCW( List<Point2D_F64> points ) {
Point2D_F64 center = mean(points,null);
double angles[] = new double[ points.size() ];
for (int i = 0; i < angles.length; i++) {
Point2D_F64 p = points.get(i);
double dx = p.x - center.x;
double dy = p.y - center.y;
angles[i] = Math.atan2(dy,dx);
}
int order[] = new int[ points.size() ];
QuickSort_F64 sorter = new QuickSort_F64();
sorter.sort(angles,points.size(),order);
List<Point2D_F64> out = new ArrayList<Point2D_F64>(points.size());
for (int i = 0; i < points.size(); i++) {
out.add(points.get(order[i]));
}
return out;
}
}