Select to view content in your preferred language

GraphicsLayer Limitation on Number of Graphics Selected

5719
10
Jump to solution
01-25-2013 03:16 PM
CarlosColón-Maldonado
Frequent Contributor
I figured out how to get the getGraphicIDs method to work with a graphicslayer off a MessageGroupLayer and worked fine. I post it here on another thread.

I ran into a behavior that may become an issue at some point for some people (as it did me). I noticed that there is a limitation on the number of graphic ids being selected and, thus the number of Graphic objects being collected in order to obtain an associated Message object from the message processor for each.

After creating 1,000 symbols in near approximation then later zoom out in order to give the impression that they appeared on top of each other ([ATTACH=CONFIG]21084[/ATTACH]), I could only collect a maximum of 20 symbols. Furthermore, I noticed that the selected corresponding symbols were not approximate to each other([ATTACH=CONFIG]21085[/ATTACH]), while others were but unselected([ATTACH=CONFIG]21086[/ATTACH]). I've guessed using different tolerance levels but didn't seem to matter.

Is there a way to manipulate this behavior? It appears to have relevance of the current map scale, but I'm not sure how the tolerance can be dynamically modified to overcome this.

Any help will be appreciated.
0 Kudos
1 Solution

Accepted Solutions
by Anonymous User
Not applicable
Original User: mbaird

Hi Carlos,

I take your point about reordering the point graphics layers. 

Going back to the selection issue, I changed my code to add a few more symbols to include:

- point based position reports
- chem lights
- line based position reports

I then altered my map click event to dive into each of the graphics layers in the message group layer:

          //get layers in message group layer           Layer[] layers = mgl.getLayers();           System.out.println("there are layers : " + layers.length);                      //go through the layers in the message group layer to do a hit test on each one:           for(Layer gLayer : layers)           {            System.out.println("Layer name = " + gLayer.getName());            System.out.println("--------------------------------");                        //cast to graphics layer            GraphicsLayer gl = (GraphicsLayer) gLayer;                        int[] all_graphics = gl.getGraphicIDs();               System.out.println("total graphics = " + all_graphics.length);                              int[] ids = gl.getGraphicIDs((float)arg0.getX(),(float) arg0.getY(), 5, 4000);                              if (ids.length > 0)               {                               System.out.println("hit result with " + ids.length);                                gl.setSelectionIDs(ids, true);               }           }



I then zoomed out and clicked in the middle of the jumble of symbols and they were all selected.

I get the following output :

map clicked at -156543.03392799944,626172.1357119977 there are layers : 3 Layer name = position_reports_Lines -------------------------------- total graphics = 4001 hit result with 4000 Layer name = position_reports -------------------------------- total graphics = 4001 hit result with 4000 Layer name = chemlights -------------------------------- total graphics = 4000 hit result with 4000


As before the position reports are reporting 4001 items as I've got some created in another area of the world.

Mark

View solution in original post

0 Kudos
10 Replies
by Anonymous User
Not applicable
Original User: mbaird

Hi Carlos,

It's not really a limitation, it's more of a feature as they say 🙂

When you perform a getGraphicsIDs call it limits the number of results to 10.  It's documented in the Java Doc:


getGraphicIDs
public int[] getGraphicIDs(float x,
                           float y,
                           int tolerance)
Finds the graphics near the supplied x,y in pixels. Both visible and invisible graphics are returned. The graphics must have been through a Map draw cycle before they can be found.

Parameters:
x - the x coordinates of the point for searching.
y - the y coordinates of the point for searching.
tolerance - the search tolerance in pixels
Returns:
the first 10 graphics within the search tolerance.



However all is not lost as there is an overloaded method which might help (see numberOfResults):


[INDENT]getGraphicIDs(x, y, tolerance, numberOfResults)[/INDENT]


Also note that the tolerance of your hit test of the graphics layer is in pixels.  I typically find that 5 is a good value - but you need to tune this to your application and operating environment.

Let me know if this answers your question

Mark
0 Kudos
CarlosColón-Maldonado
Frequent Contributor
Nice catch, Mark. And, nice feature! 😉

Yes, this does indeed answers it and will help me fine-tune my application.

Thanks,

