georegression.geometry.UtilPoint2D_F32 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of georegression Show documentation
Show all versions of georegression Show documentation
GeoRegression is a free Java based geometry library for scientific computing in fields such as robotics and computer vision with a focus on 2D/3D space.
The newest version!
/*
* Copyright (C) 2021, 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 javax.annotation.Generated;
import georegression.struct.GeoTuple2D_F32;
import georegression.struct.point.Point2D_F32;
import georegression.struct.shapes.Rectangle2D_F32;
import georegression.struct.shapes.RectangleLength2D_F32;
import org.ddogleg.sorting.QuickSort_F32;
import org.ejml.data.FMatrix;
import org.ejml.data.ReshapeMatrix;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
*
*
*/
@Generated("georegression.geometry.UtilPoint2D_F64")
public class UtilPoint2D_F32 {
/**
* Finds the closest point in the list to the specified point that is within tolerance. Returns
* the index of the point or -1 if none was found.
*
* @param tol Tolerance in Euclidean distance.
*/
public static int findClosestIdx( float x , float y, List pts , float tol ) {
float bestDist = Float.MAX_VALUE;
int best = -1;
for (int i = 0; i < pts.size(); i++) {
float dist = pts.get(i).distance2(x,y);
if (dist copy( List pts ) {
List ret = new ArrayList<>();
for( Point2D_F32 p : pts ) {
ret.add( p.copy() );
}
return ret;
}
public static void noiseNormal( List pts, float sigma, Random rand ) {
for( Point2D_F32 p : pts ) {
p.x += (float)rand.nextGaussian() * sigma;
p.y += (float)rand.nextGaussian() * sigma;
}
}
public static Point2D_F32 noiseNormal(Point2D_F32 mean ,
float sigmaX , float sigmaY,
Random rand ,
@Nullable Point2D_F32 output )
{
if( output == null )
output = new Point2D_F32();
output.x = mean.x + (float)rand.nextGaussian()*sigmaX;
output.y = mean.y + (float)rand.nextGaussian()*sigmaY;
return output;
}
public static float distance( float x0, float y0, float x1, float y1 ) {
float dx = x1 - x0;
float dy = y1 - y0;
return (float)Math.sqrt( dx * dx + dy * dy );
}
public static float distanceSq( float x0, float y0, float x1, float y1 ) {
float dx = x1 - x0;
float 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_F32 mean( List list , @Nullable Point2D_F32 mean ) {
if( mean == null )
mean = new Point2D_F32();
float x = 0;
float y = 0;
for( Point2D_F32 p : list ) {
x += p.getX();
y += p.getY();
}
x /= list.size();
y /= list.size();
mean.setTo(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_F32 mean( Point2D_F32[] list , int offset , int length ,
@Nullable Point2D_F32 mean ) {
if( mean == null )
mean = new Point2D_F32();
float x = 0;
float y = 0;
for (int i = 0; i < length; i++) {
Point2D_F32 p = list[offset+i];
x += p.getX();
y += p.getY();
}
x /= length;
y /= length;
mean.setTo(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_F32 mean( Point2D_F32 a , Point2D_F32 b,
@Nullable Point2D_F32 mean ) {
if( mean == null )
mean = new Point2D_F32();
mean.x = (a.x + b.x)/2.0f;
mean.y = (a.y + b.y)/2.0f;
return mean;
}
public static List random( float min, float max, int num, Random rand ) {
List ret = new ArrayList<>();
float d = max - min;
for( int i = 0; i < num; i++ ) {
Point2D_F32 p = new Point2D_F32();
p.x = rand.nextFloat() * d + min;
p.y = rand.nextFloat() * d + min;
ret.add( p );
}
return ret;
}
public static boolean isEquals( GeoTuple2D_F32 a, GeoTuple2D_F32 b, float tol ) {
return ( (float)Math.abs( a.x - b.x ) <= tol && (float)Math.abs( a.y - b.y ) <= tol );
}
/**
* Finds the minimal volume {@link georegression.struct.shapes.RectangleLength2D_F32} which contains all the points.
*
* @param points Input: List of points.
* @param bounding Output: Bounding rectangle
*/
public static RectangleLength2D_F32 bounding(List points,
@Nullable RectangleLength2D_F32 bounding) {
if( bounding == null )
bounding = new RectangleLength2D_F32();
float minX=Float.MAX_VALUE,maxX=-Float.MAX_VALUE;
float minY=Float.MAX_VALUE,maxY=-Float.MAX_VALUE;
for( int i = 0; i < points.size(); i++ ) {
Point2D_F32 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 += (float)Math.max(0,(maxX-(bounding.x0+bounding.width ))*10.0f);
bounding.height += (float)Math.max(0,(maxY-(bounding.y0+bounding.height))*10.0f);
return bounding;
}
/**
* Finds the minimal volume {@link georegression.struct.shapes.RectangleLength2D_F32} which contains all the points.
*
* @param points Input: List of points.
* @param bounding Output: Bounding rectangle
*/
public static Rectangle2D_F32 bounding(List points,
@Nullable Rectangle2D_F32 bounding) {
if( bounding == null )
bounding = new Rectangle2D_F32();
float minX=Float.MAX_VALUE,maxX=-Float.MAX_VALUE;
float minY=Float.MAX_VALUE,maxY=-Float.MAX_VALUE;
for( int i = 0; i < points.size(); i++ ) {
Point2D_F32 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.setTo(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 orderCCW( List points ) {
Point2D_F32 center = mean(points,null);
float[] angles = new float[ points.size() ];
for (int i = 0; i < angles.length; i++) {
Point2D_F32 p = points.get(i);
float dx = p.x - center.x;
float dy = p.y - center.y;
angles[i] = (float)Math.atan2(dy,dx);
}
int[] order = new int[ points.size() ];
QuickSort_F32 sorter = new QuickSort_F32();
sorter.sort(angles,0,points.size(),order);
List out = new ArrayList<>(points.size());
for (int i = 0; i < points.size(); i++) {
out.add(points.get(order[i]));
}
return out;
}
/**
* Computes the mean and covariance matrix from the set of points. This describes a normal distribution
* @param points (Input) points
* @param mean (Output) mean of the points
* @param covariance (Output) 2x2 covariance matrix
*/
public static void computeNormal(List points , Point2D_F32 mean , FMatrix covariance ) {
if( covariance.getNumCols() != 2 || covariance.getNumRows() != 2 ) {
if (covariance instanceof ReshapeMatrix) {
((ReshapeMatrix)covariance).reshape(2,2);
} else {
throw new IllegalArgumentException("Must be a 2x2 matrix");
}
}
mean(points,mean);
float xx=0,xy=0,yy=0;
for (int i = 0; i < points.size(); i++) {
Point2D_F32 p = points.get(i);
float dx = p.x-mean.x;
float dy = p.y-mean.y;
xx += dx*dx;
xy += dx*dy;
yy += dy*dy;
}
xx /= points.size();
xy /= points.size();
yy /= points.size();
covariance.unsafe_set(0,0,xx);
covariance.unsafe_set(0,1,xy);
covariance.unsafe_set(1,0,xy);
covariance.unsafe_set(1,1,yy);
}
/**
* Randomly generates points from the specified normal distribution
* @param mean (Input) mean
* @param covariance (Output) 2x2 covariance matrix
* @param count (Input) Number of points to create
* @param rand (Input) Random number generator
* @param output (Output) Optional storage for points. If null a new list is created
* @return List containing points.
*/
public static List randomNorm( Point2D_F32 mean , FMatrix covariance , int count ,
Random rand ,
@Nullable List output )
{
if( output == null )
output = new ArrayList<>();
// extract values of covariance
float cxx = covariance.get(0,0);
float cxy = covariance.get(0,1);
float cyy = covariance.get(1,1);
// perform cholesky decomposition
float sxx = (float)Math.sqrt(cxx);
float sxy = cxy/cxx;
float syy = (float)Math.sqrt(cyy-sxy*sxy);
for (int i = 0; i < count; i++) {
Point2D_F32 p = new Point2D_F32();
float x = (float)rand.nextGaussian();
float y = (float)rand.nextGaussian();
p.x = mean.x + sxx*x + sxy*y;
p.y = mean.y + sxy*x + syy*y;
output.add(p);
}
return output;
}
}