#
source:
trunk/third/mozilla/other-licenses/libart_lgpl/art_affine.c
@
22325

Revision 22325, 11.8 KB checked in by rbasch, 19 years ago (diff) |
---|

Line | |
---|---|

1 | /* Libart_LGPL - library of basic graphic primitives |

2 | * Copyright (C) 1998 Raph Levien |

3 | * |

4 | * This library is free software; you can redistribute it and/or |

5 | * modify it under the terms of the GNU Library General Public |

6 | * License as published by the Free Software Foundation; either |

7 | * version 2 of the License, or (at your option) any later version. |

8 | * |

9 | * This library is distributed in the hope that it will be useful, |

10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |

11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |

12 | * Library General Public License for more details. |

13 | * |

14 | * You should have received a copy of the GNU Library General Public |

15 | * License along with this library; if not, write to the |

16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |

17 | * Boston, MA 02111-1307, USA. |

18 | */ |

19 | |

20 | /* Simple manipulations with affine transformations */ |

21 | |

22 | #include "config.h" |

23 | #include "art_affine.h" |

24 | |

25 | #include <math.h> |

26 | #include <stdio.h> /* for sprintf */ |

27 | #include <string.h> /* for strcpy */ |

28 | |

29 | #include "art_misc.h" /* for M_PI */ |

30 | |

31 | /* According to a strict interpretation of the libart structure, this |

32 | routine should go into its own module, art_point_affine. However, |

33 | it's only two lines of code, and it can be argued that it is one of |

34 | the natural basic functions of an affine transformation. |

35 | */ |

36 | |

37 | /** |

38 | * art_affine_point: Do an affine transformation of a point. |

39 | * @dst: Where the result point is stored. |

40 | * @src: The original point. |

41 | @ @affine: The affine transformation. |

42 | **/ |

43 | void |

44 | art_affine_point (ArtPoint *dst, const ArtPoint *src, |

45 | const double affine[6]) |

46 | { |

47 | double x, y; |

48 | |

49 | x = src->x; |

50 | y = src->y; |

51 | dst->x = x * affine[0] + y * affine[2] + affine[4]; |

52 | dst->y = x * affine[1] + y * affine[3] + affine[5]; |

53 | } |

54 | |

55 | /** |

56 | * art_affine_invert: Find the inverse of an affine transformation. |

57 | * @dst: Where the resulting affine is stored. |

58 | * @src: The original affine transformation. |

59 | * |

60 | * All non-degenerate affine transforms are invertible. If the original |

61 | * affine is degenerate or nearly so, expect numerical instability and |

62 | * very likely core dumps on Alpha and other fp-picky architectures. |

63 | * Otherwise, @dst multiplied with @src, or @src multiplied with @dst |

64 | * will be (to within roundoff error) the identity affine. |

65 | **/ |

66 | void |

67 | art_affine_invert (double dst[6], const double src[6]) |

68 | { |

69 | double r_det; |

70 | |

71 | r_det = 1.0 / (src[0] * src[3] - src[1] * src[2]); |

72 | dst[0] = src[3] * r_det; |

73 | dst[1] = -src[1] * r_det; |

74 | dst[2] = -src[2] * r_det; |

75 | dst[3] = src[0] * r_det; |

76 | dst[4] = -src[4] * dst[0] - src[5] * dst[2]; |

77 | dst[5] = -src[4] * dst[1] - src[5] * dst[3]; |

78 | } |

79 | |

80 | /** |

81 | * art_affine_flip: Flip an affine transformation horizontally and/or vertically. |

82 | * @dst_affine: Where the resulting affine is stored. |

83 | * @src_affine: The original affine transformation. |

84 | * @horiz: Whether or not to flip horizontally. |

85 | * @vert: Whether or not to flip horizontally. |

86 | * |

87 | * Flips the affine transform. FALSE for both @horiz and @vert implements |

88 | * a simple copy operation. TRUE for both @horiz and @vert is a |

89 | * 180 degree rotation. It is ok for @src_affine and @dst_affine to |

90 | * be equal pointers. |

91 | **/ |

92 | void |

93 | art_affine_flip (double dst_affine[6], const double src_affine[6], int horz, int vert) |

94 | { |

95 | dst_affine[0] = horz ? - src_affine[0] : src_affine[0]; |

96 | dst_affine[1] = horz ? - src_affine[1] : src_affine[1]; |

97 | dst_affine[2] = vert ? - src_affine[2] : src_affine[2]; |

98 | dst_affine[3] = vert ? - src_affine[3] : src_affine[3]; |

99 | dst_affine[4] = horz ? - src_affine[4] : src_affine[4]; |

100 | dst_affine[5] = vert ? - src_affine[5] : src_affine[5]; |

101 | } |