Carlos
0 Kudos
CarlosColón-Maldonado
Frequent Contributor
I did exactly as you suggested and it all worked just fine up until I had over 1,000 symbols on the map and attempted to collect them all at once. I zoomed out at certain levels to where they appeared on top of each other, then clicking on certain spots where there were close to 900 of them kept the application responsive. On other spots where all were nearest to each other, while the map was at full extent, the application became unresponsive to include any interaction with the map (panning, zooming, etc.) to the point where it had to be forcefully closed. I tried different TPK's, zooming levels and different symbols at different locations, but the behavior appeared to remain when over 900 symbols were top of each other at or near full extent.
0 Kudos
by Anonymous User
Not applicable
Original User: mbaird

Hi Carlos,

There is more to this than I'm seeing in my testing....

To test this, I generated a load of symbols:

     //add lots of symbols at random points
     for (int i=1; i<=4000;i++)
     {
      System.out.println("adding item " + i);
 
      Random randomGenerator = new Random();
      int xPos = randomGenerator.nextInt(10000);
      int yPos = randomGenerator.nextInt(10000);

         message.setID(UUID.randomUUID().toString());
         message.setProperty("_Type", "position_report");
         message.setProperty("_Action", "update");
         message.setProperty("_Control_Points", xPos + "," + yPos);
         message.setProperty("sic", "SFGPUH-----E---");
         message.setProperty("_WKID", "3857");
         message.setProperty("uniquedesignation", "Yellows");
         mgl.getMessageProcessor().processMessage(message);
     }

I then set up a mouseClicked listener on the map so I can find out where a user clicked.  I then pass this point into a getGraphicIDs which returns an array of clicked items (zoomed out this returns 4000 items).  I then select them all so I can see this visually.

Here is the code with loads of extra debug stuff:

         public void mouseClicked(MouseEvent arg0) {
         
          Point pt = map.toMapPoint(arg0.getX(), arg0.getY());
         
          System.out.println("map clicked at " + pt.getX() + "," + pt.getY());
         
          Layer[] layers = mgl.getLayers();
          System.out.println("there are layers : " + layers.length);
         
         
          GraphicsLayer gl = (GraphicsLayer) layers[1];
          System.out.println("gl layer = " + gl.getName());
         
          int[] all_graphics = gl.getGraphicIDs();
          System.out.println("total graphics = " + all_graphics.length);
         
          int[] ids = gl.getGraphicIDs((float)arg0.getX(),(float) arg0.getY(), 5, 4000);
         
          //Graphic gr = gl.getGraphic(ids[0]);
         
          if (ids.length > 0)
          {
         
           System.out.println("hit result with " + ids.length);
          
           gl.setSelectionIDs(ids, true);
          
          }
         }
        });

The last few lines of my debug window display the following:

