/* * 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.metric.UtilAngle; import georegression.struct.line.LineGeneral2D_F64; import georegression.struct.line.LineParametric2D_F64; import georegression.struct.line.LinePolar2D_F64; import georegression.struct.line.LineSegment2D_F64; import georegression.struct.point.Point2D_F64; /** * Various functions related to lines * * @author Peter Abeles */ public class UtilLine2D_F64 { /** * Returns the acute angle between the slope of two lines. Lines do not need to ever * intersect. Found using the dot product. * * @param a (input) line * @param b (input) line * @return acute angle in radians */ public static double acuteAngle( LineGeneral2D_F64 a , LineGeneral2D_F64 b ) { double la = Math.sqrt(a.A*a.A + a.B*a.B); double lb = Math.sqrt(b.A*b.A + b.B*b.B); // numerical round off error can cause it to be barely greater than 1, which is outside the allowed // domain of acos() double value = (a.A*b.A + a.B*b.B)/(la*lb); if( value < -1.0 ) value = -1.0; else if( value > 1.0 ) value = 1.0; return Math.acos(value); } /** * Returns the acute angle between the slope of two lines and assumes that the lines have * been normalized such that A*A + B*B = 1. This avoids the need to compute the square root * twice. Lines do not need to ever intersect. Found using the dot product. * * @param a (input) normalized line * @param b (input) normalized line * @return acute angle in radians */ public static double acuteAngleN( LineGeneral2D_F64 a , LineGeneral2D_F64 b ) { double value = a.A*b.A + a.B*b.B; if( value < -1.0 ) value = -1.0; else if( value > 1.0 ) value = 1.0; return Math.acos(value); } /** * Converts a line from polar form to parametric. * * @param src (input) line is polar notation * @param ret (output) line in parametric notation. If null a new instance will be created. * @return Converted line in parametric notation */ public static LineParametric2D_F64 convert( LinePolar2D_F64 src , LineParametric2D_F64 ret ) { if( ret == null ) ret = new LineParametric2D_F64(); double c = (double) Math.cos(src.angle); double s = (double) Math.sin(src.angle); ret.p.set(c*src.distance,s*src.distance); ret.slope.set(-s,c); return ret; } /** * Converts a line from polar form to general. After conversion the line will be normalized, e.g. A*A + B*B == 1. * * @param src (input) line is polar notation * @param ret (output) line in general notation. If null a new instance will be created. * @return Converted line in general notation */ public static LineGeneral2D_F64 convert( LinePolar2D_F64 src , LineGeneral2D_F64 ret ) { if( ret == null ) ret = new LineGeneral2D_F64(); double c = (double) Math.cos(src.angle); double s = (double) Math.sin(src.angle); ret.A = c; ret.B = s; ret.C = -src.distance; return ret; } /** * Converts a line from general to polar. * * @param src (input) line is general notation * @param ret (output) line in polar notation. If null a new instance will be created. * @return Converted line in polar notation */ public static LinePolar2D_F64 convert( LineGeneral2D_F64 src , LinePolar2D_F64 ret ) { if( ret == null ) ret = new LinePolar2D_F64(); double r = Math.sqrt(src.A*src.A + src.B*src.B); double sign = src.C < 0 ? -1 : 1; ret.angle = Math.atan2(-sign*src.B/r,-sign*src.A/r); ret.distance = sign*src.C/r; return ret; } /** * Converts a line segment into a parametric line. The start point will be 'src.a' and the * direction will be in the direction of 'src.b-src.a' * * @param src (input) line segment * @param ret (output) line in parametric notation. If null a new instance will be created. * @return Converted line in parametric notation */ public static LineParametric2D_F64 convert( LineSegment2D_F64 src , LineParametric2D_F64 ret ) { if( ret == null ) ret = new LineParametric2D_F64(); ret.p.set(src.a); ret.slope.set(src.slopeX(),src.slopeY()); return ret; } /** * Converts a line segment into a general line. * * @param src (Input) line segment * @param ret (output) line in general notation. If null a new instance will be created. * @return Line in general notation */ public static LineGeneral2D_F64 convert( LineSegment2D_F64 src , LineGeneral2D_F64 ret ) { return convert(src.a,src.b,ret); } /** * Converts a line segment into a general line. Line segment is defined by two points. * * @param a (Input) End point of line segment * @param b (Input) End point of line segment * @param ret (output) line in general notation. If null a new instance will be created. * @return Line in general notation */ public static LineGeneral2D_F64 convert( Point2D_F64 a , Point2D_F64 b , LineGeneral2D_F64 ret ) { if( ret == null ) ret = new LineGeneral2D_F64(); ret.A = a.y - b.y; ret.B = b.x - a.x; ret.C = -(ret.A*a.x + ret.B*a.y); return ret; } /** * Converts a line from parametric to polar. * * @param src (Input) line in parametric notation * @param ret (output) line in polar notation. If null a new instance will be created. * @return Line in polar notation */ public static LinePolar2D_F64 convert( LineParametric2D_F64 src , LinePolar2D_F64 ret ) { if( ret == null ) ret = new LinePolar2D_F64(); double top = src.slope.y*src.p.x - src.slope.x*src.p.y; ret.distance = top/src.slope.norm(); ret.angle = Math.atan2(-src.slope.x,src.slope.y); if( ret.distance < 0 ) { ret.distance = -ret.distance; ret.angle = UtilAngle.bound(ret.angle + Math.PI); } return ret; } /** * Converts a line from parametric to general * * @param src (input) line in parametric notation. * @param ret (output) line in general notation. If null a new instance will be created. * @return Converted line in general notation */ public static LineGeneral2D_F64 convert( LineParametric2D_F64 src , LineGeneral2D_F64 ret ) { if( ret == null ) { ret = new LineGeneral2D_F64(); } ret.A = -src.slope.y; ret.B = src.slope.x; ret.C = -ret.A*src.p.x - ret.B*src.p.y; return ret; } /** * Converts a line from general to parametric * * @param src (input) line in general notation. * @param ret (output) line in parametric notation. If null a new instance will be created. * @return Converted line in parametric notation */ public static LineParametric2D_F64 convert( LineGeneral2D_F64 src , LineParametric2D_F64 ret ) { if( ret == null ) { ret = new LineParametric2D_F64(); } ret.slope.x = src.B; ret.slope.y = -src.A; // find a point on the line if( Math.abs(src.B) > Math.abs(src.A) ) { ret.p.y = -src.C/src.B; ret.p.x = 0; } else { ret.p.x = -src.C/src.A; ret.p.y = 0; } return ret; } }