/*
* JGrass - Free Open Source Java GIS http://www.jgrass.org
* (C) HydroloGIS - www.hydrologis.com
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Library General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
* details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; if not, write to the Free Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.jgrasstools.gears.io.dxfdwg.libs.dwg.utils;
import java.awt.geom.Point2D;
import java.util.Vector;
/**
* This class allows to obtain arcs and circles given by the most usual parameters, in a
* Gis geometry model. In this model, an arc or a circle is given by a set of points that
* defines it shape
*
* @author jmorell
*/
public class GisModelCurveCalculator {
/**
* This method calculates an array of Point2D that represents a circle. The distance
* between it points is 1 angular unit
*
* @param c Point2D that represents the center of the circle
* @param r double value that represents the radius of the circle
* @return Point2D[] An array of Point2D that represents the shape of the circle
*/
public static Point2D[] calculateGisModelCircle(Point2D c, double r) {
Point2D[] pts = new Point2D[360];
int angulo = 0;
for (angulo=0; angulo<360; angulo++) {
pts[angulo] = new Point2D.Double(c.getX(), c.getY());
pts[angulo].setLocation(pts[angulo].getX() + r * Math.sin(angulo*Math.PI/(double)180.0), pts[angulo].getY() + r * Math.cos(angulo*Math.PI/(double)180.0));
}
return pts;
}
/**
* This method calculates an array of Point2D that represents a ellipse. The distance
* between it points is 1 angular unit
*
* @param center Point2D that represents the center of the ellipse
* @param majorAxisVector Point2D that represents the vector for the major axis
* @param axisRatio double value that represents the axis ratio
* @param initAngle double value that represents the start angle of the ellipse arc
* @param endAngle double value that represents the end angle of the ellipse arc
* @return Point2D[] An array of Point2D that represents the shape of the ellipse
*/
public static Point2D[] calculateGisModelEllipse(Point2D center, Point2D majorAxisVector, double axisRatio, double initAngle, double endAngle) {
Point2D majorPoint = new Point2D.Double(center.getX()+majorAxisVector.getX(), center.getY()+majorAxisVector.getY());
double orientation = Math.atan(majorAxisVector.getY()/majorAxisVector.getX());
double semiMajorAxisLength = center.distance(majorPoint);
double semiMinorAxisLength = semiMajorAxisLength*axisRatio;
double eccentricity = Math.sqrt(1-((Math.pow(semiMinorAxisLength, 2))/(Math.pow(semiMajorAxisLength, 2))));
int isa = (int)initAngle;
int iea = (int)endAngle;
double angulo;
Point2D[] pts;
if (initAngle <= endAngle) {
pts = new Point2D[(iea-isa)+2];
angulo = initAngle;
double r = semiMinorAxisLength/Math.sqrt(1-((Math.pow(eccentricity, 2))*(Math.pow(Math.cos(angulo*Math.PI/(double)180.0), 2))));
double x = r*Math.cos(angulo*Math.PI/(double)180.0);
double y = r*Math.sin(angulo*Math.PI/(double)180.0);
double xrot = x*Math.cos(orientation) - y*Math.sin(orientation);
double yrot = x*Math.sin(orientation) + y*Math.cos(orientation);
pts[0] = new Point2D.Double(center.getX() + xrot, center.getY() + yrot);
for (int i=1; i<=(iea-isa)+1; i++) {
angulo = (double)(isa+i);
r = semiMinorAxisLength/Math.sqrt(1-((Math.pow(eccentricity, 2))*(Math.pow(Math.cos(angulo*Math.PI/(double)180.0), 2))));
x = r*Math.cos(angulo*Math.PI/(double)180.0);
y = r*Math.sin(angulo*Math.PI/(double)180.0);
xrot = x*Math.cos(orientation) - y*Math.sin(orientation);
yrot = x*Math.sin(orientation) + y*Math.cos(orientation);
pts[i] = new Point2D.Double(center.getX() + xrot, center.getY() + yrot);
}
angulo = endAngle;
r = semiMinorAxisLength/Math.sqrt(1-((Math.pow(eccentricity, 2))*(Math.pow(Math.cos(angulo*Math.PI/(double)180.0), 2))));
x = r*Math.cos(angulo*Math.PI/(double)180.0);
y = r*Math.sin(angulo*Math.PI/(double)180.0);
xrot = x*Math.cos(orientation) - y*Math.sin(orientation);
yrot = x*Math.sin(orientation) + y*Math.cos(orientation);
pts[(iea-isa)+1] = new Point2D.Double(center.getX() + xrot, center.getY() + yrot);
} else {
pts = new Point2D[(360-isa)+iea+2];
angulo = initAngle;
double r = semiMinorAxisLength/Math.sqrt(1-((Math.pow(eccentricity, 2))*(Math.pow(Math.cos(angulo*Math.PI/(double)180.0), 2))));
double x = r*Math.cos(angulo*Math.PI/(double)180.0);
double y = r*Math.sin(angulo*Math.PI/(double)180.0);
double xrot = x*Math.cos(orientation) - y*Math.sin(orientation);
double yrot = x*Math.sin(orientation) + y*Math.cos(orientation);
pts[0] = new Point2D.Double(center.getX() + r*Math.cos(angulo*Math.PI/(double)180.0), center.getY() + r*Math.sin(angulo*Math.PI/(double)180.0));
for (int i=1; i<=(360-isa); i++) {
angulo = (double)(isa+i);
r = semiMinorAxisLength/Math.sqrt(1-((Math.pow(eccentricity, 2))*(Math.pow(Math.cos(angulo*Math.PI/(double)180.0), 2))));
x = r*Math.cos(angulo*Math.PI/(double)180.0);
y = r*Math.sin(angulo*Math.PI/(double)180.0);
xrot = x*Math.cos(orientation) - y*Math.sin(orientation);
yrot = x*Math.sin(orientation) + y*Math.cos(orientation);
pts[i] = new Point2D.Double(center.getX() + xrot, center.getY() + yrot);
}
for (int i=(360-isa)+1; i<=(360-isa)+iea; i++) {
angulo = (double)(i-(360-isa));
r = semiMinorAxisLength/Math.sqrt(1-((Math.pow(eccentricity, 2))*(Math.pow(Math.cos(angulo*Math.PI/(double)180.0), 2))));
x = r*Math.cos(angulo*Math.PI/(double)180.0);
y = r*Math.sin(angulo*Math.PI/(double)180.0);
xrot = x*Math.cos(orientation) - y*Math.sin(orientation);
yrot = x*Math.sin(orientation) + y*Math.cos(orientation);
pts[i] = new Point2D.Double(center.getX() + xrot, center.getY() + yrot);
}
angulo = endAngle;
r = semiMinorAxisLength/Math.sqrt(1-((Math.pow(eccentricity, 2))*(Math.pow(Math.cos(angulo*Math.PI/(double)180.0), 2))));
x = r*Math.cos(angulo*Math.PI/(double)180.0);
y = r*Math.sin(angulo*Math.PI/(double)180.0);
xrot = x*Math.cos(orientation) - y*Math.sin(orientation);
yrot = x*Math.sin(orientation) + y*Math.cos(orientation);
pts[(360-isa)+iea+1] = new Point2D.Double(center.getX() + xrot, center.getY() + yrot);
}
return pts;
}
/**
* This method calculates an array of Point2D that represents an arc. The distance
* between it points is 1 angular unit
*
* @param c Point2D that represents the center of the arc
* @param r double value that represents the radius of the arc
* @param sa double value that represents the start angle of the arc
* @param ea double value that represents the end angle of the arc
* @return Point2D[] An array of Point2D that represents the shape of the arc
*/
public static Point2D[] calculateGisModelArc(Point2D c, double r, double sa, double ea) {
int isa = (int)sa;
int iea = (int)ea;
double angulo;
Point2D[] pts;
if (sa <= ea) {
pts = new Point2D[(iea-isa)+2];
angulo = sa;
pts[0] = new Point2D.Double(c.getX() + r * Math.cos(angulo*Math.PI/(double)180.0), c.getY() + r * Math.sin(angulo*Math.PI/(double)180.0));
for (int i=1; i<=(iea-isa)+1; i++) {
angulo = (double)(isa+i);
pts[i] = new Point2D.Double(c.getX() + r * Math.cos(angulo*Math.PI/(double)180.0), c.getY() + r * Math.sin(angulo*Math.PI/(double)180.0));
}
angulo = ea;
pts[(iea-isa)+1] = new Point2D.Double(c.getX() + r * Math.cos(angulo*Math.PI/(double)180.0), c.getY() + r * Math.sin(angulo*Math.PI/(double)180.0));
} else {
pts = new Point2D[(360-isa)+iea+2];
angulo = sa;
pts[0] = new Point2D.Double(c.getX() + r * Math.cos(angulo*Math.PI/(double)180.0), c.getY() + r * Math.sin(angulo*Math.PI/(double)180.0));
for (int i=1; i<=(360-isa); i++) {
angulo = (double)(isa+i);
pts[i] = new Point2D.Double(c.getX() + r * Math.cos(angulo*Math.PI/(double)180.0), c.getY() + r * Math.sin(angulo*Math.PI/(double)180.0));
}
for (int i=(360-isa)+1; i<=(360-isa)+iea; i++) {
angulo = (double)(i-(360-isa));
pts[i] = new Point2D.Double(c.getX() + r * Math.cos(angulo*Math.PI/(double)180.0), c.getY() + r * Math.sin(angulo*Math.PI/(double)180.0));
}
angulo = ea;
pts[(360-isa)+iea+1] = new Point2D.Double(c.getX() + r * Math.cos(angulo*Math.PI/(double)180.0), c.getY() + r * Math.sin(angulo*Math.PI/(double)180.0));
}
return pts;
}
/**
* This method applies an array of bulges to an array of Point2D that defines a
* polyline. The result is a polyline with the input points with the addition of the
* points that define the new arcs added to the polyline
*
* @param newPts Base points of the polyline
* @param bulges Array of bulge parameters
* @return Polyline with a new set of arcs added and defined by the bulge parameters
*/
public static Point2D[] calculateGisModelBulge(Point2D[] newPts, double[] bulges) {
Vector ptspol = new Vector();
Point2D init = new Point2D.Double();
Point2D end = new Point2D.Double();
for (int j=0; j<newPts.length; j++) {
init = newPts[j];
if (j!=newPts.length-1) end = newPts[j+1];
if (bulges[j]==0 || j==newPts.length-1 || (init.getX()==end.getX() && init.getY()==end.getY())) {
ptspol.add(init);
} else {
ArcFromBulgeCalculator arcCalculator = new ArcFromBulgeCalculator(init, end, bulges[j]);
Vector arc = arcCalculator.getPoints(1);
if (bulges[j]<0) {
for (int k=arc.size()-1; k>=0; k--) {
ptspol.add(arc.get(k));
}
ptspol.remove(ptspol.size()-1);
} else {
for (int k=0;k<arc.size();k++) {
ptspol.add(arc.get(k));
}
ptspol.remove(ptspol.size()-1);
}
}
}
Point2D[] points = new Point2D[ptspol.size()];
for (int j=0;j<ptspol.size();j++) {
points[j] = (Point2D)ptspol.get(j);
}
return points;
}
}