简体   繁体   English

使用Java将多边形拉伸到其他多边形

[英]Stretching Polygon to other Polygon with Java

My problem is that I have a rectangle presented with a small perspective, and I would like to stretch it back to be presented as a rectangle again. 我的问题是我有一个带有小透视的矩形,我想将它拉回来再次呈现为矩形。

To represent it visually, I currently have within my image something like the red shape, and I have 4 Points (each corner of this shape). 为了直观地表现它,我目前在我的图像中有类似红色的形状,我有4个Points (这个形状的每个角)。 As result I would like to have something like the blue shape, and I already have the Rectangle object for it. 结果我想要像蓝色的形状,我已经有了Rectangle对象。

在此输入图像描述

I was wondering if there is a method to copy a polygon and draw it as another polygon stretched. 我想知道是否有一种方法来复制多边形并将其绘制为另一个多边形拉伸。 I found something for Android (setPolyToPoly), but I couldn't find something like this for java. 我找到了适合Android的东西(setPolyToPoly),但我找不到像这样的东西。

Is there some reference or code sample that performs this operation, or maybe some idea how can I solve this problem? 是否有一些参考或代码示例执行此操作,或者可能有一些想法如何解决此问题?

I think I understand what you need: a so-called perspective transformation that can be applied to an image. 我想我理解你需要的东西:一种可以应用于图像的所谓透视变换。 Java has the built-in AffineTransform , but an affine transform always preserves the "parallelness" of lines, so you cannot use that. Java有内置的AffineTransform ,但是仿射变换总是保留行的“并行性”,所以你不能使用它。

Now if you search the web for "java perspective transformation", you will find lots of options like the JavaFX PerspectiveTransform , the JAI PerspectiveTransform . 现在,如果您在网上搜索“java perspective transformation”,您会发现许多选项,如JavaFX PerspectiveTransform ,JAI PerspectiveTransform If you only need to stretch images, you can also use the JHLabs PerspectiveFilter and there are other options as well. 如果您只需要拉伸图像,您也可以使用JHLabs PerspectiveFilter ,还有其他选项。

Here is some code that will turn stretch a polygon with four points to a rectangle. 这里有一些代码可以将带有四个点的多边形拉伸到一个矩形。

public static Rectangle2D polyToRect(Polygon polygon) {
    if (polygon.xpoints.length != 4 || polygon.ypoints.length != 4)
        throw new IllegalArgumentException(
                "More than four points, this cannot be fitted to a rectangle");


    Rectangle2D rect = new Rectangle2D.Double();
    for (int i = 0; i < 4; i++) {
        Point2D point = new Point2D.Double(polygon.xpoints[i],
                polygon.ypoints[i]);
        rect.add(point);
    }
    return rect;
}

public static Polygon rectangleToPolygon(Rectangle2D rect) {
    Polygon poly = new Polygon();
    poly.addPoint((int) rect.getX(), (int) rect.getY());
    poly.addPoint((int) (rect.getX() + rect.getWidth()), (int) rect.getY());
    poly.addPoint((int) (rect.getX() + rect.getWidth()),
            (int) (rect.getY() + rect.getHeight()));
    poly.addPoint((int) rect.getX(), (int) (rect.getY() + rect.getHeight()));
    return poly;
}


public static class drawPolyAndRect extends JPanel {
    Polygon poly = new Polygon();

    public drawPolyAndRect() {
        poly.addPoint(0, 0);
        poly.addPoint(400, 40);
        poly.addPoint(400, 250);
        poly.addPoint(0, 400);

    }

    @Override
    @Transient
    public Dimension getPreferredSize() {
        return new Dimension(1000, 1000);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(Color.green);
        g2d.fill(poly);
        Composite c = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                0.5f);
        g2d.setColor(Color.blue);
        g2d.setComposite(c);
        Rectangle2D polyToRect = polyToRect(poly);
        g2d.fill(polyToRect);

        // displace for drawing
        polyToRect.setFrame(polyToRect.getX() + 100,
                polyToRect.getY() + 100, polyToRect.getWidth(),
                polyToRect.getHeight());

