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