All Downloads are FREE. Search and download functionalities are using the official Maven repository.

georegression.geometry.UtilPoint2D_F32 Maven / Gradle / Ivy

Go to download

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;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy