1 /******************************************************************************* 2 * Copyright (c) 2000, 2008 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 * Port to the D programming language: 11 * Frank Benoit <benoit@tionex.de> 12 *******************************************************************************/ 13 module org.eclipse.swt.graphics.Transform; 14 15 import java.lang.all; 16 17 import org.eclipse.swt.SWT; 18 import org.eclipse.swt.internal.Compatibility; 19 import org.eclipse.swt.internal.cairo.Cairo; 20 import org.eclipse.swt.graphics.Resource; 21 import org.eclipse.swt.graphics.Device; 22 23 24 /** 25 * Instances of this class represent transformation matrices for 26 * points expressed as (x, y) pairs of floating point numbers. 27 * <p> 28 * Application code must explicitly invoke the <code>Transform.dispose()</code> 29 * method to release the operating system resources managed by each instance 30 * when those instances are no longer required. 31 * </p> 32 * <p> 33 * This class requires the operating system's advanced graphics subsystem 34 * which may not be available on some platforms. 35 * </p> 36 * 37 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: GraphicsExample</a> 38 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> 39 * 40 * @since 3.1 41 */ 42 public class Transform : Resource { 43 /** 44 * the OS resource for the Transform 45 * (Warning: This field is platform dependent) 46 * <p> 47 * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT 48 * public API. It is marked public only so that it can be shared 49 * within the packages provided by SWT. It is not available on all 50 * platforms and should never be accessed from application code. 51 * </p> 52 */ 53 public double[] handle; 54 55 /** 56 * Constructs a new identity Transform. 57 * <p> 58 * This operation requires the operating system's advanced 59 * graphics subsystem which may not be available on some 60 * platforms. 61 * </p> 62 * 63 * @param device the device on which to allocate the Transform 64 * 65 * @exception IllegalArgumentException <ul> 66 * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> 67 * </ul> 68 * @exception SWTException <ul> 69 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> 70 * </ul> 71 * @exception SWTError <ul> 72 * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained</li> 73 * </ul> 74 * 75 * @see #dispose() 76 */ 77 public this (Device device) { 78 this(device, 1, 0, 0, 1, 0, 0); 79 } 80 81 /** 82 * Constructs a new Transform given an array of elements that represent the 83 * matrix that describes the transformation. 84 * <p> 85 * This operation requires the operating system's advanced 86 * graphics subsystem which may not be available on some 87 * platforms. 88 * </p> 89 * 90 * @param device the device on which to allocate the Transform 91 * @param elements an array of floats that describe the transformation matrix 92 * 93 * @exception IllegalArgumentException <ul> 94 * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device, or the elements array is null</li> 95 * <li>ERROR_INVALID_ARGUMENT - if the elements array is too small to hold the matrix values</li> 96 * </ul> 97 * @exception SWTException <ul> 98 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> 99 * </ul> 100 * @exception SWTError <ul> 101 * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained</li> 102 * </ul> 103 * 104 * @see #dispose() 105 */ 106 public this(Device device, float[] elements) { 107 this (device, checkTransform(elements)[0], elements[1], elements[2], elements[3], elements[4], elements[5]); 108 } 109 110 /** 111 * Constructs a new Transform given all of the elements that represent the 112 * matrix that describes the transformation. 113 * <p> 114 * This operation requires the operating system's advanced 115 * graphics subsystem which may not be available on some 116 * platforms. 117 * </p> 118 * 119 * @param device the device on which to allocate the Transform 120 * @param m11 the first element of the first row of the matrix 121 * @param m12 the second element of the first row of the matrix 122 * @param m21 the first element of the second row of the matrix 123 * @param m22 the second element of the second row of the matrix 124 * @param dx the third element of the first row of the matrix 125 * @param dy the third element of the second row of the matrix 126 * 127 * @exception IllegalArgumentException <ul> 128 * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> 129 * </ul> 130 * @exception SWTException <ul> 131 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> 132 * </ul> 133 * @exception SWTError <ul> 134 * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained</li> 135 * </ul> 136 * 137 * @see #dispose() 138 */ 139 public this (Device device, float m11, float m12, float m21, float m22, float dx, float dy) { 140 super(device); 141 this.device.checkCairo(); 142 handle = new double[6]; 143 if (handle is null) SWT.error(SWT.ERROR_NO_HANDLES); 144 Cairo.cairo_matrix_init( cast(cairo_matrix_t*)handle.ptr, m11, m12, m21, m22, dx, dy); 145 init_(); 146 } 147 148 static float[] checkTransform(float[] elements) { 149 if (elements is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 150 if (elements.length < 6) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 151 return elements; 152 } 153 154 override 155 void destroy() { 156 handle = null; 157 } 158 159 /** 160 * Fills the parameter with the values of the transformation matrix 161 * that the receiver represents, in the order {m11, m12, m21, m22, dx, dy}. 162 * 163 * @param elements array to hold the matrix values 164 * 165 * @exception SWTException <ul> 166 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 167 * </ul> 168 * @exception IllegalArgumentException <ul> 169 * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> 170 * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the matrix values</li> 171 * </ul> 172 */ 173 public void getElements(float[] elements) { 174 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 175 if (elements is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 176 if (elements.length < 6) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 177 elements[0] = cast(float)handle[0]; 178 elements[1] = cast(float)handle[1]; 179 elements[2] = cast(float)handle[2]; 180 elements[3] = cast(float)handle[3]; 181 elements[4] = cast(float)handle[4]; 182 elements[5] = cast(float)handle[5]; 183 } 184 185 /** 186 * Modifies the receiver such that the matrix it represents becomes the 187 * identity matrix. 188 * 189 * @exception SWTException <ul> 190 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 191 * </ul> 192 * 193 * @since 3.4 194 */ 195 public void identity() { 196 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 197 Cairo.cairo_matrix_init(cast(cairo_matrix_t*)handle.ptr, 1, 0, 0, 1, 0, 0); 198 } 199 200 /** 201 * Modifies the receiver such that the matrix it represents becomes 202 * the mathematical inverse of the matrix it previously represented. 203 * 204 * @exception SWTException <ul> 205 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 206 * <li>ERROR_CANNOT_INVERT_MATRIX - if the matrix is not invertible</li> 207 * </ul> 208 */ 209 public void invert() { 210 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 211 if (Cairo.cairo_matrix_invert(cast(cairo_matrix_t*)handle.ptr) !is 0) { 212 SWT.error(SWT.ERROR_CANNOT_INVERT_MATRIX); 213 } 214 } 215 216 /** 217 * Returns <code>true</code> if the Transform has been disposed, 218 * and <code>false</code> otherwise. 219 * <p> 220 * This method gets the dispose state for the Transform. 221 * When a Transform has been disposed, it is an error to 222 * invoke any other method using the Transform. 223 * 224 * @return <code>true</code> when the Transform is disposed, and <code>false</code> otherwise 225 */ 226 public override bool isDisposed() { 227 return handle is null; 228 } 229 230 /** 231 * Returns <code>true</code> if the Transform represents the identity matrix 232 * and false otherwise. 233 * 234 * @return <code>true</code> if the receiver is an identity Transform, and <code>false</code> otherwise 235 */ 236 public bool isIdentity() { 237 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 238 float[] m = new float[6]; 239 getElements(m); 240 return m[0] is 1 && m[1] is 0 && m[2] is 0 && m[3] is 1 && m[4] is 0 && m[5] is 0; 241 } 242 243 /** 244 * Modifies the receiver such that the matrix it represents becomes the 245 * the result of multiplying the matrix it previously represented by the 246 * argument. 247 * 248 * @param matrix the matrix to multiply the receiver by 249 * 250 * @exception SWTException <ul> 251 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 252 * </ul> 253 * @exception IllegalArgumentException <ul> 254 * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> 255 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> 256 * </ul> 257 */ 258 public void multiply(Transform matrix) { 259 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 260 if (matrix is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 261 if (matrix.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 262 Cairo.cairo_matrix_multiply(cast(cairo_matrix_t*)handle.ptr,cast(cairo_matrix_t*)matrix.handle.ptr, cast(cairo_matrix_t*)handle.ptr); 263 } 264 265 /** 266 * Modifies the receiver so that it represents a transformation that is 267 * equivalent to its previous transformation rotated by the specified angle. 268 * The angle is specified in degrees and for the identity transform 0 degrees 269 * is at the 3 o'clock position. A positive value indicates a clockwise rotation 270 * while a negative value indicates a counter-clockwise rotation. 271 * 272 * @param angle the angle to rotate the transformation by 273 * 274 * @exception SWTException <ul> 275 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 276 * </ul> 277 */ 278 public void rotate(float angle) { 279 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 280 Cairo.cairo_matrix_rotate(cast(cairo_matrix_t*)handle.ptr, angle * cast(float)Compatibility.PI / 180); 281 } 282 283 /** 284 * Modifies the receiver so that it represents a transformation that is 285 * equivalent to its previous transformation scaled by (scaleX, scaleY). 286 * 287 * @param scaleX the amount to scale in the X direction 288 * @param scaleY the amount to scale in the Y direction 289 * 290 * @exception SWTException <ul> 291 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 292 * </ul> 293 */ 294 public void scale(float scaleX, float scaleY) { 295 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 296 Cairo.cairo_matrix_scale(cast(cairo_matrix_t*)handle.ptr, scaleX, scaleY); 297 } 298 299 /** 300 * Modifies the receiver to represent a new transformation given all of 301 * the elements that represent the matrix that describes that transformation. 302 * 303 * @param m11 the first element of the first row of the matrix 304 * @param m12 the second element of the first row of the matrix 305 * @param m21 the first element of the second row of the matrix 306 * @param m22 the second element of the second row of the matrix 307 * @param dx the third element of the first row of the matrix 308 * @param dy the third element of the second row of the matrix 309 * 310 * @exception SWTException <ul> 311 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 312 * </ul> 313 */ 314 public void setElements(float m11, float m12, float m21, float m22, float dx, float dy) { 315 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 316 Cairo.cairo_matrix_init(cast(cairo_matrix_t*)handle.ptr, m11, m12, m21, m22, dx, dy); 317 } 318 319 /** 320 * Modifies the receiver so that it represents a transformation that is 321 * equivalent to its previous transformation sheared by (shearX, shearY). 322 * 323 * @param shearX the shear factor in the X direction 324 * @param shearY the shear factor in the Y direction 325 * 326 * @exception SWTException <ul> 327 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 328 * </ul> 329 * 330 * @since 3.4 331 */ 332 public void shear(float shearX, float shearY) { 333 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 334 double[] matrix = [ 1.0, shearX, shearY, 1, 0, 0]; 335 Cairo.cairo_matrix_multiply(cast(cairo_matrix_t*)handle.ptr, cast(cairo_matrix_t*)matrix.ptr, cast(cairo_matrix_t*)handle.ptr); 336 } 337 338 /** 339 * Given an array containing points described by alternating x and y values, 340 * modify that array such that each point has been replaced with the result of 341 * applying the transformation represented by the receiver to that point. 342 * 343 * @param pointArray an array of alternating x and y values to be transformed 344 * 345 * @exception IllegalArgumentException <ul> 346 * <li>ERROR_NULL_ARGUMENT - if the point array is null</li> 347 * </ul> 348 * @exception SWTException <ul> 349 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 350 * </ul> 351 */ 352 public void transform(float[] pointArray) { 353 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 354 if (pointArray is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 355 double dx = 0, dy = 0; 356 auto length = pointArray.length / 2; 357 for (int i = 0, j = 0; i < length; i++, j += 2) { 358 dx = pointArray[j]; 359 dy = pointArray[j + 1]; 360 Cairo.cairo_matrix_transform_point(cast(cairo_matrix_t*)handle.ptr, &dx, &dy); 361 pointArray[j] = cast(float)dx; 362 pointArray[j + 1] = cast(float)dy; 363 } 364 } 365 366 /** 367 * Modifies the receiver so that it represents a transformation that is 368 * equivalent to its previous transformation translated by (offsetX, offsetY). 369 * 370 * @param offsetX the distance to translate in the X direction 371 * @param offsetY the distance to translate in the Y direction 372 * 373 * @exception SWTException <ul> 374 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> 375 * </ul> 376 */ 377 public void translate(float offsetX, float offsetY) { 378 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 379 Cairo.cairo_matrix_translate(cast(cairo_matrix_t*)handle.ptr, offsetX, offsetY); 380 } 381 382 /** 383 * Returns a string containing a concise, human-readable 384 * description of the receiver. 385 * 386 * @return a string representation of the receiver 387 */ 388 public override String toString() { 389 if (isDisposed()) return "Transform {*DISPOSED*}"; 390 float[] elements = new float[6]; 391 getElements(elements); 392 return Format( "Transform {{{}}", elements ); 393 } 394 395 }