/*! Copyright (C) 2009 Apertus, All Rights Reserved *! Author : Apertus Team *! Description: -----------------------------------------------------------------------------** *! *! This program is free software: you can redistribute it and/or modify *! it under the terms of the GNU General Public License as published by *! the Free Software Foundation, either version 3 of the License, or *! (at your option) any later version. *! *! This program 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 General Public License for more details. *! *! You should have received a copy of the GNU General Public License *! along with this program. If not, see <http://www.gnu.org/licenses/>. *! -----------------------------------------------------------------------------**/ import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.GeneralPath; public class Bezier { private Point[] controlPoints; private Point[] curvePoints; public Bezier(int order, int segments) { controlPoints = new Point[order + 1]; for (int i = 0; i < controlPoints.length; i++) { controlPoints[i] = new Point(0, 0); } curvePoints = new Point[segments + 1]; for (int i = 0; i < curvePoints.length; i++) { curvePoints[i] = new Point(0, 0); } } public void SetControlPoints(double X1, double Y1, double X2, double Y2, double X3, double Y3, double X4, double Y4) { controlPoints[0].setXY(X1, Y1); controlPoints[1].setXY(X2, Y2); controlPoints[2].setXY(X3, Y3); controlPoints[3].setXY(X4, Y4); } public int[] GetGammaTable() { int[] return_value = new int[255]; for (int i = 0; i < 255; i++) { return_value[i] = (int)(256 - curvePoints[i].y); } return return_value; } public Point ClosestControlPoint(Point p) { double temp; double distance = p.dist(controlPoints[0]); Point closest = controlPoints[0]; for (int i = 1; i < controlPoints.length; i++) { temp = p.dist(controlPoints[i]); if (distance > temp) { distance = temp; closest = controlPoints[i]; } } return closest; } private void SubDivide(Point p1, Point p2, double t) { if (p1.x > p2.x) { p1.x -= Math.abs(p1.x - p2.x) * t; } else { p1.x += Math.abs(p1.x - p2.x) * t; } if (p1.y > p2.y) { p1.y -= Math.abs(p1.y - p2.y) * t; } else { p1.y += Math.abs(p1.y - p2.y) * t; } } public void Compute() { Point[] tmp = new Point[controlPoints.length]; for (int i = 0; i < tmp.length; i++) { tmp[i] = new Point(0, 0); } for (int i = 0; i < curvePoints.length; i++) { double t = ((double) i) / (curvePoints.length - 1); for (int j = 0; j < controlPoints.length; j++) { tmp[j].setXY(controlPoints[j].x, controlPoints[j].y); } int Depth = tmp.length; while (Depth > 1) { for (int j = 0; j < Depth - 1; j++) { SubDivide(tmp[j], tmp[j + 1], t); } Depth--; } System.out.println(); curvePoints[i].setXY(tmp[0].x, tmp[0].y); } } private boolean AllPointsAreOnLeft(Point a, Point b) { /* * Area of the triangle ABC * 1 |a1 b1 c1| 1 * -*|a2 b2 c2| = -*(a1b2 + b1c2 + c1a2 - a1c2 - b1a2 - c1b2) * 2 |1 1 1 | 2 * * If the area is positive, then C is to the left of AB. If it is * negative, C is to the right of AB. If it is 0, A B and C are * collinear. */ for (int i = 0; i < controlPoints.length; i++) { if ((controlPoints[i] == a) || (controlPoints[i] == b)) { continue; } if ((a.x * (-b.y) + b.x * (-controlPoints[i].y) + controlPoints[i].x * (-a.y) - a.x * (-controlPoints[i].y) - b.x * (-a.y) - controlPoints[i].x * (-b.y)) <= 0) { return false; } } return true; } public void Draw(Graphics2D g2d) { // Convex hull g2d.setColor(Color.LIGHT_GRAY); Point minX = controlPoints[0]; for (int i = 1; i < controlPoints.length; i++) { minX = minX.x > controlPoints[i].x ? controlPoints[i] : minX; } GeneralPath path = new GeneralPath(); path.moveTo(minX.x, minX.y); Point current = minX; for (int i = 0; i < controlPoints.length; i++) { if (controlPoints[i] != minX) { if (AllPointsAreOnLeft(minX, controlPoints[i])) { current = controlPoints[i]; } } } path.lineTo(current.x, current.y); while (current != minX) { for (int i = 0; i < controlPoints.length; i++) { if (controlPoints[i] != current) { if (AllPointsAreOnLeft(current, controlPoints[i])) { current = controlPoints[i]; break; } } } path.lineTo(current.x, current.y); } /*g2d.draw(path); // Connected control points g2d.setColor(Color.BLACK); for (int i = 0; i < controlPoints.length - 1; i++) { g2d.drawLine( (int) controlPoints[i].x, (int) controlPoints[i].y, (int) controlPoints[i + 1].x, (int) controlPoints[i + 1].y); }*/ // Bezier curve g2d.setColor(Color.RED); path = new GeneralPath(); path.moveTo(curvePoints[0].x, curvePoints[0].y); for (int i = 1; i < curvePoints.length; i++) { path.lineTo(curvePoints[i].x, curvePoints[i].y); } g2d.draw(path); } }