1 回答

TA貢獻1811條經驗 獲得超4個贊
這至少與Texture deforming密切相關,4分,但我不會說它可以被認為是重復的。
你在那里做了很多數學工作。但也許這不是必需的。使用正確的方法,問題本身是相當微不足道的??紤]二維仿射變換的含義:它將一個空間變換到另一個空間。這里的關鍵點是:
矩陣列是將矩陣應用于單位向量的結果
現在,當你有 3 個點時,你可以從它們計算向量:
double dx1 = p1.getX() - p0.getX();
double dy1 = p1.getY() - p0.getY();
double dx2 = p2.getX() - p0.getX();
double dy2 = p2.getY() - p0.getY();
然后您可以簡單地將這些值插入AffineTransform
.?最后一列AffineTransform
包含由 給出的翻譯p0
。結果是AffineTransform
將點 (0,0)、(1,0) 和 (0,1) 分別轉換為點p0
、p1
和p2
。當您反轉此變換時,它會將點p0
、p1
和轉換p2
為點 (0,0)、(1,0) 和 (0,1)。
所以你所要做的就是
創建將源點轉換為單位向量的變換
創建將單位向量轉換為目標點的變換
將兩者連接起來
偽代碼 (!) 真的很簡單
? ? AffineTransform unitToSrc = computeTransform(src[0], src[1], src[2]);
? ? AffineTransform unitToDst = computeTransform(dst[0], dst[1], dst[2]);
? ? AffineTransform at = new AffineTransform();
? ? at.concatenate(unitToDst);
? ? at.concatenate(unitToSrc.inverted());
整個事情都在這里實現,作為 MCVE。紅色點是“源”點,綠色點是“目的地”點。你可以用鼠標拖動它們:
藍色圓圈表示將變換應用于源點的結果,您可以看到它們最終到達了所需的目標位置。
實際計算是通過computeTransform方法完成的。請注意,這是基于java.awt.geom.Point2D類(而不是Vector2d您省略的類)實現的,但這應該很容易更改:點或矢量類唯一使用的是 x/y 坐標。除此之外,實現中根本不涉及(自定義)數學。唯一的數學是反轉仿射變換,但有一個內置的功能。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.util.Arrays;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class AffineTransformFromPoints
{
? ? public static void main(String[] args)
? ? {
? ? ? ? SwingUtilities.invokeLater(() -> createAndShowGUI());
? ? }
? ? private static void createAndShowGUI()
? ? {
? ? ? ? JFrame f = new JFrame();
? ? ? ? f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
? ? ? ? AffineTransformFromPointsPanel panel =?
? ? ? ? ? ? new AffineTransformFromPointsPanel();
? ? ? ? f.getContentPane().setLayout(new BorderLayout());
? ? ? ? f.getContentPane().add(panel, BorderLayout.CENTER);
? ? ? ? f.setSize(1200,900);
? ? ? ? f.setLocationRelativeTo(null);
? ? ? ? f.setVisible(true);
? ? }
}
class AffineTransformFromPointsPanel extends JPanel?
? ? implements MouseListener, MouseMotionListener
{
? ? private Point2D draggedPoint;
? ? // the position of the points before the transformation
? ? Point2D[] src = new Point2D[] {
? ? ? ? new Point2D.Double(486, 191),
? ? ? ? new Point2D.Double(456, 565),
? ? ? ? new Point2D.Double(149, 353)
? ? };
? ? // the position of the points after the transformation
? ? Point2D[] dst = new Point2D[] {
? ? ? ? new Point2D.Double(0, 0),
? ? ? ? new Point2D.Double(0, 600),
? ? ? ? new Point2D.Double(600, 600)
? ? };
? ? public AffineTransformFromPointsPanel()
? ? {
? ? ? ? addMouseListener(this);
? ? ? ? addMouseMotionListener(this);
? ? }
? ? @Override
? ? protected void paintComponent(Graphics gr)
? ? {
? ? ? ? super.paintComponent(gr);
? ? ? ? Graphics2D g = (Graphics2D)gr;
? ? ? ? g.setColor(Color.WHITE);
? ? ? ? g.fillRect(0, 0, getWidth(), getHeight());
? ? ? ? g.setRenderingHint(
? ? ? ? ? ? RenderingHints.KEY_ANTIALIASING,?
? ? ? ? ? ? RenderingHints.VALUE_ANTIALIAS_ON);
? ? ? ? g.setColor(Color.RED);
? ? ? ? for (Point2D v : src)
? ? ? ? {
? ? ? ? ? ? paint(g, v);
? ? ? ? }
? ? ? ? g.setColor(Color.GREEN);
? ? ? ? for (Point2D v : dst)
? ? ? ? {
? ? ? ? ? ? paint(g, v);
? ? ? ? }
? ? ? ? g.setColor(Color.BLUE);
? ? ? ? AffineTransform at = computeTransform(src, dst);
? ? ? ? for (Point2D v : src)
? ? ? ? {
? ? ? ? ? ? draw(g, v, at);
? ? ? ? }
? ? }
? ? private static AffineTransform computeTransform(
? ? ? ? Point2D src[], Point2D dst[])
? ? {
? ? ? ? AffineTransform unitToSrc = computeTransform(src[0], src[1], src[2]);
? ? ? ? AffineTransform unitToDst = computeTransform(dst[0], dst[1], dst[2]);
? ? ? ? AffineTransform srcToUnit = null;
? ? ? ? try
? ? ? ? {
? ? ? ? ? ? srcToUnit = unitToSrc.createInverse();
? ? ? ? }
? ? ? ? catch (NoninvertibleTransformException e)
? ? ? ? {
? ? ? ? ? ? System.out.println(e.getMessage());
? ? ? ? ? ? return new AffineTransform();
? ? ? ? }
? ? ? ? AffineTransform at = new AffineTransform();
? ? ? ? at.concatenate(unitToDst);
? ? ? ? at.concatenate(srcToUnit);
? ? ? ? return at;
? ? }
? ? private static AffineTransform computeTransform(
? ? ? ? Point2D p0, Point2D p1, Point2D p2)
? ? {
? ? ? ? AffineTransform at = new AffineTransform();
? ? ? ? double dx1 = p1.getX() - p0.getX();
? ? ? ? double dy1 = p1.getY() - p0.getY();
? ? ? ? double dx2 = p2.getX() - p0.getX();
? ? ? ? double dy2 = p2.getY() - p0.getY();
? ? ? ? at.setTransform(dx1, dy1, dx2, dy2, p0.getX(), p0.getY());
? ? ? ? return at;
? ? }
? ? private static void paint(Graphics2D g, Point2D p)
? ? {
? ? ? ? double r = 6;
? ? ? ? g.fill(new Ellipse2D.Double(
? ? ? ? ? ? p.getX() - r, p.getY() - r, r + r, r + r));
? ? }
? ? private static void draw(Graphics2D g, Point2D v, AffineTransform at)
? ? {
? ? ? ? double r = 8;
? ? ? ? Point2D p = new Point2D.Double(v.getX(), v.getY());
? ? ? ? at.transform(p, p);
? ? ? ? g.draw(new Ellipse2D.Double(
? ? ? ? ? ? p.getX() - r, p.getY() - r, r + r, r + r));
? ? }
? ? @Override
? ? public void mouseDragged(MouseEvent e)
? ? {
? ? ? ? if (draggedPoint != null)
? ? ? ? {
? ? ? ? ? ? draggedPoint.setLocation(e.getPoint());
? ? ? ? ? ? repaint();
? ? ? ? }
? ? }
? ? @Override
? ? public void mousePressed(MouseEvent e)
? ? {
? ? ? ? draggedPoint = closest(e.getPoint(), Arrays.asList(src));
? ? ? ? if (draggedPoint == null)
? ? ? ? {
? ? ? ? ? ? draggedPoint = closest(e.getPoint(), Arrays.asList(dst));
? ? ? ? }
? ? }
? ? private static Point2D closest(
? ? ? ? Point2D p, Iterable<? extends Point2D> points)
? ? {
? ? ? ? final double threshold = 10;
? ? ? ? Point2D closestPoint = null;
? ? ? ? double minDistance = Double.MAX_VALUE;
? ? ? ? for (Point2D point : points)
? ? ? ? {
? ? ? ? ? ? double dd = point.distance(p);
? ? ? ? ? ? if (dd < threshold && dd < minDistance)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? minDistance = dd;
? ? ? ? ? ? ? ? closestPoint = point;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return closestPoint;
? ? }
? ? @Override
? ? public void mouseReleased(MouseEvent e)
? ? {
? ? ? ? draggedPoint = null;
? ? }
? ? @Override
? ? public void mouseMoved(MouseEvent e)
? ? {
? ? ? ? // Nothing to do here
? ? }
? ? @Override
? ? public void mouseClicked(MouseEvent e)
? ? {
? ? ? ? // Nothing to do here
? ? }
? ? @Override
? ? public void mouseEntered(MouseEvent e)
? ? {
? ? ? ? // Nothing to do here
? ? }
? ? @Override
? ? public void mouseExited(MouseEvent e)
? ? {
? ? ? ? // Nothing to do here
? ? }
}
添加回答
舉報