001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.canvas; 020 021import icy.gui.main.MainFrame; 022import icy.gui.viewer.Viewer; 023import icy.main.Icy; 024import icy.painter.Overlay; 025import icy.sequence.DimensionId; 026import icy.sequence.Sequence; 027 028import java.awt.Component; 029import java.awt.Dimension; 030import java.awt.Graphics; 031import java.awt.Graphics2D; 032import java.awt.Point; 033import java.awt.Rectangle; 034import java.awt.geom.AffineTransform; 035import java.awt.geom.NoninvertibleTransformException; 036import java.awt.geom.Point2D; 037import java.awt.geom.Rectangle2D; 038 039import javax.swing.JComponent; 040 041/** 042 * @author Stephane 043 */ 044public abstract class IcyCanvas2D extends IcyCanvas 045{ 046 /** 047 * 048 */ 049 private static final long serialVersionUID = 743937493919099495L; 050 051 /** mouse position (image coordinate space) */ 052 protected Point2D.Double mouseImagePos; 053 054 // image coordinate to canvas coordinate transform 055 protected final AffineTransform transform; 056 // canvas coordinate to image coordinate transform 057 protected AffineTransform inverseTransform; 058 protected boolean transformChanged; 059 060 public IcyCanvas2D(Viewer viewer) 061 { 062 super(viewer); 063 064 // default for 2D canvas 065 posX = -1; 066 posY = -1; 067 posZ = 0; 068 posT = 0; 069 070 // initial mouse position 071 mouseImagePos = new Point2D.Double(); 072 transform = new AffineTransform(); 073 inverseTransform = new AffineTransform(); 074 transformChanged = false; 075 076 // adjust LUT alpha level for 2D view 077 lut.setAlphaToOpaque(); 078 } 079 080 @Override 081 public void setPositionZ(int z) 082 { 083 // position -1 not supported for Z dimension on this canvas 084 if (z != -1) 085 super.setPositionZ(z); 086 } 087 088 @Override 089 public void setPositionT(int t) 090 { 091 // position -1 not supported for T dimension on this canvas 092 if (t != -1) 093 super.setPositionT(t); 094 } 095 096 @Override 097 public double getMouseImagePosX() 098 { 099 // can be called before constructor ended 100 if (mouseImagePos == null) 101 return 0d; 102 103 return mouseImagePos.x; 104 105 } 106 107 @Override 108 public double getMouseImagePosY() 109 { 110 // can be called before constructor ended 111 if (mouseImagePos == null) 112 return 0d; 113 114 return mouseImagePos.y; 115 } 116 117 /** 118 * Return mouse image position 119 */ 120 public Point2D.Double getMouseImagePos() 121 { 122 return (Point2D.Double) mouseImagePos.clone(); 123 } 124 125 public void setMouseImagePos(double x, double y) 126 { 127 if ((mouseImagePos.x != x) || (mouseImagePos.y != y)) 128 { 129 mouseImagePos.x = x; 130 mouseImagePos.y = y; 131 132 // direct update of mouse canvas position 133 mousePos = imageToCanvas(mouseImagePos); 134 // notify change 135 mouseImagePositionChanged(DimensionId.NULL); 136 } 137 } 138 139 /** 140 * Set mouse image position 141 */ 142 public void setMouseImagePos(Point2D.Double point) 143 { 144 setMouseImagePos(point.x, point.y); 145 } 146 147 @Override 148 public boolean setMousePos(int x, int y) 149 { 150 final boolean result = super.setMousePos(x, y); 151 152 if (result) 153 { 154 if (mouseImagePos == null) 155 mouseImagePos = new Point2D.Double(); 156 157 final Point2D newPos = canvasToImage(mousePos); 158 final double newX = newPos.getX(); 159 final double newY = newPos.getY(); 160 boolean changed = false; 161 162 // need to check against NaN is conversion is not supported 163 if (!Double.isNaN(newX) && (newX != mouseImagePos.x)) 164 { 165 mouseImagePos.x = newX; 166 changed = true; 167 } 168 // need to check against NaN is conversion is not supported 169 if (!Double.isNaN(newY) && (newY != mouseImagePos.y)) 170 { 171 mouseImagePos.y = newY; 172 changed = true; 173 } 174 175 // notify change 176 if (changed) 177 mouseImagePositionChanged(DimensionId.NULL); 178 } 179 180 return result; 181 } 182 183 /** 184 * @deprecated Use {@link #setMousePos(int, int)} instead 185 */ 186 @Deprecated 187 public void setMouseCanvasPos(int x, int y) 188 { 189 setMousePos(x, y); 190 } 191 192 /** 193 * @deprecated Use {@link #setMousePos(Point)} instead. 194 */ 195 @Deprecated 196 public void setMouseCanvasPos(Point point) 197 { 198 setMousePos(point); 199 } 200 201 @Override 202 protected void setMouseImagePosXInternal(double value) 203 { 204 mouseImagePos.x = value; 205 206 // direct update of mouse canvas position 207 mousePos = imageToCanvas(mouseImagePos); 208 209 super.setMouseImagePosXInternal(value); 210 } 211 212 @Override 213 protected void setMouseImagePosYInternal(double value) 214 { 215 mouseImagePos.y = value; 216 217 // direct update of mouse canvas position 218 mousePos = imageToCanvas(mouseImagePos); 219 220 super.setMouseImagePosYInternal(value); 221 } 222 223 /** 224 * Convert specified canvas delta to image delta.<br> 225 */ 226 protected Point2D.Double canvasToImageDelta(int x, int y, double scaleX, double scaleY, double rot) 227 { 228 // get cos and sin 229 final double cos = Math.cos(-rot); 230 final double sin = Math.sin(-rot); 231 232 // apply rotation 233 final double resX = (x * cos) - (y * sin); 234 final double resY = (x * sin) + (y * cos); 235 236 // and scale 237 return new Point2D.Double(resX / scaleX, resY / scaleY); 238 } 239 240 /** 241 * Convert specified canvas delta point to image delta point 242 */ 243 public Point2D.Double canvasToImageDelta(int x, int y) 244 { 245 return canvasToImageDelta(x, y, getScaleX(), getScaleY(), getRotationZ()); 246 } 247 248 /** 249 * Convert specified canvas delta point to image delta point 250 */ 251 public Point2D.Double canvasToImageDelta(Point point) 252 { 253 return canvasToImageDelta(point.x, point.y); 254 } 255 256 /** 257 * Convert specified canvas delta point to image delta point. 258 * The conversion is affected by zoom ratio but with the specified logarithm factor. 259 */ 260 public Point2D.Double canvasToImageLogDelta(int x, int y, double logFactor) 261 { 262 final double sx = getScaleX() / Math.pow(10, Math.log10(getScaleX()) / logFactor); 263 final double sy = getScaleY() / Math.pow(10, Math.log10(getScaleY()) / logFactor); 264 265 return canvasToImageDelta(x, y, sx, sy, getRotationZ()); 266 } 267 268 /** 269 * Convert specified canvas delta point to image delta point. 270 * The conversion is affected by zoom ratio but with the specified logarithm factor. 271 */ 272 public Point2D.Double canvasToImageLogDelta(int x, int y) 273 { 274 return canvasToImageLogDelta(x, y, 5d); 275 } 276 277 /** 278 * Convert specified canvas point to image point.<br> 279 * By default we consider the rotation applied relatively to canvas center.<br> 280 * Override this method if you want different transformation type. 281 */ 282 protected Point2D.Double canvasToImage(int x, int y, int offsetX, int offsetY, double scaleX, double scaleY, 283 double rot) 284 { 285 // get canvas center 286 final double canvasCenterX = getCanvasSizeX() / 2; 287 final double canvasCenterY = getCanvasSizeY() / 2; 288 289 // center to canvas for rotation 290 final double dx = x - canvasCenterX; 291 final double dy = y - canvasCenterY; 292 293 // get cos and sin 294 final double cos = Math.cos(-rot); 295 final double sin = Math.sin(-rot); 296 297 // apply rotation 298 double resX = (dx * cos) - (dy * sin); 299 double resY = (dx * sin) + (dy * cos); 300 301 // translate back to position 302 resX += canvasCenterX; 303 resY += canvasCenterY; 304 305 // basic transform to image coordinates 306 resX = ((resX - offsetX) / scaleX); 307 resY = ((resY - offsetY) / scaleY); 308 309 return new Point2D.Double(resX, resY); 310 } 311 312 /** 313 * Convert specified canvas point to image point 314 */ 315 public Point2D.Double canvasToImage(int x, int y) 316 { 317 final Point2D.Double result = new Point2D.Double(0d, 0d); 318 319 // we can directly use the transform object here 320 getInverseTransform().transform(new Point2D.Double(x, y), result); 321 322 return result; 323 324 // return canvasToImage(x, y, getOffsetX(), getOffsetY(), getScaleX(), getScaleY(), 325 // getRotationZ()); 326 } 327 328 /** 329 * Convert specified canvas point to image point 330 */ 331 public Point2D.Double canvasToImage(Point point) 332 { 333 return canvasToImage(point.x, point.y); 334 } 335 336 /** 337 * Convert specified canvas rectangle to image rectangle 338 */ 339 public Rectangle2D.Double canvasToImage(int x, int y, int w, int h) 340 { 341 // convert each rectangle point 342 final Point2D.Double pt1 = canvasToImage(x, y); 343 final Point2D.Double pt2 = canvasToImage(x + w, y); 344 final Point2D.Double pt3 = canvasToImage(x + w, y + h); 345 final Point2D.Double pt4 = canvasToImage(x, y + h); 346 347 // get minimum and maximum X / Y 348 final double minX = Math.min(pt1.x, Math.min(pt2.x, Math.min(pt3.x, pt4.x))); 349 final double maxX = Math.max(pt1.x, Math.max(pt2.x, Math.max(pt3.x, pt4.x))); 350 final double minY = Math.min(pt1.y, Math.min(pt2.y, Math.min(pt3.y, pt4.y))); 351 final double maxY = Math.max(pt1.y, Math.max(pt2.y, Math.max(pt3.y, pt4.y))); 352 353 // return transformed rectangle 354 return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY); 355 } 356 357 /** 358 * Convert specified canvas rectangle to image rectangle 359 */ 360 public Rectangle2D.Double canvasToImage(Rectangle rect) 361 { 362 return canvasToImage(rect.x, rect.y, rect.width, rect.height); 363 } 364 365 /** 366 * Convert specified image delta to canvas delta.<br> 367 */ 368 protected Point imageToCanvasDelta(double x, double y, double scaleX, double scaleY, double rot) 369 { 370 // apply scale 371 final double dx = x * scaleX; 372 final double dy = y * scaleY; 373 374 // get cos and sin 375 final double cos = Math.cos(rot); 376 final double sin = Math.sin(rot); 377 378 // apply rotation 379 final double resX = (dx * cos) - (dy * sin); 380 final double resY = (dx * sin) + (dy * cos); 381 382 return new Point((int) Math.round(resX), (int) Math.round(resY)); 383 } 384 385 /** 386 * Convert specified image delta point to canvas delta point 387 */ 388 public Point imageToCanvasDelta(double x, double y) 389 { 390 return imageToCanvasDelta(x, y, getScaleX(), getScaleY(), getRotationZ()); 391 } 392 393 /** 394 * Convert specified image delta point to canvas delta point 395 */ 396 public Point imageToCanvasDelta(Point2D.Double point) 397 { 398 return imageToCanvasDelta(point.x, point.y); 399 } 400 401 /** 402 * Convert specified image point to canvas point.<br> 403 * By default we consider the rotation applied relatively to image center.<br> 404 * Override this method if you want different transformation type. 405 */ 406 protected Point imageToCanvas(double x, double y, int offsetX, int offsetY, double scaleX, double scaleY, double rot) 407 { 408 // get canvas center 409 final double canvasCenterX = getCanvasSizeX() / 2; 410 final double canvasCenterY = getCanvasSizeY() / 2; 411 412 // basic transform to canvas coordinates and canvas centering 413 final double dx = ((x * scaleX) + offsetX) - canvasCenterX; 414 final double dy = ((y * scaleY) + offsetY) - canvasCenterY; 415 416 // get cos and sin 417 final double cos = Math.cos(rot); 418 final double sin = Math.sin(rot); 419 420 // apply rotation 421 double resX = (dx * cos) - (dy * sin); 422 double resY = (dx * sin) + (dy * cos); 423 424 // translate back to position 425 resX += canvasCenterX; 426 resY += canvasCenterY; 427 428 return new Point((int) Math.round(resX), (int) Math.round(resY)); 429 } 430 431 /** 432 * Convert specified image point to canvas point 433 */ 434 public Point imageToCanvas(double x, double y) 435 { 436 final Point result = new Point(); 437 438 // we can directly use the transform object here 439 getTransform().transform(new Point2D.Double(x, y), result); 440 441 return result; 442 443 // return imageToCanvas(x, y, getOffsetX(), getOffsetY(), getScaleX(), getScaleY(), 444 // getRotationZ()); 445 } 446 447 /** 448 * Convert specified image point to canvas point 449 */ 450 public Point imageToCanvas(Point2D.Double point) 451 { 452 return imageToCanvas(point.x, point.y); 453 } 454 455 /** 456 * Convert specified image rectangle to canvas rectangle 457 */ 458 public Rectangle imageToCanvas(double x, double y, double w, double h) 459 { 460 // convert each rectangle point 461 final Point pt1 = imageToCanvas(x, y); 462 final Point pt2 = imageToCanvas(x + w, y); 463 final Point pt3 = imageToCanvas(x + w, y + h); 464 final Point pt4 = imageToCanvas(x, y + h); 465 466 // get minimum and maximum X / Y 467 final int minX = Math.min(pt1.x, Math.min(pt2.x, Math.min(pt3.x, pt4.x))); 468 final int maxX = Math.max(pt1.x, Math.max(pt2.x, Math.max(pt3.x, pt4.x))); 469 final int minY = Math.min(pt1.y, Math.min(pt2.y, Math.min(pt3.y, pt4.y))); 470 final int maxY = Math.max(pt1.y, Math.max(pt2.y, Math.max(pt3.y, pt4.y))); 471 472 // return transformed rectangle 473 return new Rectangle(minX, minY, maxX - minX, maxY - minY); 474 } 475 476 /** 477 * Convert specified image rectangle to canvas rectangle 478 */ 479 public Rectangle imageToCanvas(Rectangle2D.Double rect) 480 { 481 return imageToCanvas(rect.x, rect.y, rect.width, rect.height); 482 } 483 484 /** 485 * Get 2D view size in canvas pixel coordinate 486 * 487 * @return a Dimension which represents the visible size. 488 */ 489 public Dimension getCanvasSize() 490 { 491 return new Dimension(getCanvasSizeX(), getCanvasSizeY()); 492 } 493 494 /** 495 * Get 2D image size 496 */ 497 public Dimension getImageSize() 498 { 499 return new Dimension(getImageSizeX(), getImageSizeY()); 500 } 501 502 /** 503 * Get 2D image size in canvas pixel coordinate 504 */ 505 public Dimension getImageCanvasSize() 506 { 507 final double imageSizeX = getImageSizeX(); 508 final double imageSizeY = getImageSizeY(); 509 final double scaleX = getScaleX(); 510 final double scaleY = getScaleY(); 511 final double rot = getRotationZ(); 512 513 // convert image rectangle 514 final Point pt1 = imageToCanvas(0d, 0d, 0, 0, scaleX, scaleY, rot); 515 final Point pt2 = imageToCanvas(imageSizeX, 0d, 0, 0, scaleX, scaleY, rot); 516 final Point pt3 = imageToCanvas(0d, imageSizeY, 0, 0, scaleX, scaleY, rot); 517 final Point pt4 = imageToCanvas(imageSizeX, imageSizeY, 0, 0, scaleX, scaleY, rot); 518 519 final int minX = Math.min(pt1.x, Math.min(pt2.x, Math.min(pt3.x, pt4.x))); 520 final int maxX = Math.max(pt1.x, Math.max(pt2.x, Math.max(pt3.x, pt4.x))); 521 final int minY = Math.min(pt1.y, Math.min(pt2.y, Math.min(pt3.y, pt4.y))); 522 final int maxY = Math.max(pt1.y, Math.max(pt2.y, Math.max(pt3.y, pt4.y))); 523 524 return new Dimension(maxX - minX, maxY - minY); 525 } 526 527 /** 528 * Get 2D canvas visible rectangle (canvas coordinate). 529 */ 530 public Rectangle getCanvasVisibleRect() 531 { 532 // try to return view component visible rectangle by default 533 final Component comp = getViewComponent(); 534 if (comp instanceof JComponent) 535 return ((JComponent) comp).getVisibleRect(); 536 537 // just return the canvas component visible rectangle 538 return getVisibleRect(); 539 } 540 541 /** 542 * Get 2D image visible rectangle (image coordinate).<br> 543 * Prefer the {@link Graphics#getClipBounds()} method for paint operation as the image visible 544 * rectangle may return wrong information sometime (when using the {@link #getRenderedImage(int, int, int, boolean)} 545 * method for instance). 546 */ 547 public Rectangle2D getImageVisibleRect() 548 { 549 return canvasToImage(getCanvasVisibleRect()); 550 } 551 552 /** 553 * Adjust view position and possibly scaling factor to ensure the specified region become visible.<br> 554 * It's up to the Canvas implementation to decide how to make the region visible. 555 * 556 * @param region 557 * the region we want to see 558 */ 559 public void centerOn(Rectangle region) 560 { 561 // override it in Canvas implementation 562 } 563 564 /** 565 * Center image on specified image position in canvas 566 */ 567 public void centerOnImage(double x, double y) 568 { 569 // get point on canvas 570 final Point pt = imageToCanvas(x, y); 571 final int canvasCenterX = getCanvasSizeX() / 2; 572 final int canvasCenterY = getCanvasSizeY() / 2; 573 574 final Point2D.Double newTrans = canvasToImageDelta(canvasCenterX - pt.x, canvasCenterY - pt.y, 1d, 1d, 575 getRotationZ()); 576 577 setOffsetX(getOffsetX() + (int) Math.round(newTrans.x)); 578 setOffsetY(getOffsetY() + (int) Math.round(newTrans.y)); 579 } 580 581 /** 582 * Center image on specified image position in canvas 583 */ 584 public void centerOnImage(Point2D.Double pt) 585 { 586 centerOnImage(pt.x, pt.y); 587 } 588 589 /** 590 * Center image in canvas 591 */ 592 public void centerImage() 593 { 594 centerOnImage(getImageSizeX() / 2, getImageSizeY() / 2); 595 } 596 597 /** 598 * get scale X and scale Y so image fit in canvas view dimension 599 */ 600 protected Point2D.Double getFitImageToCanvasScale() 601 { 602 final double imageSizeX = getImageSizeX(); 603 final double imageSizeY = getImageSizeY(); 604 605 if ((imageSizeX > 0d) && (imageSizeY > 0d)) 606 { 607 final double rot = getRotationZ(); 608 609 // convert image rectangle 610 final Point pt1 = imageToCanvas(0d, 0d, 0, 0, 1d, 1d, rot); 611 final Point pt2 = imageToCanvas(imageSizeX, 0d, 0, 0, 1d, 1d, rot); 612 final Point pt3 = imageToCanvas(0d, imageSizeY, 0, 0, 1d, 1d, rot); 613 final Point pt4 = imageToCanvas(imageSizeX, imageSizeY, 0, 0, 1d, 1d, rot); 614 615 final int minX = Math.min(pt1.x, Math.min(pt2.x, Math.min(pt3.x, pt4.x))); 616 final int maxX = Math.max(pt1.x, Math.max(pt2.x, Math.max(pt3.x, pt4.x))); 617 final int minY = Math.min(pt1.y, Math.min(pt2.y, Math.min(pt3.y, pt4.y))); 618 final int maxY = Math.max(pt1.y, Math.max(pt2.y, Math.max(pt3.y, pt4.y))); 619 620 // get image dimension transformed by rotation 621 final double sx = (double) getCanvasSizeX() / (double) (maxX - minX); 622 final double sy = (double) getCanvasSizeY() / (double) (maxY - minY); 623 624 return new Point2D.Double(sx, sy); 625 } 626 627 return null; 628 } 629 630 /** 631 * Change scale so image fit in canvas view dimension 632 */ 633 public void fitImageToCanvas() 634 { 635 final Point2D.Double s = getFitImageToCanvasScale(); 636 637 if (s != null) 638 { 639 final double scale = Math.min(s.x, s.y); 640 641 setScaleX(scale); 642 setScaleY(scale); 643 } 644 } 645 646 /** 647 * Change canvas size (so viewer size) to get it fit with image dimension if possible 648 */ 649 public void fitCanvasToImage() 650 { 651 final MainFrame mainFrame = Icy.getMainInterface().getMainFrame(); 652 final Dimension imageCanvasSize = getImageCanvasSize(); 653 654 if ((imageCanvasSize.width > 0) && (imageCanvasSize.height > 0) && (mainFrame != null)) 655 { 656 final Dimension maxDim = mainFrame.getDesktopSize(); 657 final Dimension adjImgCnvSize = canvasToViewer(imageCanvasSize); 658 659 // fit in available space --> resize viewer 660 viewer.setSize(Math.min(adjImgCnvSize.width, maxDim.width), Math.min(adjImgCnvSize.height, maxDim.height)); 661 } 662 } 663 664 /** 665 * Convert canvas dimension to viewer dimension 666 */ 667 public Dimension canvasToViewer(Dimension dim) 668 { 669 final Dimension canvasViewSize = getCanvasSize(); 670 final Dimension viewerSize = viewer.getSize(); 671 final Dimension result = new Dimension(dim); 672 673 result.width -= canvasViewSize.width; 674 result.width += viewerSize.width; 675 result.height -= canvasViewSize.height; 676 result.height += viewerSize.height; 677 678 return result; 679 } 680 681 /** 682 * Convert viewer dimension to canvas dimension 683 */ 684 public Dimension viewerToCanvas(Dimension dim) 685 { 686 final Dimension canvasViewSize = getCanvasSize(); 687 final Dimension viewerSize = viewer.getSize(); 688 final Dimension result = new Dimension(dim); 689 690 result.width -= viewerSize.width; 691 result.width += canvasViewSize.width; 692 result.height -= viewerSize.height; 693 result.height += canvasViewSize.height; 694 695 return result; 696 } 697 698 /** 699 * Update internal {@link AffineTransform} object. 700 */ 701 protected void updateTransform() 702 { 703 final int canvasCenterX = getCanvasSizeX() / 2; 704 final int canvasCenterY = getCanvasSizeY() / 2; 705 706 // rotation is centered to canvas 707 transform.setToTranslation(canvasCenterX, canvasCenterY); 708 transform.rotate(getRotationZ()); 709 transform.translate(-canvasCenterX, -canvasCenterY); 710 711 transform.translate(getOffsetX(), getOffsetY()); 712 transform.scale(getScaleX(), getScaleY()); 713 714 transformChanged = true; 715 } 716 717 /** 718 * Return the 2D {@link AffineTransform} object which convert from image coordinate to canvas 719 * coordinate.<br> 720 * {@link Overlay} should directly use the transform information from the {@link Graphics2D} object provided in 721 * their {@link Overlay#paint(Graphics2D, Sequence, IcyCanvas)} method. 722 */ 723 public AffineTransform getTransform() 724 { 725 return transform; 726 } 727 728 /** 729 * Return the 2D {@link AffineTransform} object which convert from canvas coordinate to image 730 * coordinate.<br> 731 * {@link Overlay} should directly use the transform information from the {@link Graphics2D} object provided in 732 * their {@link Overlay#paint(Graphics2D, Sequence, IcyCanvas)} method. 733 */ 734 public AffineTransform getInverseTransform() 735 { 736 if (transformChanged) 737 { 738 try 739 { 740 inverseTransform = transform.createInverse(); 741 } 742 catch (NoninvertibleTransformException e) 743 { 744 inverseTransform = new AffineTransform(); 745 } 746 747 transformChanged = false; 748 } 749 750 return inverseTransform; 751 } 752 753 @Override 754 public void changed(IcyCanvasEvent event) 755 { 756 super.changed(event); 757 758 switch (event.getType()) 759 { 760 case OFFSET_CHANGED: 761 case ROTATION_CHANGED: 762 case SCALE_CHANGED: 763 updateTransform(); 764 break; 765 } 766 } 767}