gpt4 book ai didi

java - 这个奇怪的区域减法问题的原因是什么?

转载 作者:塔克拉玛干 更新时间:2023-11-02 07:56:10 25 4
gpt4 key购买 nike

当我编写碰撞检测算法时,我遇到了这个问题。这是一件奇怪的事情,超出了我的理解。

这里的问题是,如果在我的算法中,在函数 tryMove() 中出现,我将 potentialArea 添加到 moveLineArea 并且我正在检测 spaceTestArea(从 moveLineArea 创建)在减去所有单元占用的区域后,我与一个单元发生碰撞这甚至不接近 x=280,y=120,其中移动单元位于 x=1880,y=120,并且正在移动到 x= 1914 年,y=126

我想知道这个问题的可能原因是什么以及如何避免将来发生。

我必须说我有一个临时解决方案 (tryMove2()) 但请不要让它影响你的想法,即我不喜欢这个解决方案并且我坚信第一个解决方案 (tryMove()) 应该可以工作,一定是我忘记了什么。

请参阅下面显示问题的代码。

import java.awt.Point;
import java.awt.Polygon;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;

/**
* Test showing some unexpected and weird behaviour of area subtraction.
* @author Konrad Borowiecki
*/
public class TestTryMove {
private static final List<Point> unitCenterPoints = new ArrayList<Point>();
static{
unitCenterPoints.add(new Point(1720, 120));
unitCenterPoints.add(new Point(1880, 120));
unitCenterPoints.add(new Point(1800, 200));
unitCenterPoints.add(new Point(1720, 280));
unitCenterPoints.add(new Point(1880, 280));
unitCenterPoints.add(new Point(120, 120));
unitCenterPoints.add(new Point(280, 120));
unitCenterPoints.add(new Point(200, 200));
unitCenterPoints.add(new Point(120, 280));
unitCenterPoints.add(new Point(280, 280));
unitCenterPoints.add(new Point(120, 1720));
unitCenterPoints.add(new Point(280, 1720));
unitCenterPoints.add(new Point(200, 1800));
unitCenterPoints.add(new Point(120, 1880));
unitCenterPoints.add(new Point(280, 1880));
}
public static void main(String[] args) {
int[] xpointsOK = new int[]{1876, 1884, 1918, 1910};//for Move OK
int[] ypointsOK = new int[]{139, 101, 108, 146};//for Move OK
Polygon lineOK = new Polygon(xpointsOK, ypointsOK, xpointsOK.length);

int[] xpointsFAIL = new int[]{1877, 1883, 1917, 1911};//for problem no move
int[] ypointsFAIL = new int[]{139, 101, 107, 145};//for problem no move
Polygon lineFAIL = new Polygon(xpointsFAIL, ypointsFAIL, xpointsFAIL.length);

Point endPointCPOK = new Point(1914, 127);//Move OK
Point endPointCPFAIL = new Point(1914, 126);//problem no move
//where in both cases it should be move OK
System.out.println("******TEST for method tryMove()******");
System.out.println("TEST 1: this will FAIL");
System.out.println("Result="+tryMove(endPointCPFAIL, lineFAIL));
System.out.println("\nTEST 2: this will be OK");
System.out.println("Result="+tryMove(endPointCPOK, lineOK));


System.out.println("******TEST for method tryMove2()******");
System.out.println("TEST 1: this will be OK");
System.out.println("Result="+tryMove2(endPointCPFAIL, lineFAIL));
System.out.println("\nTEST 2: this will be OK");
System.out.println("Result="+tryMove2(endPointCPOK, lineOK));
}
/**
* Tests if a unit represented by point of index 1 in the list of
* unitCenterPoints (i.e. [1880, 120]) can make a move to the given endPointCP.
* (Please notice we are ignoring this unit in the algorithm
* i.e. if(i != movingUnitIndexInTheArray)).
* @param endPointCP the point where the unit moves to.
* @param line the line of the move of the thickness equal to units width (mod=40),
* drawn between the current unit's center point and the endPointCP,
* represented as a polygon object.
* @return true if move possible; false otherwise.
*/
private static boolean tryMove(Point endPointCP, Polygon line){
Area potentialArea = getArea(endPointCP);
Area moveLineArea = new Area(line);
moveLineArea.add(potentialArea);
//this area is used for testing if nothing stays on the way of the move
Area spaceTestArea = new Area(moveLineArea);
//the index of the unit making the move in the unitCenterPoints list
int movingUnitIndexInTheArray = 1;
//we are subtracting from spaceTestArea all areas of units
for(int i = 0; i < unitCenterPoints.size(); i++)
if(i != movingUnitIndexInTheArray) {
Point p = unitCenterPoints.get(i);
Area uArea = getArea(p);
spaceTestArea.subtract(uArea);
//we have intersection then return false, we cannot make this move
if(spaceTestArea.isEmpty() || !spaceTestArea.equals(moveLineArea)) {
System.out.println("No move --- a unit is on the way. "
+ "Conflicting point is="+p +"; for i="+i);
return false;
}
}
System.out.println("Move OK.");
return true;
}

private static boolean tryMove2(Point endPointCP, Polygon line){
Area potentialArea = getArea(endPointCP);
Area moveLineArea = new Area(line);
//test if unit can move to the new position
Area potentialTestArea = new Area(potentialArea);
//this area is used for testing if nothing stays on the way of the move
Area spaceTestArea = new Area(moveLineArea);
//the index of the unit making the move in the unitCenterPoints list
int movingUnitIndexInTheArray = 1;
//we are subtracting from spaceTestArea all areas of units
for(int i = 0; i < unitCenterPoints.size(); i++)
if(i != movingUnitIndexInTheArray) {
Point p = unitCenterPoints.get(i);
Area uArea = getArea(p);
spaceTestArea.subtract(uArea);
potentialTestArea.subtract(uArea);
//we have intersection then return false, we cannot make this move
if(spaceTestArea.isEmpty() || !spaceTestArea.equals(moveLineArea)
|| potentialTestArea.isEmpty() || !potentialTestArea.equals(potentialArea)) {
System.out.println("No move --- a unit is on the way. "
+ "Conflicting point is="+p +"; for i="+i);
return false;
}
}
System.out.println("Move OK.");
return true;
}
/**
* Gets the area taken by a unit given the unit's center point.
* @param p the center point of a unit.
* @return circle area.
*/
private static Area getArea(Point p) {
int mod = 40;//this is width and height of a unit
Ellipse2D circle = new Ellipse2D.Double(p.x - mod / 2, p.y - mod / 2, mod, mod);
return new Area(circle);
}
}