        Polygon polyToRectToPoly = rectangleToPolygon(polyToRect);
        g2d.fill(polyToRectToPoly);

        g2d.dispose();
    }

}

public static void main(String[] args) {
    JFrame frame = new JFrame("Poly to rect");
    frame.getContentPane().add(new drawPolyAndRect());
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
}

Essentially this uses how adding points to an empty rectangle2d works, it constructs the smallest possible rectangle containing all four points, stretching the polygon. 本质上,这使用了如何向空矩形2d添加点,它构造包含所有四个点的最小可能矩形,拉伸多边形。 Check the second static method if you want the returned rectangle as a polygon. 如果要将返回的矩形作为多边形,请检查第二个静态方法。 Picture: 图片: 在此输入图像描述

A JavaFX based solution using a PerspectiveTransform as suggested by @lbalazscs answer . 使用PerspectiveTransform的基于JavaFX的解决方案,如@lbalazscs回答所示

  • Toggle Perspective switches on and off the perspective effect on the content. Toggle Perspective打开和关闭对内容的透视效果。
  • Morph Perspective smoothly animates a transition between the perspective transformed and non-perspective transformed content. Morph Perspective平滑地动画透视变换内容和非透视变换内容之间的过渡。

透视透视

import javafx.animation.*;
import javafx.application.*;
import javafx.beans.value.*;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.ToggleButton;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.image.*;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.*;
import javafx.stage.Stage;
import javafx.util.Duration;

public class PerspectiveMovement extends Application {
  // perspective transformed group width and height.
  private final int W = 280;
  private final int H = 96;

  // upper right and lower right co-ordinates of perspective transformed group.
  private final int URY = 35;
  private final int LRY = 65;

  @Override public void start(Stage stage) {
    final PerspectiveTransform perspectiveTransform = createPerspectiveTransform();

    final Group group = new Group();
    group.setCache(true);
    setContent(group);

    final ToggleButton perspectiveToggle = createToggle(
      group, 
      perspectiveTransform
    );

    VBox layout = new VBox(10);
    layout.setAlignment(Pos.CENTER);
    layout.getChildren().setAll(
      perspectiveToggle,
      createMorph(perspectiveToggle, group, perspectiveTransform),
      group
    );
    layout.setStyle("-fx-padding: 10px; -fx-background-color: rgb(17, 20, 25);");

    stage.setScene(new Scene(layout));
    stage.show();
  }

  private void setContent(Group group) {
    Rectangle rect = new Rectangle(0, 5, W, 80);
    rect.setFill(Color.web("0x3b596d"));

    Text text = new Text();
    text.setX(4.0);
    text.setY(60.0);
    text.setText("A long time ago");
    text.setFill(Color.ALICEBLUE);
    text.setFont(Font.font(null, FontWeight.BOLD, 36));

    Image image = new Image(
      "http://icons.iconarchive.com/icons/danrabbit/elementary/96/Star-icon.png"
    );
    ImageView imageView = new ImageView(image);
    imageView.setX(50);

    group.getChildren().addAll(rect, imageView, text);
  }

  private PerspectiveTransform createPerspectiveTransform() {
    PerspectiveTransform perspectiveTransform = new PerspectiveTransform();

    perspectiveTransform.setUlx(0.0);
    perspectiveTransform.setUly(0.0);
    perspectiveTransform.setUrx(W);
    perspectiveTransform.setUry(URY);
    perspectiveTransform.setLrx(W);
    perspectiveTransform.setLry(LRY);
    perspectiveTransform.setLlx(0.0);
    perspectiveTransform.setLly(H);

    return perspectiveTransform;
  }

  private ToggleButton createToggle(final Group group, final PerspectiveTransform perspectiveTransform) {
    final ToggleButton toggle = new ToggleButton("Toggle Perspective");
    toggle.selectedProperty().addListener(new ChangeListener<Boolean>() {
      @Override public void changed(ObservableValue<? extends Boolean> observable, Boolean wasSelected, Boolean selected) {
        if (selected) {
          perspectiveTransform.setUry(URY);
          perspectiveTransform.setLry(LRY);
          group.setEffect(perspectiveTransform);
        } else {
          group.setEffect(null);
        }
      }
    });

    return toggle;
  }

