blob: 112808f62c42d43fa1af4110b1f3f83fe399bc6c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/* $Id$ */
package org.apache.fop.render.intermediate;
import java.io.IOException;
public class ArcToBezierCurveTransformer {
private final BezierCurvePainter bezierCurvePainter;
public ArcToBezierCurveTransformer(BezierCurvePainter bezierCurvePainter) {
this.bezierCurvePainter = bezierCurvePainter;
}
/**
* Draws an arc on the ellipse centered at (cx, cy) with width width and height height
* from start angle startAngle (with respect to the x-axis counter-clockwise)
* to the end angle endAngle.
* The ellipses major axis are assumed to coincide with the coordinate axis.
* The current position MUST coincide with the starting position on the ellipse.
* @param startAngle the start angle
* @param endAngle the end angle
* @param cx the x coordinate of the ellipse center
* @param cy the y coordinate of the ellipse center
* @param width the extent of the ellipse in the x direction
* @param height the extent of the ellipse in the y direction
* @throws IOException if an I/O error occurs
*/
public void arcTo(final double startAngle, final double endAngle, final int cx, final int cy,
final int width, final int height) throws IOException {
// Implementation follows http://www.spaceroots.org/documents/ellipse/ -
// Drawing an elliptical arc using polylines, quadratic or cubic Bézier curves
// L. Maisonobe, July 21, 2003
// Scaling the coordinate system to represent the ellipse as a circle:
final double etaStart = Math.atan(Math.tan(startAngle) * width / height)
+ quadrant(startAngle);
final double etaEnd = Math.atan(Math.tan(endAngle) * width / height)
+ quadrant(endAngle);
final double sinStart = Math.sin(etaStart);
final double cosStart = Math.cos(etaStart);
final double sinEnd = Math.sin(etaEnd);
final double cosEnd = Math.cos(etaEnd);
final double p0x = cx + cosStart * width;
final double p0y = cy + sinStart * height;
final double p3x = cx + cosEnd * width;
final double p3y = cy + sinEnd * height;
double etaDiff = Math.abs(etaEnd - etaStart);
double tan = Math.tan((etaDiff) / 2d);
final double alpha = Math.sin(etaDiff) * (Math.sqrt(4d + 3d * tan * tan) - 1d) / 3d;
int order = etaEnd > etaStart ? 1 : -1;
// p1 = p0 + alpha*(-sin(startAngle), cos(startAngle))
final double p1x = p0x - alpha * sinStart * width * order;
final double p1y = p0y + alpha * cosStart * height * order;
// p1 = p3 + alpha*(sin(endAngle), -cos(endAngle))
final double p2x = p3x + alpha * sinEnd * width * order;
final double p2y = p3y - alpha * cosEnd * height * order;
//Draw the curve in original coordinate system
bezierCurvePainter.cubicBezierTo((int) p1x, (int) p1y, (int) p2x, (int) p2y, (int) p3x, (int) p3y);
}
private double quadrant(double angle) {
if (angle <= Math.PI) {
if (angle <= Math.PI / 2d) {
return 0;
} else {
return Math.PI;
}
} else {
if (angle > Math.PI * 3d / 2d) {
return 2d * Math.PI;
} else {
return Math.PI;
}
}
}
}