102 | |

103 | #define EPSILON 1e-6 |

104 | |

105 | /* It's ridiculous I have to write this myself. This is hardcoded to |

106 | six digits of precision, which is good enough for PostScript. |

107 | |

108 | The return value is the number of characters (i.e. strlen (str)). |

109 | It is no more than 12. */ |

110 | static int |

111 | art_ftoa (char str[80], double x) |

112 | { |

113 | char *p = str; |

114 | int i, j; |

115 | |

116 | p = str; |

117 | if (fabs (x) < EPSILON / 2) |

118 | { |

119 | strcpy (str, "0"); |

120 | return 1; |

121 | } |

122 | if (x < 0) |

123 | { |

124 | *p++ = '-'; |

125 | x = -x; |

126 | } |

127 | if ((int)floor ((x + EPSILON / 2) < 1)) |

128 | { |

129 | *p++ = '0'; |

130 | *p++ = '.'; |

131 | i = sprintf (p, "%06d", (int)floor ((x + EPSILON / 2) * 1e6)); |

132 | while (i && p[i - 1] == '0') |

133 | i--; |

134 | if (i == 0) |

135 | i--; |

136 | p += i; |

137 | } |

138 | else if (x < 1e6) |

139 | { |

140 | i = sprintf (p, "%d", (int)floor (x + EPSILON / 2)); |

141 | p += i; |

142 | if (i < 6) |

143 | { |

144 | int ix; |

145 | |

146 | *p++ = '.'; |

147 | x -= floor (x + EPSILON / 2); |

148 | for (j = i; j < 6; j++) |

149 | x *= 10; |

150 | ix = floor (x + 0.5); |

151 | |

152 | for (j = 0; j < i; j++) |

153 | ix *= 10; |

154 | |

155 | /* A cheap hack, this routine can round wrong for fractions |

156 | near one. */ |

157 | if (ix == 1000000) |

158 | ix = 999999; |

159 | |

160 | sprintf (p, "%06d", ix); |

161 | i = 6 - i; |

162 | while (i && p[i - 1] == '0') |

163 | i--; |

164 | if (i == 0) |

165 | i--; |

166 | p += i; |

167 | } |

168 | } |

169 | else |

170 | p += sprintf (p, "%g", x); |

171 | |

172 | *p = '\0'; |

173 | return p - str; |

174 | } |

175 | |

176 | |

177 | |

178 | #include <stdlib.h> |

179 | /** |

180 | * art_affine_to_string: Convert affine transformation to concise PostScript string representation. |

181 | * @str: Where to store the resulting string. |

182 | * @src: The affine transform. |

183 | * |

184 | * Converts an affine transform into a bit of PostScript code that |

185 | * implements the transform. Special cases of scaling, rotation, and |

186 | * translation are detected, and the corresponding PostScript |

187 | * operators used (this greatly aids understanding the output |

188 | * generated). The identity transform is mapped to the null string. |

189 | **/ |

190 | void |

191 | art_affine_to_string (char str[128], const double src[6]) |

192 | { |

193 | char tmp[80]; |

194 | int i, ix; |

195 | |

196 | #if 0 |

197 | for (i = 0; i < 1000; i++) |

198 | { |

199 | double d = rand () * .1 / RAND_MAX; |

200 | art_ftoa (tmp, d); |

201 | printf ("%g %f %s\n", d, d, tmp); |

202 | } |

203 | #endif |

204 | if (fabs (src[4]) < EPSILON && fabs (src[5]) < EPSILON) |

205 | { |

206 | /* could be scale or rotate */ |

207 | if (fabs (src[1]) < EPSILON && fabs (src[2]) < EPSILON) |

208 | { |

209 | /* scale */ |

210 | if (fabs (src[0] - 1) < EPSILON && fabs (src[3] - 1) < EPSILON) |

211 | { |

212 | /* identity transform */ |

213 | str[0] = '\0'; |

214 | return; |

215 | } |

216 | else |

217 | { |

218 | ix = 0; |

219 | ix += art_ftoa (str + ix, src[0]); |

220 | str[ix++] = ' '; |

221 | ix += art_ftoa (str + ix, src[3]); |

222 | strcpy (str + ix, " scale"); |

223 | return; |

224 | } |

225 | } |

226 | else |

227 | { |

228 | /* could be rotate */ |

229 | if (fabs (src[0] - src[3]) < EPSILON && |

230 | fabs (src[1] + src[2]) < EPSILON && |

231 | fabs (src[0] * src[0] + src[1] * src[1] - 1) < 2 * EPSILON) |

232 | { |

233 | double theta; |

234 | |

235 | theta = (180 / M_PI) * atan2 (src[1], src[0]); |

236 | art_ftoa (tmp, theta); |

237 | sprintf (str, "%s rotate", tmp); |

238 | return; |

239 | } |

240 | } |

241 | } |

242 | else |

243 | { |

244 | /* could be translate */ |

245 | if (fabs (src[0] - 1) < EPSILON && fabs (src[1]) < EPSILON && |

246 | fabs (src[2]) < EPSILON && fabs (src[3] - 1) < EPSILON) |

247 | { |

248 | ix = 0; |

249 | ix += art_ftoa (str + ix, src[4]); |

250 | str[ix++] = ' '; |

251 | ix += art_ftoa (str + ix, src[5]); |

252 | strcpy (str + ix, " translate"); |

253 | return; |

254 | } |

255 | } |

256 | |

257 | ix = 0; |

258 | str[ix++] = '['; |

259 | str[ix++] = ' '; |

260 | for (i = 0; i < 6; i++) |

261 | { |

262 | ix += art_ftoa (str + ix, src[i]); |

263 | str[ix++] = ' '; |

264 | } |

265 | strcpy (str + ix, "] concat"); |

266 | } |

