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.

here have problem.

here 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.

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); 

Comments

Popular posts from this blog

c++ - Is it possible to compile a VST on linux? -

c# - SharpSVN - How to get the previous revision? -

php cli reading files and how to fix it? -