Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

CTM.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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.area;
  19. import java.awt.Rectangle;
  20. import java.awt.geom.AffineTransform;
  21. import java.awt.geom.Rectangle2D;
  22. import java.io.Serializable;
  23. import org.apache.fop.datatypes.FODimension;
  24. import org.apache.fop.traits.WritingMode;
  25. import static org.apache.fop.fo.Constants.EN_LR_TB;
  26. import static org.apache.fop.fo.Constants.EN_RL_TB;
  27. import static org.apache.fop.fo.Constants.EN_TB_LR;
  28. import static org.apache.fop.fo.Constants.EN_TB_RL;
  29. /**
  30. * Describe a PDF or PostScript style coordinate transformation matrix (CTM).
  31. * The matrix encodes translations, scaling and rotations of the coordinate
  32. * system used to render pages.
  33. */
  34. public class CTM implements Serializable {
  35. private static final long serialVersionUID = -8743287485623778341L;
  36. private double a;
  37. private double b;
  38. private double c;
  39. private double d;
  40. private double e;
  41. private double f;
  42. private static final CTM CTM_LRTB = new CTM(1, 0, 0, 1, 0, 0);
  43. private static final CTM CTM_RLTB = new CTM(1, 0, 0, 1, 0, 0);
  44. private static final CTM CTM_TBRL = new CTM(0, 1, -1, 0, 0, 0);
  45. /**
  46. * Create the identity matrix
  47. */
  48. public CTM() {
  49. a = 1;
  50. b = 0;
  51. c = 0;
  52. d = 1;
  53. e = 0;
  54. f = 0;
  55. }
  56. /**
  57. * Initialize a CTM from the passed arguments.
  58. *
  59. * @param a the x scale
  60. * @param b the x shear
  61. * @param c the y shear
  62. * @param d the y scale
  63. * @param e the x shift
  64. * @param f the y shift
  65. */
  66. public CTM(double a, double b, double c, double d, double e, double f) {
  67. this.a = a;
  68. this.b = b;
  69. this.c = c;
  70. this.d = d;
  71. this.e = e;
  72. this.f = f;
  73. }
  74. /**
  75. * Initialize a CTM to the identity matrix with a translation
  76. * specified by x and y
  77. *
  78. * @param x the x shift
  79. * @param y the y shift.
  80. */
  81. public CTM(double x, double y) {
  82. this.a = 1;
  83. this.b = 0;
  84. this.c = 0;
  85. this.d = 1;
  86. this.e = x;
  87. this.f = y;
  88. }
  89. /**
  90. * Initialize a CTM with the values of another CTM.
  91. *
  92. * @param ctm another CTM
  93. */
  94. protected CTM(CTM ctm) {
  95. this.a = ctm.a;
  96. this.b = ctm.b;
  97. this.c = ctm.c;
  98. this.d = ctm.d;
  99. this.e = ctm.e;
  100. this.f = ctm.f;
  101. }
  102. /**
  103. * Initialize a CTM with the values of an AffineTransform.
  104. *
  105. * @param at the transformation matrix
  106. */
  107. public CTM(AffineTransform at) {
  108. double[] matrix = new double[6];
  109. at.getMatrix(matrix);
  110. this.a = matrix[0];
  111. this.b = matrix[1];
  112. this.c = matrix[2];
  113. this.d = matrix[3];
  114. this.e = matrix[4];
  115. this.f = matrix[5];
  116. }
  117. /**
  118. * Return a CTM which will transform coordinates for a particular writing-mode
  119. * into normalized first quandrant coordinates.
  120. * @param wm A writing mode constant from fo.properties.WritingMode, ie.
  121. * one of LR_TB, RL_TB, TB_RL, TB_LR.
  122. * @param ipd The inline-progression dimension of the reference area whose
  123. * CTM is being set..
  124. * @param bpd The block-progression dimension of the reference area whose
  125. * CTM is being set.
  126. * @return a new CTM with the required transform
  127. */
  128. public static CTM getWMctm(WritingMode wm, int ipd, int bpd) {
  129. CTM wmctm;
  130. switch (wm.getEnumValue()) {
  131. case EN_LR_TB:
  132. return new CTM(CTM_LRTB);
  133. case EN_RL_TB:
  134. return new CTM(CTM_RLTB);
  135. case EN_TB_RL: // CJK
  136. case EN_TB_LR: // CJK
  137. wmctm = new CTM(CTM_TBRL);
  138. wmctm.e = bpd;
  139. return wmctm;
  140. default:
  141. return null;
  142. }
  143. }
  144. /**
  145. * Multiply new passed CTM with this one and generate a new result CTM.
  146. * @param premult The CTM to multiply with this one. The new one will be
  147. * the first multiplicand.
  148. * @return CTM The result of multiplying premult * this.
  149. */
  150. public CTM multiply(CTM premult) {
  151. return new CTM((premult.a * a) + (premult.b * c),
  152. (premult.a * b) + (premult.b * d),
  153. (premult.c * a) + (premult.d * c),
  154. (premult.c * b) + (premult.d * d),
  155. (premult.e * a) + (premult.f * c) + e,
  156. (premult.e * b) + (premult.f * d) + f);
  157. }
  158. /**
  159. * Rotate this CTM by "angle" radians and return a new result CTM.
  160. * This is used to account for reference-orientation.
  161. * @param angle The angle in radians. Positive angles are measured counter-
  162. * clockwise.
  163. * @return CTM The result of rotating this CTM.
  164. */
  165. public CTM rotate(double angle) {
  166. double cos;
  167. double sin;
  168. if (angle == 90.0 || angle == -270.0) {
  169. cos = 0.0;
  170. sin = 1.0;
  171. } else if (angle == 270.0 || angle == -90.0) {
  172. cos = 0.0;
  173. sin = -1.0;
  174. } else if (angle == 180.0 || angle == -180.0) {
  175. cos = -1.0;
  176. sin = 0.0;
  177. } else {
  178. double rad = Math.toRadians(angle);
  179. cos = Math.cos(rad);
  180. sin = Math.sin(rad);
  181. }
  182. CTM rotate = new CTM(cos, -sin, sin, cos, 0, 0);
  183. return multiply(rotate);
  184. }
  185. /**
  186. * Translate this CTM by the passed x and y values and return a new result CTM.
  187. * @param x The amount to translate along the x axis.
  188. * @param y The amount to translate along the y axis.
  189. * @return CTM The result of translating this CTM.
  190. */
  191. public CTM translate(double x, double y) {
  192. CTM translate = new CTM(1, 0, 0, 1, x, y);
  193. return multiply(translate);
  194. }
  195. /**
  196. * Scale this CTM by the passed x and y values and return a new result CTM.
  197. * @param x The amount to scale along the x axis.
  198. * @param y The amount to scale along the y axis.
  199. * @return CTM The result of scaling this CTM.
  200. */
  201. public CTM scale(double x, double y) {
  202. CTM scale = new CTM(x, 0, 0, y, 0, 0);
  203. return multiply(scale);
  204. }
  205. /**
  206. * Transform a rectangle by the CTM to produce a rectangle in the transformed
  207. * coordinate system.
  208. * @param inRect The rectangle in the original coordinate system
  209. * @return Rectangle2D The rectangle in the transformed coordinate system.
  210. */
  211. public Rectangle2D transform(Rectangle2D inRect) {
  212. // Store as 2 sets of 2 points and transform those, then
  213. // recalculate the width and height
  214. int x1t = (int)(inRect.getX() * a + inRect.getY() * c + e);
  215. int y1t = (int)(inRect.getX() * b + inRect.getY() * d + f);
  216. int x2t = (int)((inRect.getX() + inRect.getWidth()) * a
  217. + (inRect.getY() + inRect.getHeight()) * c + e);
  218. int y2t = (int)((inRect.getX() + inRect.getWidth()) * b
  219. + (inRect.getY() + inRect.getHeight()) * d + f);
  220. // Normalize with x1 < x2
  221. if (x1t > x2t) {
  222. int tmp = x2t;
  223. x2t = x1t;
  224. x1t = tmp;
  225. }
  226. if (y1t > y2t) {
  227. int tmp = y2t;
  228. y2t = y1t;
  229. y1t = tmp;
  230. }
  231. return new Rectangle(x1t, y1t, x2t - x1t, y2t - y1t);
  232. }
  233. /**
  234. * Get string for this transform.
  235. *
  236. * @return a string with the transform values
  237. */
  238. @Override
  239. public String toString() {
  240. return "[" + a + " " + b + " " + c + " " + d + " " + e + " "
  241. + f + "]";
  242. }
  243. /**
  244. * Get an array containing the values of this transform.
  245. * This creates and returns a new transform with the values in it.
  246. *
  247. * @return an array containing the transform values
  248. */
  249. public double[] toArray() {
  250. return new double[]{a, b, c, d, e, f};
  251. }
  252. /**
  253. * Returns this CTM as an AffineTransform object.
  254. * @return the AffineTransform representation
  255. */
  256. public AffineTransform toAffineTransform() {
  257. return new AffineTransform(toArray());
  258. }
  259. /**
  260. * Construct a coordinate transformation matrix (CTM).
  261. * @param absRefOrient absolute reference orientation
  262. * @param writingMode the writing mode
  263. * @param absVPrect absolute viewpoint rectangle
  264. * @param reldims relative dimensions
  265. * @return CTM the coordinate transformation matrix (CTM)
  266. */
  267. public static CTM getCTMandRelDims(int absRefOrient,
  268. WritingMode writingMode,
  269. Rectangle2D absVPrect,
  270. FODimension reldims) {
  271. int width;
  272. int height;
  273. // We will use the absolute reference-orientation to set up the CTM.
  274. // The value here is relative to its ancestor reference area.
  275. if (absRefOrient % 180 == 0) {
  276. width = (int) absVPrect.getWidth();
  277. height = (int) absVPrect.getHeight();
  278. } else {
  279. // invert width and height since top left are rotated by 90 (cl or ccl)
  280. height = (int) absVPrect.getWidth();
  281. width = (int) absVPrect.getHeight();
  282. }
  283. /* Set up the CTM for the content of this reference area.
  284. * This will transform region content coordinates in
  285. * writing-mode relative into absolute page-relative
  286. * which will then be translated based on the position of
  287. * the region viewport.
  288. * (Note: scrolling between region vp and ref area when
  289. * doing online content!)
  290. */
  291. CTM ctm = new CTM(absVPrect.getX(), absVPrect.getY());
  292. // First transform for rotation
  293. if (absRefOrient != 0) {
  294. // Rotation implies translation to keep the drawing area in the
  295. // first quadrant. Note: rotation is counter-clockwise
  296. switch (absRefOrient) {
  297. case 90:
  298. case -270:
  299. ctm = ctm.translate(0, width); // width = absVPrect.height
  300. break;
  301. case 180:
  302. case -180:
  303. ctm = ctm.translate(width, height);
  304. break;
  305. case 270:
  306. case -90:
  307. ctm = ctm.translate(height, 0); // height = absVPrect.width
  308. break;
  309. default:
  310. throw new RuntimeException();
  311. }
  312. ctm = ctm.rotate(absRefOrient);
  313. }
  314. /* Since we've already put adjusted width and height values for the
  315. * top and left positions implied by the reference-orientation, we
  316. * can set ipd and bpd appropriately based on the writing mode.
  317. */
  318. switch (writingMode.getEnumValue()) {
  319. case EN_TB_LR:
  320. case EN_TB_RL:
  321. reldims.ipd = height;
  322. reldims.bpd = width;
  323. break;
  324. case EN_LR_TB:
  325. case EN_RL_TB:
  326. default:
  327. reldims.ipd = width;
  328. reldims.bpd = height;
  329. break;
  330. }
  331. // Set a rectangle to be the writing-mode relative version???
  332. // Now transform for writing mode
  333. return ctm.multiply(CTM.getWMctm(writingMode, reldims.ipd, reldims.bpd));
  334. }
  335. }