267 | |

268 | /** |

269 | * art_affine_multiply: Multiply two affine transformation matrices. |

270 | * @dst: Where to store the result. |

271 | * @src1: The first affine transform to multiply. |

272 | * @src2: The second affine transform to multiply. |

273 | * |

274 | * Multiplies two affine transforms together, i.e. the resulting @dst |

275 | * is equivalent to doing first @src1 then @src2. Note that the |

276 | * PostScript concat operator multiplies on the left, i.e. "M concat" |

277 | * is equivalent to "CTM = multiply (M, CTM)"; |

278 | * |

279 | * It is safe to call this function with @dst equal to @src1 or @src2. |

280 | **/ |

281 | void |

282 | art_affine_multiply (double dst[6], const double src1[6], const double src2[6]) |

283 | { |

284 | double d0, d1, d2, d3, d4, d5; |

285 | |

286 | d0 = src1[0] * src2[0] + src1[1] * src2[2]; |

287 | d1 = src1[0] * src2[1] + src1[1] * src2[3]; |

288 | d2 = src1[2] * src2[0] + src1[3] * src2[2]; |

289 | d3 = src1[2] * src2[1] + src1[3] * src2[3]; |

290 | d4 = src1[4] * src2[0] + src1[5] * src2[2] + src2[4]; |

291 | d5 = src1[4] * src2[1] + src1[5] * src2[3] + src2[5]; |

292 | dst[0] = d0; |

293 | dst[1] = d1; |

294 | dst[2] = d2; |

295 | dst[3] = d3; |

296 | dst[4] = d4; |

297 | dst[5] = d5; |

298 | } |

299 | |

300 | /** |

301 | * art_affine_identity: Set up the identity matrix. |

302 | * @dst: Where to store the resulting affine transform. |

303 | * |

304 | * Sets up an identity matrix. |

305 | **/ |

306 | void |

307 | art_affine_identity (double dst[6]) |

308 | { |

309 | dst[0] = 1; |

310 | dst[1] = 0; |

311 | dst[2] = 0; |

312 | dst[3] = 1; |

313 | dst[4] = 0; |

314 | dst[5] = 0; |

315 | } |

316 | |

317 | |

318 | /** |

319 | * art_affine_scale: Set up a scaling matrix. |

320 | * @dst: Where to store the resulting affine transform. |

321 | * @sx: X scale factor. |

322 | * @sy: Y scale factor. |

323 | * |

324 | * Sets up a scaling matrix. |

325 | **/ |

326 | void |

327 | art_affine_scale (double dst[6], double sx, double sy) |

328 | { |

329 | dst[0] = sx; |

330 | dst[1] = 0; |

331 | dst[2] = 0; |

332 | dst[3] = sy; |

333 | dst[4] = 0; |

334 | dst[5] = 0; |

335 | } |

336 | |

337 | /** |

338 | * art_affine_rotate: Set up a rotation affine transform. |

339 | * @dst: Where to store the resulting affine transform. |

340 | * @theta: Rotation angle in degrees. |

341 | * |

342 | * Sets up a rotation matrix. In the standard libart coordinate |

343 | * system, in which increasing y moves downward, this is a |

344 | * counterclockwise rotation. In the standard PostScript coordinate |

345 | * system, which is reversed in the y direction, it is a clockwise |

346 | * rotation. |

347 | **/ |