...
adding item 3998
adding item 3999
adding item 4000
map clicked at 156543.03392799944,156543.0339280516
there are layers : 2
gl layer = position_reports
total graphics = 4001 - [this is because I've got another graphic added elsewhere in the app]
hit result with 4000

All the graphics are selected quick as a flash and it doesn't hang etc.

How does this differ to what you are doing?

Thanks

Mark
0 Kudos
CarlosColón-Maldonado
Frequent Contributor
Hi Mark,

It differs in that I am creating multiple types of symbols, e.g., single-point position report, single-point spot reports and multiple-point spot report symbols. This particularly occurs when zooming out after their creation before causing the mouse-click event. I wonder if it has something to do with my customized map overlay class that handles the multiple graphic layers the message group layer creates (I am tracking their creation and addition to map overlay only once to avoid duplicate effort).

 

for (GraphicsLayer layer : this.graphicsLayers) {

layer.clearSelection();

// Get the maximum number of graphics per layer within 5 pixels of the X and Y of

// the selected mouse click.

int[] hitGraphicsIDs = layer.getGraphicIDs(mouseEvent.getX(),

mouseEvent.getY(),

5,

layer.getNumberOfGraphics());

layer.setSelectionIDs(hitGraphicsIDs, true);

try {

for (int id : hitGraphicsIDs) {

this.graphicsQueue.put(layer.getGraphic(id));

}

} catch (InterruptedException e) {

// TODO Log

e.printStackTrace();

break;

}

}


I then get a list of Graphic objects out my queue to get the associated Message objects.
List<Pair<Message> selectedMgs = new ArrayList<Message>();

for (Graphic graph : graphics) {

MessageProcessor mp = messageGroupLayer.getMessageProcessor();

Message msg =  mp.createMessageFrom(graph);

if (msg != null)

selectedMgs.add(msg);

}


On a similar note, I wanted to have the Graphic brought to the front of adjacent ones using the graphics layer's BringToFront method. I then realized that it does not work well when there are other Graphic objects that are managed by another graphics layer. I looked around the API to see how I can bring the containing layer to the front as well and couldn't find it.
Graphic graph = messageProcessor().getGraphic(value.getID());

for (Layer layer : symbolLayer.getLayers()) {

GraphicsLayer gLayer = (GraphicsLayer)layer;

if ((gLayer.getGraphic(graph.getUid()) != null)) {

// TODO: Also bring layer to front!!

gLayer.bringToFront(graph.getUid());

}

}


Help?
0 Kudos
by Anonymous User
Not applicable
Original User: mbaird

Hi Carlos,

I'm putting together an application which better simulates your selection question which uses multiple point and line symbol graphics layers, so I'll get back to you on the selection question.

I will however answer your question about layer ordering.

At the moment there isn't a way of changing the draw order of the graphics layers in a MessageGroupLayer.  The moveToFront method you mention is for moving a graphic inside a graphics layer.  Sounds like you want to move an entire graphics layer to be above another.

We do however have what I believe to be sensible logic for drawing the graphics in the MessageGroupLayers:

- Polygon graphics layers are drawn at the bottom of the stack
- Line graphics layers are next (appearing over polygons)
- Followed by the point graphics layers on top.  There will be separate graphics layers for chemlights and position reports.
0 Kudos
CarlosColón-Maldonado
Frequent Contributor
Thanks for looking this up for me, Mark.

What you believe to be sensible logic for drawing the graphics makes perfect sense to me in that you don't want single point symbols to hide behind multi-point ones. I wouldn't change that, and I don't think anyone could argue that the functionality would be useful in any event otherwise. The difficulty in this comes in dealing with single-point symbols being drawn on different layers, e.g., position_report single-point symbol over a spot_report single-point symbol. Take for instance, the screenshots below that depict a group of selected symbols being brought to front:

[ATTACH=CONFIG]21506[/ATTACH]          [ATTACH=CONFIG]21507[/ATTACH]          [ATTACH=CONFIG]21508[/ATTACH]

In an area where only position_report type symbols were drawn and selected, the symbol being brought to front matches the symbol being previewed. Doing this in an area where spot_report and position_report type symbols are drawn:

[ATTACH=CONFIG]21509[/ATTACH]          [ATTACH=CONFIG]21510[/ATTACH]

The symbol drawn in the spot_report layer remains atop of any symbol regardless. Perhaps, someday, I may persuade you to consider the ability of ordering single-point layers of all types (or at least allowing it internally).
0 Kudos
by Anonymous User
Not applicable
Original User: mbaird

Hi Carlos,

I take your point about reordering the point graphics layers. 

Going back to the selection issue, I changed my code to add a few more symbols to include:

- point based position reports
- chem lights
- line based position reports

I then altered my map click event to dive into each of the graphics layers in the message group layer:

          //get layers in message group layer           Layer[] layers = mgl.getLayers();           System.out.println("there are layers : " + layers.length);                      //go through the layers in the message group layer to do a hit test on each one:           for(Layer gLayer : layers)           {            System.out.println("Layer name = " + gLayer.getName());            System.out.println("--------------------------------");                        //cast to graphics layer            GraphicsLayer gl = (GraphicsLayer) gLayer;                        int[] all_graphics = gl.getGraphicIDs();               System.out.println("total graphics = " + all_graphics.length);                              int[] ids = gl.getGraphicIDs((float)arg0.getX(),(float) arg0.getY(), 5, 4000);                              if (ids.length > 0)               {                               System.out.println("hit result with " + ids.length);                                gl.setSelectionIDs(ids, true);               }           }



I then zoomed out and clicked in the middle of the jumble of symbols and they were all selected.

I get the following output :

map clicked at -156543.03392799944,626172.1357119977 there are layers : 3 Layer name = position_reports_Lines -------------------------------- total graphics = 4001 hit result with 4000 Layer name = position_reports -------------------------------- total graphics = 4001 hit result with 4000 Layer name = chemlights -------------------------------- total graphics = 4000 hit result with 4000


As before the position reports are reporting 4001 items as I've got some created in another area of the world.

Mark
0 Kudos
CarlosColón-Maldonado
Frequent Contributor
Hi Mark,

I re-checked my code that gave me the impression this was happening and I'm afraid you've got me. It was a deadlock I caused in my code. I was using a blocking queue to collect the graphics that later got an array to collct their associated messages. It all worked once I changed the collection to a linked list. Sorry to have you research this unnecessarily. I guess we're even :cool:

Thanks for understanding my view on the point graphics layers.
0 Kudos