java - What is the reason of this weird area subtraction issue? -
while coding algorithm of collision detection have come @ problem. weird beyond understanding.
the problem here is if in algorithm, presented in function trymove(), add potentialarea movelinearea , doing detection of change in spacetestarea (which created movelinearea) after subtracting areas taken units, have collision unit not close x=280,y=120, moving unit @ x=1880,y=120, , moving x=1914,y=126.
i know might reason of issue , in order avoid in future.
i must have temporary solution (trymove2()) please not let influence thinking, i.e. not solution , believe first solution (trymove()) should work , must me forgot something.
please see below code presenting problem.
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 unexpected , 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 should move ok system.out.println("******test method trymove()******"); system.out.println("test 1: fail"); system.out.println("result="+trymove(endpointcpfail, linefail)); system.out.println("\ntest 2: ok"); system.out.println("result="+trymove(endpointcpok, lineok)); system.out.println("******test method trymove2()******"); system.out.println("test 1: ok"); system.out.println("result="+trymove2(endpointcpfail, linefail)); system.out.println("\ntest 2: ok"); system.out.println("result="+trymove2(endpointcpok, lineok)); } /** * tests if unit represented point of index 1 in list of * unitcenterpoints (i.e. [1880, 120]) can make move given endpointcp. * (please notice ignoring unit in algorithm * i.e. if(i != movingunitindexinthearray)). * @param endpointcp point unit moves to. * @param line line of move of thickness equal units width (mod=40), * drawn between current unit's center point , endpointcp, * represented 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 used testing if nothing stays on way of move area spacetestarea = new area(movelinearea); //the index of unit making move in unitcenterpoints list int movingunitindexinthearray = 1; //we subtracting spacetestarea areas of units for(int = 0; < unitcenterpoints.size(); i++) if(i != movingunitindexinthearray) { point p = unitcenterpoints.get(i); area uarea = getarea(p); spacetestarea.subtract(uarea); //we have intersection return false, cannot make move if(spacetestarea.isempty() || !spacetestarea.equals(movelinearea)) { system.out.println("no move --- unit on way. " + "conflicting point is="+p +"; 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 new position area potentialtestarea = new area(potentialarea); //this area used testing if nothing stays on way of move area spacetestarea = new area(movelinearea); //the index of unit making move in unitcenterpoints list int movingunitindexinthearray = 1; //we subtracting spacetestarea areas of units for(int = 0; < unitcenterpoints.size(); i++) if(i != movingunitindexinthearray) { point p = unitcenterpoints.get(i); area uarea = getarea(p); spacetestarea.subtract(uarea); potentialtestarea.subtract(uarea); //we have intersection return false, cannot make move if(spacetestarea.isempty() || !spacetestarea.equals(movelinearea) || potentialtestarea.isempty() || !potentialtestarea.equals(potentialarea)) { system.out.println("no move --- unit on way. " + "conflicting point is="+p +"; i="+i); return false; } } system.out.println("move ok."); return true; } /** * gets area taken unit given unit's center point. * @param p center point of unit. * @return circle area. */ private static area getarea(point p) { int mod = 40;//this width , height of unit ellipse2d circle = new ellipse2d.double(p.x - mod / 2, p.y - mod / 2, mod, mod); return new area(circle); } } and output producing:
******test method trymove()****** test 1: fail no move --- unit on way. conflicting point is=java.awt.point[x=280,y=120]; i=6; moving unit point is=java.awt.point[x=1880,y=120]; unit moving to=java.awt.point[x=1914,y=126] result=false test 2: ok move ok. result=true ******test method trymove2()****** test 1: ok move ok. result=true test 2: ok move ok. result=true in order see problem better have 2 images presenting 2 endpoints, first 1914, 126 when method fails, , second 1914, 127 when ok.


if more description needed answer asap. thank in advance.
edit1: suggested @trashgod did tried , implemented solution uses intersect() method. not every test must create new object. can suggest optimization algorithm.
private static boolean trymove3(point endpointcp, polygon line){ area potentialarea = getarea(endpointcp); area movelinearea = new area(line); movelinearea.add(potentialarea); //this area used testing if nothing stays on way of move //the index of unit making move in unitcenterpoints list int movingunitindexinthearray = 1; //we subtracting spacetestarea areas of units for(int = 0; < 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 return false, cannot make move if(!spacetestarea.isempty()) { system.out.println("no move --- unit on way. " + "conflicting point is="+p +"; i="+i + "; moving unit point is=" +unitcenterpoints.get(movingunitindexinthearray) +"; unit moving to="+endpointcp +"; spacetestarea.isempty()="+spacetestarea.isempty()); return false; } } system.out.println("move ok."); return true; }
i'm guessing you're running afoul of 1 of ways java.awt.geom.area can become empty. if helps, took picture, below. alternatively, use createtransformedshape() , contains()?
addendum: trymove3() appears correct. if profiles worse, see several possibilities:
cache static
area, perhaps associated each center point.do rough vicinity check based on
getbounds()or quadtree , skip remote pairs.

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);
Comments
Post a Comment