348 | void |

349 | art_affine_rotate (double dst[6], double theta) |

350 | { |

351 | double s, c; |

352 | |

353 | s = sin (theta * M_PI / 180.0); |

354 | c = cos (theta * M_PI / 180.0); |

355 | dst[0] = c; |

356 | dst[1] = s; |

357 | dst[2] = -s; |

358 | dst[3] = c; |

359 | dst[4] = 0; |

360 | dst[5] = 0; |

361 | } |

362 | |

363 | /** |

364 | * art_affine_shear: Set up a shearing matrix. |

365 | * @dst: Where to store the resulting affine transform. |

366 | * @theta: Shear angle in degrees. |

367 | * |

368 | * Sets up a shearing matrix. In the standard libart coordinate system |

369 | * and a small value for theta, || becomes \\. Horizontal lines remain |

370 | * unchanged. |

371 | **/ |

372 | void |

373 | art_affine_shear (double dst[6], double theta) |

374 | { |

375 | double t; |

376 | |

377 | t = tan (theta * M_PI / 180.0); |

378 | dst[0] = 1; |

379 | dst[1] = 0; |

380 | dst[2] = t; |

381 | dst[3] = 1; |

382 | dst[4] = 0; |

383 | dst[5] = 0; |

384 | } |

385 | |

386 | /** |

387 | * art_affine_translate: Set up a translation matrix. |

388 | * @dst: Where to store the resulting affine transform. |

389 | * @tx: X translation amount. |

390 | * @tx: Y translation amount. |

391 | * |

392 | * Sets up a translation matrix. |

393 | **/ |

394 | void |

395 | art_affine_translate (double dst[6], double tx, double ty) |

396 | { |

397 | dst[0] = 1; |

398 | dst[1] = 0; |

399 | dst[2] = 0; |

400 | dst[3] = 1; |

401 | dst[4] = tx; |

402 | dst[5] = ty; |

403 | } |

404 | |

405 | /** |

406 | * art_affine_expansion: Find the affine's expansion factor. |

407 | * @src: The affine transformation. |

408 | * |

409 | * Finds the expansion factor, i.e. the square root of the factor |

410 | * by which the affine transform affects area. In an affine transform |

411 | * composed of scaling, rotation, shearing, and translation, returns |

412 | * the amount of scaling. |

413 | * |

414 | * Return value: the expansion factor. |

415 | **/ |

416 | double |

417 | art_affine_expansion (const double src[6]) |

418 | { |

419 | return sqrt (fabs (src[0] * src[3] - src[1] * src[2])); |

420 | } |

421 | |

422 | /** |

423 | * art_affine_rectilinear: Determine whether the affine transformation is rectilinear. |

424 | * @src: The original affine transformation. |

425 | * |

426 | * Determines whether @src is rectilinear, i.e. grid-aligned |

427 | * rectangles are transformed to other grid-aligned rectangles. The |

428 | * implementation has epsilon-tolerance for roundoff errors. |

429 | * |

430 | * Return value: TRUE if @src is rectilinear. |

431 | **/ |

432 | int |

433 | art_affine_rectilinear (const double src[6]) |

434 | { |

435 | return ((fabs (src[1]) < EPSILON && fabs (src[2]) < EPSILON) || |

436 | (fabs (src[0]) < EPSILON && fabs (src[3]) < EPSILON)); |

437 | } |

438 | |

439 | /** |

440 | * art_affine_equal: Determine whether two affine transformations are equal. |

441 | * @matrix1: An affine transformation. |

442 | * @matrix2: Another affine transformation. |

443 | * |

444 | * Determines whether @matrix1 and @matrix2 are equal, with |

445 | * epsilon-tolerance for roundoff errors. |

446 | * |

447 | * Return value: TRUE if @matrix1 and @matrix2 are equal. |

448 | **/ |

449 | int |

450 | art_affine_equal (double matrix1[6], double matrix2[6]) |

451 | { |

452 | return (fabs (matrix1[0] - matrix2[0]) < EPSILON && |

453 | fabs (matrix1[1] - matrix2[1]) < EPSILON && |

454 | fabs (matrix1[2] - matrix2[2]) < EPSILON && |

455 | fabs (matrix1[3] - matrix2[3]) < EPSILON && |

456 | fabs (matrix1[4] - matrix2[4]) < EPSILON && |

457 | fabs (matrix1[5] - matrix2[5]) < EPSILON); |

458 | } |

**Note:**See TracBrowser for help on using the repository browser.