这是它产生的输出:

******TEST for method tryMove()******
TEST 1: this will FAIL
No move --- a unit is on the way. Conflicting point is=java.awt.Point[x=280,y=120]; for i=6; where moving unit point is=java.awt.Point[x=1880,y=120]; the unit is moving to=java.awt.Point[x=1914,y=126]
Result=false

TEST 2: this will be OK
Move OK.
Result=true
******TEST for method tryMove2()******
TEST 1: this will be OK
Move OK.
Result=true

TEST 2: this will be OK
Move OK.
Result=true

为了让您更好地看到问题,我用两张图片展示了两个端点,第一个 1914, 126 当方法失败时,第二个 1914, 127什么时候可以。

Here we have the problem.

Here is all OK.

如果需要更多描述,我会尽快答复。提前谢谢大家。

编辑 1:正如@trashgod 所建议的,我确实尝试并实现了一个使用 intersect() 方法的解决方案。我不喜欢每次测试都必须创建一个新对象。你能对这个算法提出一些优化建议吗。

private static boolean tryMove3(Point endPointCP, Polygon line){
Area potentialArea = getArea(endPointCP);
Area moveLineArea = new Area(line);
moveLineArea.add(potentialArea);
//this area is used for testing if nothing stays on the way of the move
//the index of the unit making the move in the unitCenterPoints list
int movingUnitIndexInTheArray = 1;
//we are subtracting from spaceTestArea all areas of units
for(int i = 0; i < unitCenterPoints.size(); i++)
if(i != movingUnitIndexInTheArray) {
Point p = unitCenterPoints.get(i);
Area uArea = getArea(p);
Area spaceTestArea = new Area(moveLineArea);
spaceTestArea.intersect(uArea);
//we have intersection then return false, we cannot make this move
if(!spaceTestArea.isEmpty()) {
System.out.println("No move --- a unit is on the way. "
+ "Conflicting point is="+p +"; for i="+i
+ "; where moving unit point is="
+unitCenterPoints.get(movingUnitIndexInTheArray)
+"; the unit is moving to="+endPointCP
+"; spaceTestArea.isEmpty()="+spaceTestArea.isEmpty());
return false;
}
}
System.out.println("Move OK.");
return true;
}

最佳答案

我猜你正在与其中一种方式发生冲突 java.awt.geom.Area可以变空。如果有帮助,我在下面拍了张照片。或者,您可以使用 createTransformedShape()contains() 吗?

附录:tryMove3() 看起来是正确的。如果情况真的更糟,我看到了几种可能性:

  • Cache任何静态区域,可能是与每个中心点相关联的区域。

  • 根据 getBounds()quadtree 进行粗略的邻域检查并跳过远程对。

enter image description here

JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JPanel(){

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.scale(10, 10);
g2d.translate(-1875, -100);
g2d.setColor(Color.green);
g2d.draw(lineOK);
g2d.setColor(Color.green.darker());
g2d.drawRect(endPointCPOK.x, endPointCPOK.y, 1, 1);
g2d.setColor(Color.red);
g2d.draw(lineFAIL);
g2d.setColor(Color.red.darker());
g2d.drawRect(endPointCPFAIL.x, endPointCPFAIL.y, 1, 1);
}
});
f.pack();
f.setSize(450, 500);
f.setLocationRelativeTo(null);
f.setVisible(true);

关于java - 这个奇怪的区域减法问题的原因是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6551713/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com