You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ArcToBezierCurveTransformer.java 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.render.intermediate;
  19. import java.io.IOException;
  20. public class ArcToBezierCurveTransformer {
  21. private final BezierCurvePainter bezierCurvePainter;
  22. public ArcToBezierCurveTransformer(BezierCurvePainter bezierCurvePainter) {
  23. this.bezierCurvePainter = bezierCurvePainter;
  24. }
  25. /**
  26. * Draws an arc on the ellipse centered at (cx, cy) with width width and height height
  27. * from start angle startAngle (with respect to the x-axis counter-clockwise)
  28. * to the end angle endAngle.
  29. * The ellipses major axis are assumed to coincide with the coordinate axis.
  30. * The current position MUST coincide with the starting position on the ellipse.
  31. * @param startAngle the start angle
  32. * @param endAngle the end angle
  33. * @param cx the x coordinate of the ellipse center
  34. * @param cy the y coordinate of the ellipse center
  35. * @param width the extent of the ellipse in the x direction
  36. * @param height the extent of the ellipse in the y direction
  37. * @throws IOException if an I/O error occurs
  38. */
  39. public void arcTo(final double startAngle, final double endAngle, final int cx, final int cy,
  40. final int width, final int height) throws IOException {
  41. // Implementation follows http://www.spaceroots.org/documents/ellipse/ -
  42. // Drawing an elliptical arc using polylines, quadratic or cubic Bézier curves
  43. // L. Maisonobe, July 21, 2003
  44. // Scaling the coordinate system to represent the ellipse as a circle:
  45. final double etaStart = Math.atan(Math.tan(startAngle) * width / height)
  46. + quadrant(startAngle);
  47. final double etaEnd = Math.atan(Math.tan(endAngle) * width / height)
  48. + quadrant(endAngle);
  49. final double sinStart = Math.sin(etaStart);
  50. final double cosStart = Math.cos(etaStart);
  51. final double sinEnd = Math.sin(etaEnd);
  52. final double cosEnd = Math.cos(etaEnd);
  53. final double p0x = cx + cosStart * width;
  54. final double p0y = cy + sinStart * height;
  55. final double p3x = cx + cosEnd * width;
  56. final double p3y = cy + sinEnd * height;
  57. double etaDiff = Math.abs(etaEnd - etaStart);
  58. double tan = Math.tan((etaDiff) / 2d);
  59. final double alpha = Math.sin(etaDiff) * (Math.sqrt(4d + 3d * tan * tan) - 1d) / 3d;
  60. int order = etaEnd > etaStart ? 1 : -1;
  61. // p1 = p0 + alpha*(-sin(startAngle), cos(startAngle))
  62. final double p1x = p0x - alpha * sinStart * width * order;
  63. final double p1y = p0y + alpha * cosStart * height * order;
  64. // p1 = p3 + alpha*(sin(endAngle), -cos(endAngle))
  65. final double p2x = p3x + alpha * sinEnd * width * order;
  66. final double p2y = p3y - alpha * cosEnd * height * order;
  67. //Draw the curve in original coordinate system
  68. bezierCurvePainter.cubicBezierTo((int) p1x, (int) p1y, (int) p2x, (int) p2y, (int) p3x, (int) p3y);
  69. }
  70. private double quadrant(double angle) {
  71. if (angle <= Math.PI) {
  72. if (angle <= Math.PI / 2d) {
  73. return 0;
  74. } else {
  75. return Math.PI;
  76. }
  77. } else {
  78. if (angle > Math.PI * 3d / 2d) {
  79. return 2d * Math.PI;
  80. } else {
  81. return Math.PI;
  82. }
  83. }
  84. }
  85. }