2009-03-27 20 views
6

J'essaye de mettre à l'échelle un rectangle depuis son centre en utilisant AffineTransform. Je suis sûr que la solution est évidente mais je ne peux pas le faire fonctionner! Voici ce que j'ai testé jusqu'à présent ...AffineTransform: mise à l'échelle d'une forme à partir de son centre

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.awt.geom.AffineTransform; 

import javax.swing.JOptionPane; 
import javax.swing.JPanel; 

public class Test extends JPanel { 
    Test() 
     { 
     super(null); 
     setOpaque(true); 
     setBackground(Color.WHITE); 
     setPreferredSize(new Dimension(200,200)); 
     } 
    @Override 
    protected void paintComponent(Graphics g1) { 
     super.paintComponent(g1); 
     Rectangle r= new Rectangle(5,5,getWidth()-10,getHeight()-10); 
     double cx= r.getCenterX(); 
     double cy= r.getCenterY(); 
     Graphics2D g=(Graphics2D)g1; 
     g.setColor(Color.BLACK); 
     AffineTransform old= g.getTransform(); 
     for(double zoom=0.9; zoom>=0.5; zoom-=0.1) 
      { 
      AffineTransform tr2= new AffineTransform(old); 
      tr2.translate(-cx, -cy); 
      tr2.scale(zoom, zoom); 
      tr2.translate(cx/zoom,cy/zoom); 
      g.setTransform(tr2); 
      g.draw(r); 
      g.setTransform(old); 
      } 
     } 


    public static void main(String[] args) { 
     JOptionPane.showMessageDialog(null, new Test()); 
     } 
    } 

Mais cela ne fonctionne pas .... Une suggestion?

+0

Je suppose que vous essayez de suivre des rectangles concentriques/interne? – basszero

Répondre

5

Je vois ce que vous voulez dire quand vous avez affaire à des rectangles. La raison en est que le calcul initial de la traduction n'a pas pris en compte la taille de l'objet conteneur.

Utilisez ce lieu:

tr2.translate(
    (this.getWidth()/2) - (r.getWidth()*(zoom))/2, 
    (this.getHeight()/2) - (r.getHeight()*(zoom))/2 
); 
tr2.scale(zoom,zoom); 
g.setTransform(tr2); 

Ce que cela fait est la traduction du rectangle au centre du panneau avant redimensionnant. Dans mes tests cela fonctionne très bien.

5

En supposant que la mise à l'échelle corrige l'emplacement du coin supérieur gauche du rectangle (ce qui est correct, mais cela fait longtemps que je n'ai pas fait de graphiques en Java), vous devez translater le rectangle dans le sens opposé la mise à l'échelle.

tr2.translate(
    r.getWidth()*(1-zoom)/2, 
    r.getHeight()*(1-zoom)/2 
); 
tr2.scale(zoom,zoom); 
g.setTransform(tr2); 

Vous déplacez donc le rectangle vers la gauche et vers le haut la moitié du changement de largeur et de hauteur.

+0

Ne semble pas fonctionner. –

+0

votre solution ne fonctionne pas mais elle me donne quelques nouvelles idées, merci – Pierre

+0

@mmyers: quel est le résultat que vous obtenez? Je n'ai pas accès à un IDE Java au travail, donc je ne peux pas le tester moi-même. Je travaille en grande partie de la mémoire. – Welbog

0

Cela implique un processus appelé conjuguer une transformation.

Si S est la mise à l'échelle que vous voulez faire, et T est la transformation qui prend point (0,0) au point qui doit être le centre de votre mise à l'échelle, puis la transformation qui fait le travail est

T (S (inverse (T)))

0

(Plus tard) Voici une solution fonctionnant sans aucune connaissance préalable de la Dimension du panneau.

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Shape; 
import java.awt.geom.AffineTransform; 
import java.awt.geom.Ellipse2D; 

import javax.swing.JOptionPane; 
import javax.swing.JPanel; 

public class Test extends JPanel 
    { 
    private static final long serialVersionUID = 1L; 
    private Test() 
     { 
     super(null); 
     setOpaque(true); 
     setBackground(Color.WHITE); 
     setPreferredSize(new Dimension(600,600)); 
     } 

    @Override 
    protected void paintComponent(Graphics g1) { 
     super.paintComponent(g1); 
     Shape r= new Ellipse2D.Double(5,380,400,200); 
     double cx= r.getBounds2D().getCenterX(); 
     double cy= r.getBounds2D().getCenterY(); 
     Graphics2D g=(Graphics2D)g1; 
     g.setColor(Color.BLACK); 
     AffineTransform old= g.getTransform(); 
     g.drawLine((int)cx-10, (int)cy, (int)cx+10, (int)cy); 
     g.drawLine((int)cx, (int)cy-10, (int)cx, (int)cy+10); 
     for(double zoom=1; zoom>=0.1; zoom-=0.1) 
       { 


       AffineTransform tr2 =AffineTransform.getTranslateInstance(-cx, -cy); 
       AffineTransform tr= AffineTransform.getScaleInstance(zoom,zoom); 
       tr.concatenate(tr2); tr2=tr; 
       tr =AffineTransform.getTranslateInstance(cx, cy); 
       tr.concatenate(tr2); tr2=tr; 

       tr= new AffineTransform(old); 
       tr.concatenate(tr2); tr2=tr; 

       g.setTransform(tr2); 



       g.draw(r); 
       g.setTransform(old); 
       } 
     } 


    public static void main(String[] args) { 
     JOptionPane.showMessageDialog(null, new Test()); 
     } 
    } 
0

Je viens de travailler sur une application de bureau pour rogner le visage de Brittney Spear (JOUR) Le rectangle de recadrage avait à l'échelle autour de son point central:

import javafx.scene.Cursor; 
import javafx.scene.Group; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.input.ScrollEvent; 
import javafx.scene.paint.Color; 
import javafx.scene.paint.Paint; 
import javafx.scene.shape.Rectangle; 

class ResizableRectangle extends Rectangle { 

ResizableRectangle(double x, double y, double width, double height, Group group) { 

    super(x, y, width, height); 

    // Set scroll listener for crop selection 
    group.addEventHandler(ScrollEvent.SCROLL, event -> { 
    double zoomFactor = 1.10; 
    double deltaY = event.getDeltaY(); 
    if (deltaY > 0) { 
    zoomFactor = 2.0 - zoomFactor; 
    } 

    super.setX(getX() + (super.getWidth() * (1 - zoomFactor)/2)); // Set new X position 
    super.setWidth(getWidth() * zoomFactor); // Set new Width 

    super.setY(getY() + (super.getHeight() * (1 - zoomFactor)/2)); // Set new Y position 
    super.setHeight(getHeight() * zoomFactor); // Set new Height 

    event.consume(); 
    }); 
}); 
} 

En général, l'algorithme fonctionne comme ceci:

  • Traduire rectangle valeurs x avec: x + (width * (1 - zoomFactor)/2)
  • Traduire valeurs y avec: y + (height * (1 - zoomFactor)/2)
  • Set nouvelle largeur: width * zoomFactor
  • Set nouvelle hauteur: height * zoomFactor