  private ToggleButton createMorph(final ToggleButton perspectiveToggle, final Group group, final PerspectiveTransform perspectiveTransform) {
    final Timeline distorter = new Timeline(
      new KeyFrame(
        Duration.seconds(0), 
        new KeyValue(perspectiveTransform.uryProperty(), 0,  Interpolator.LINEAR),
        new KeyValue(perspectiveTransform.lryProperty(), H, Interpolator.LINEAR)
      ),
      new KeyFrame(
        Duration.seconds(3), 
        new KeyValue(perspectiveTransform.uryProperty(), URY, Interpolator.LINEAR),
        new KeyValue(perspectiveTransform.lryProperty(), LRY, Interpolator.LINEAR)
      )
    );

    final ToggleButton morphToggle = new ToggleButton("Morph Perspective");
    morphToggle.selectedProperty().addListener(new ChangeListener<Boolean>() {
      @Override public void changed(ObservableValue<? extends Boolean> observable, Boolean wasSelected, Boolean selected) {
        if (!perspectiveToggle.isSelected()) {
          perspectiveToggle.fire();
        }
        if (selected) {
          distorter.setRate(1);
          distorter.play();
        } else {
          distorter.setRate(-1);
          distorter.play();
        }
      }
    });

    return morphToggle;
  }
}

I don't know if this could help you but let me give you what i made with what i understand: 我不知道这是否可以帮助你,但让我用你所理解的东西给你。

import javax.swing.*;
import java.awt.*;

public class PolyToRectangle extends JPanel {
public static final int SPEED = 50; //less = more fast.
private int ax = 0, bx = 800, cx = 800, dx = 0, 
            ay = 0, by = 40, cy = 250, dy = 400;
private Polygon poly;


public PolyToRectangle() {
    setPreferredSize(new Dimension(1200, 720));
    poly = new Polygon(new int[]{ax, bx, cx, dx}, new int[]{ay, by, cy, dy}, 4);
}

@Override
public void paintComponent(Graphics g) {

    Graphics2D g2d = (Graphics2D) g;
    g2d.draw(poly);
    g2d.fill(poly);
}

public void polyToRectangle() throws InterruptedException {
    int flag = 0;
    for (int i = 0; i < 150; i++) {
        flag++;
        poly.addPoint(ax, ay);
        poly.addPoint(bx, (by = flag % 3 == 0 ? --by : by));
        poly.addPoint(cx, cy++);
        poly.addPoint(dx, dy);
        Thread.sleep(SPEED);
        repaint();
    }
}

protected void clear(Graphics g) {
    super.paintComponent(g);
}

public static void main(String[] args) throws InterruptedException {
    Frame frame = new JFrame();
    PolyToRectangle se = new PolyToRectangle();
    frame.add(se);
    frame.pack();
    frame.setVisible(true);
    se.polyToRectangle();

}
}

Ok as you can see this code is more a "PolyToSquare" more than PolyToRectangle, but the main was to show the "effect" of repainting with a Thread.sleep in a for, maybe that's the "visual stretch" you are talking about, note that the numbers of iterations on the for depends on numbers of pixels from point 1 and 2 to "stretch" from polygon to rectangle, this is a "hand made" effect, maybe what @lbalazscs is suggesting is the best solution, hope to be helpful, regards. 好的,你可以看到这个代码比PolyToRectangle更像是一个“PolyToSquare”,但主要是显示用for中的Thread.sleep重新绘制的“效果”,也许这就是你所说的“视觉延伸”,请注意,for上的迭代次数取决于从第1点和第2点到“从多边形到矩形”“拉伸”的像素数,这是一种“手工制作”效果,也许@lbalazscs建议的是最好的解决方案,希望乐于助人,问候。

EDIT: edited the code to be more clean and to follow in a more specific way your goal (now is more a PolyToRectangle, fixed the bx and cx values). 编辑:编辑代码更干净,并以更具体的方式遵循您的目标(现在更多的是PolyToRectangle,修复了bx和cx值)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM