2009-03-27 16 views
6

Próbuję przeskalować prostokąt ze środka za pomocą AffineTransform. Jestem pewien, że rozwiązanie jest oczywiste, ale nie mogę sprawić, żeby działało! Oto, co przetestowałem do tej pory ...AffineTransform: skalowanie kształtu ze środka

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()); 
     } 
    } 

Ale to nie działa .... Jakieś sugestie?

+0

Zakładam próbujesz śledzić koncentryczne/wewnętrzne prostokąty? – basszero

Odpowiedz

5

Widzę, co masz na myśli, kiedy masz do czynienia z prostokątami. Powodem jest to, że początkowe obliczenia tłumaczenia nie uwzględniały wielkości obiektu kontenera.

Użyj tego zamiast:

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

Co to robi się tłumaczenia prostokąt na środku panelu przed skalowania. W moich testach działa dobrze.

5

Zakładając, że skalowanie ustala położenie lewego górnego rogu prostokąta (co, jak sądzę, jest prawidłowe, ale od dawna nie robiłem grafiki w Javie), należy przetłumaczyć prostokąt w kierunku przeciwnym do skalowanie.

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

Przesuwasz prostokąt w lewo iw górę o połowę zmiany szerokości i wysokości.

+0

Nie wydaje się działać. –

+0

Twoje rozwiązanie nie działa, ale daje mi kilka nowych pomysłów, dzięki – Pierre

+0

@mmyers: jaki masz wynik? Nie mam dostępu do środowiska Java IDE w pracy, więc nie mogę go przetestować samodzielnie. Pracuję głównie z pamięci. – Welbog

0

Dotyczy to procesu zwanego sprzężeniem transformacji.

Jeśli S jest skalowanie chcesz zrobić, a T jest transformacja trwa punktu (0,0) do punktu, który ma być centrum Twojego skalowania, a następnie przekształcić że spełnia swoje zadanie jest

T (S (odwrotna (T)))

0

(Później) Oto rozwiązanie działające bez wcześniejszej znajomości wymiaru panelu.

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

właśnie pracuje nad aplikacją, przyciąć twarz Brittney włóczni (dzień) Prostokąt przycinający musiał skalować wokół jego punktu środkowego:

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(); 
    }); 
}); 
} 

w ogóle, algorytm działa tak:

  • Przekłada prostokąt wartości x z: x + (width * (1 - zoomFactor)/2)
  • Przekłada wartości y w: y + (height * (1 - zoomFactor)/2)
  • Ustaw nową szerokość do: width * zoomFactor
  • ustawiona nowa wysokość do: height * zoomFactor