1 回答

TA貢獻(xiàn)1811條經(jīng)驗(yàn) 獲得超4個(gè)贊
這至少與Texture deforming密切相關(guān),4分,但我不會(huì)說它可以被認(rèn)為是重復(fù)的。
你在那里做了很多數(shù)學(xué)工作。但也許這不是必需的。使用正確的方法,問題本身是相當(dāng)微不足道的??紤]二維仿射變換的含義:它將一個(gè)空間變換到另一個(gè)空間。這里的關(guān)鍵點(diǎn)是:
矩陣列是將矩陣應(yīng)用于單位向量的結(jié)果
現(xiàn)在,當(dāng)你有 3 個(gè)點(diǎn)時(shí),你可以從它們計(jì)算向量:
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
。結(jié)果是AffineTransform
將點(diǎn) (0,0)、(1,0) 和 (0,1) 分別轉(zhuǎn)換為點(diǎn)p0
、p1
和p2
。當(dāng)您反轉(zhuǎn)此變換時(shí),它會(huì)將點(diǎn)p0
、p1
和轉(zhuǎn)換p2
為點(diǎn) (0,0)、(1,0) 和 (0,1)。
所以你所要做的就是
創(chuàng)建將源點(diǎn)轉(zhuǎn)換為單位向量的變換
創(chuàng)建將單位向量轉(zhuǎn)換為目標(biāo)點(diǎn)的變換
將兩者連接起來
偽代碼 (!) 真的很簡單
? ? 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());
整個(gè)事情都在這里實(shí)現(xiàn),作為 MCVE。紅色點(diǎn)是“源”點(diǎn),綠色點(diǎn)是“目的地”點(diǎn)。你可以用鼠標(biāo)拖動(dòng)它們:
藍(lán)色圓圈表示將變換應(yīng)用于源點(diǎn)的結(jié)果,您可以看到它們最終到達(dá)了所需的目標(biāo)位置。
實(shí)際計(jì)算是通過computeTransform方法完成的。請注意,這是基于java.awt.geom.Point2D類(而不是Vector2d您省略的類)實(shí)現(xiàn)的,但這應(yīng)該很容易更改:點(diǎn)或矢量類唯一使用的是 x/y 坐標(biāo)。除此之外,實(shí)現(xiàn)中根本不涉及(自定義)數(shù)學(xué)。唯一的數(shù)學(xué)是反轉(zhuǎn)仿射變換,但有一個(gè)內(nèi)置的功能。
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
? ? }
}
添加回答
舉報(bào)