World Wind Forums

Go Back   World Wind Forums > WorldWind JAVA forums > Development Help

Development Help Help for building applications or diagnosing problems with WWJ

Reply
 
Thread Tools Display Modes
Old 07-31-2012, 04:58 PM   #1
sarahjor
Junior Member
 
Join Date: Jul 2012
Location: New York
Posts: 7
sarahjor is on a distinguished road
Default ConcurrentModificationException when modifying bounds

I created a class that uses MeasureTool to create and modify shapes on a new layer over WorldWind. The shapes (circle,ellipse,rectangle,square,polygon ) are created as the shapes themselves using MeasureTool and are then saved as as bounds using the getPositions() method in MeasureTool.

When modifying circles and ellipses though, I get a concurrentmodificationexception about 50% of the time when trying to move a point. It does not seem to be from my code - but from WorldWinds.

Quote:
java.util.ConcurrentModificationExceptio n
at java.util.ArrayList$Itr.checkForComodifi cation(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.j ava:791)
at gov.nasa.worldwind.render.AbstractSurfac eShape.generateIntermediateLocations(Abs tractSurfaceShape.java:975)
at gov.nasa.worldwind.render.SurfacePolygon .createGeometry(SurfacePolygon.java:173)
at gov.nasa.worldwind.render.AbstractSurfac eShape.getCachedGeometry(AbstractSurface Shape.java:797)
at gov.nasa.worldwind.render.AbstractSurfac eShape.determineActiveGeometry(AbstractS urfaceShape.java:677)
at gov.nasa.worldwind.render.AbstractSurfac eShape.doDrawGeographic(AbstractSurfaceS hape.java:609)
at gov.nasa.worldwind.render.AbstractSurfac eShape.drawGeographic(AbstractSurfaceSha pe.java:542)
at gov.nasa.worldwind.render.AbstractSurfac eObject.drawOrderedRenderable(AbstractSu rfaceObject.java:601)
at gov.nasa.worldwind.render.AbstractSurfac eObject.render(AbstractSurfaceObject.jav a:274)
at gov.nasa.worldwind.render.SurfaceObjectT ileBuilder.updateTile(SurfaceObjectTileB uilder.java:554)
at gov.nasa.worldwind.render.SurfaceObjectT ileBuilder.updateTiles(SurfaceObjectTile Builder.java:489)
at gov.nasa.worldwind.render.SurfaceObjectT ileBuilder.buildTiles(SurfaceObjectTileB uilder.java:345)
at gov.nasa.worldwind.AbstractSceneControll er.buildCompositeSurfaceObjects(Abstract SceneController.java:851)
at gov.nasa.worldwind.AbstractSceneControll er.preRenderOrderedSurfaceRenderables(Ab stractSceneController.java:753)
at gov.nasa.worldwind.AbstractSceneControll er.preRender(AbstractSceneController.jav a:440)
at gov.nasa.worldwind.BasicSceneController. doRepaint(BasicSceneController.java:24)
at gov.nasa.worldwind.AbstractSceneControll er.repaint(AbstractSceneController.java: 256)
at gov.nasa.worldwind.WorldWindowGLAutoDraw able.doDisplay(WorldWindowGLAutoDrawable .java:403)
at gov.nasa.worldwind.WorldWindowGLAutoDraw able.display(WorldWindowGLAutoDrawable.j ava:283)
at com.sun.opengl.impl.GLDrawableHelper.dis play(GLDrawableHelper.java:78)
at javax.media.opengl.GLJPanel$Updater.disp lay(GLJPanel.java:1056)
at com.sun.opengl.impl.GLDrawableHelper.dis play(GLDrawableHelper.java:78)
at com.sun.opengl.impl.GLPbufferImpl$Displa yAction.run(GLPbufferImpl.java:222)
at com.sun.opengl.impl.GLDrawableHelper.inv okeGL(GLDrawableHelper.java:194)
at com.sun.opengl.impl.GLPbufferImpl.maybeD oSingleThreadedWorkaround(GLPbufferImpl. java:208)
at com.sun.opengl.impl.GLPbufferImpl.displa y(GLPbufferImpl.java:88)
at javax.media.opengl.GLJPanel.paintCompone nt(GLJPanel.java:659)
at javax.swing.JComponent.paint(JComponent. java:1054)
at javax.swing.JComponent.paintToOffscreen( JComponent.java:5221)
at javax.swing.RepaintManager$PaintManager. paintDoubleBuffered(RepaintManager.java: 1482)
at javax.swing.RepaintManager$PaintManager. paint(RepaintManager.java:1413)
at javax.swing.RepaintManager.paint(Repaint Manager.java:1206)
at javax.swing.JComponent._paintImmediately (JComponent.java:5169)
at javax.swing.JComponent.paintImmediately( JComponent.java:4980)
at javax.swing.RepaintManager.paintDirtyReg ions(RepaintManager.java:770)
at javax.swing.RepaintManager.paintDirtyReg ions(RepaintManager.java:728)
at javax.swing.RepaintManager.prePaintDirty Regions(RepaintManager.java:677)
at javax.swing.RepaintManager.access$700(Re paintManager.java:59)
at javax.swing.RepaintManager$ProcessingRun nable.run(RepaintManager.java:1621)
at java.awt.event.InvocationEvent.dispatch( InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(Ev entQueue.java:701)
at java.awt.EventQueue.access$000(EventQueu e.java:102)
at java.awt.EventQueue$3.run(EventQueue.jav a:662)
at java.awt.EventQueue$3.run(EventQueue.jav a:660)
at java.security.AccessController.doPrivile ged(Native Method)
at java.security.ProtectionDomain$1.doInter sectionPrivilege(ProtectionDomain.java:7 6)
at java.awt.EventQueue.dispatchEvent(EventQ ueue.java:671)
at java.awt.EventDispatchThread.pumpOneEven tForFilters(EventDispatchThread.java:244 )
at java.awt.EventDispatchThread.pumpEventsF orFilter(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEventsF orHierarchy(EventDispatchThread.java:151 )
at java.awt.EventDispatchThread.pumpEvents( EventDispatchThread.java:147)
at java.awt.EventDispatchThread.pumpEvents( EventDispatchThread.java:139)
at java.awt.EventDispatchThread.run(EventDi spatchThread.java:97)
When clicking save after the initial placement of the shape (i.e using MeasureTool.SHAPE_CIRCLE), the following code is called:

Code:
                // create or modify the bounds
                if (activeBounds == null)
                {
                    activeBounds = BoundUtils.createManagedBounds(boundsName.getText(), getMeasureTool().getPositions());

                }
                else
                {
                    activeBounds = BoundUtils.modifyManagedBounds(activeBounds, boundsName.getText(), getMeasureTool().getPositions());
                }
I know I'm not good at explaining, so if more information is needed please let me know.
sarahjor is offline   Reply With Quote
Old 08-06-2012, 07:52 PM   #2
pabercrombie
WW Dev. Team
 
Join Date: Sep 2010
Location: Boston, MA, USA
Posts: 325
pabercrombie is on a distinguished road
Default

You need to modify the bounds on the Event Dispatch Thread. Using Swing, you can do this using the SwingUtilities.invokeLater:

Code:
SwingUtilities.invokeLater(new Runnable()
    {
        public void run()
        {
             // Modify bounds here
        }
    });
pabercrombie is offline   Reply With Quote
Old 08-06-2012, 08:49 PM   #3
sarahjor
Junior Member
 
Join Date: Jul 2012
Location: New York
Posts: 7
sarahjor is on a distinguished road
Default

I've tried to modify the bounds on the Event Dispatch Thread like you said, but the problem persists.

Is it possible that it has something to do with WW's code?

I frequently get this exception as well:

Jul 30, 2012 10:59:32 AM gov.nasa.worldwind.layers.RenderableLaye r doPreRender
SEVERE: Exception while pre-rendering Renderable
sarahjor is offline   Reply With Quote
Old 08-07-2012, 11:22 PM   #4
pabercrombie
WW Dev. Team
 
Join Date: Sep 2010
Location: Boston, MA, USA
Posts: 325
pabercrombie is on a distinguished road
Default

You must somehow be modifying the bounds off of the EDT. That's the only way a ConcurrentModificationException could happen. The exception in preRender is probably the same exception (the ConcurrentModificationException is thrown during preRendering), but you could put a break point or log statement in RenderableLayer.doPreRender to confirm that.

Can you provide a simple example that demonstrates the problem?
pabercrombie is offline   Reply With Quote
Old 08-09-2012, 07:23 PM   #5
sarahjor
Junior Member
 
Join Date: Jul 2012
Location: New York
Posts: 7
sarahjor is on a distinguished road
Default

A log already exists in RenderableLayer.doPreRender, which is where it's coming from.

Here is some of the code from the class that creates and modifies bounds. The exceptions only occur when there are a lot of points (e.g., compared to squares which have 5 points)

Maybe there's an alternative way to do this to avoid the exception?

Code:
public class ApplicationMeasureToolPanel extends BaseMeasureToolPanel
{
	/**
	 * Note: BaseMeasureToolPanel is an SWT control panel for WorldWind's MeasureTool. Based on NASA's
	 * MeasureToolPanel.
	 */
    // the active Bounds is the one that we're currently editing
    private Bounds activeBounds = null;

    private Text boundsName;
    private Label messageLabel1;
    private Label messageLabel2;

    public ApplicationMeasureToolPanel(Composite parent, WorldWindowContainer worldWindow,
            final MeasureTool measureTool)
    {
        super(parent, worldWindow, measureTool);
    }

    /**
     * Shape types that are usable by MeerCAT's Bounds Tool
     */
    @Override
    protected void hookShapeTypes()
    {
        getShapeTypes().put("Polygon", MeasureTool.SHAPE_POLYGON);
        getShapeTypes().put("Circle", MeasureTool.SHAPE_CIRCLE);
        getShapeTypes().put("Ellipse", MeasureTool.SHAPE_ELLIPSE);
        getShapeTypes().put("Square", MeasureTool.SHAPE_SQUARE);
        getShapeTypes().put("Quad", MeasureTool.SHAPE_QUAD);
    }

    /**
     * Set the bounds to be modified upon pressing Save
     */
    public void setActiveBounds(final Bounds bounds)
    {
        activeBounds = bounds;
        ARKUtils.getDisplay().asyncExec(new Runnable()
        {
            @Override
            public void run()
            {
                // show the points if there are any
                if (activeBounds.hasPoints())
                {
                    getMeasureTool().setPositions(activeBounds.getPositions());
                    // setPositions() makes the measure tool switch to polygon
                    // mode. Change the selected type in the dropdown so the
                    // user doesn't get surprised
                    getShapeCombo().setText("Polygon");
                }
                else
                    getMeasureTool().clear();

                // show the name
                boundsName.setText(activeBounds.getName());
            }
        });
    }

    /**
     * Reset any part of the UI that this specific subclass handles
     */
    @Override
    public void resetMeasureTool(boolean suppressEvents)
    {
        // clear the active Location
        activeBounds = null;

        // clear the name field
        ARKUtils.getDisplay().asyncExec(new Runnable()
        {
            @Override
            public void run()
            {
                // check if the tool is disposed first because we
                // also reset upon disposal
                if (!getControl().isDisposed())
                {
                    messageLabel1.setText("");
                    messageLabel2.setText("");
                    boundsName.setText("");
                }
            }
        });

        // parent handles the rest
        super.resetMeasureTool(suppressEvents);
    }

    /**
     * Provide options for saving Bounds to the database
     */
    @Override
    protected void hookControls()
    {
        createSetupGroup();
        createMetricGroup();
        createStartStopGroup();
        createSaveGroup();
        createMessageGroup();
        createHelpGroup();
    }
    
    /**
     * Provide options to set the Bounds name and set the shape type
     */
    private void createSetupGroup()
    {
        Composite parent = getControl();

        // Setup Group
        Group setupGroup = new Group(parent, SWT.NONE);
        setupGroup.setText("Setup Bounds");
        setupGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
        setupGroup.setLayout(new GridLayout(2, false));

        Label nameLabel = new Label(setupGroup, SWT.NONE);
        nameLabel.setText("Name");
        nameLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 1, 1));

        boundsName = new Text(setupGroup, SWT.BORDER);
        boundsName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 1, 1));
        
        // add the shape controls from the parent class
        createShapeControls(setupGroup);
    }

    /**
     * Provide options to save the Bounds to the database
     */
    private void createSaveGroup()
    {
        Composite parent = getControl();

        // Save Group
        Composite saveGroup = new Composite(parent, SWT.NONE);
        saveGroup.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
        saveGroup.setLayout(new GridLayout(2, true));

        final Button cancelButton = new Button(saveGroup, SWT.NONE);
        cancelButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 1, 1));
        cancelButton.setText("Cancel");

        final Button saveButton = new Button(saveGroup, SWT.NONE);
        saveButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true, 1, 1));
        saveButton.setText("Save");

        saveGroup.getShell().setDefaultButton(saveButton);

        // handle the cancel button
        cancelButton.addListener(SWT.Selection, new Listener()
        {
            @Override
            public void handleEvent(Event event)
            {
                resetMeasureTool(false);

                // close the tool
                MeerCatEventHelper.fireEvent(MeerCatEventManagerFactory.BOUNDS_TOOL, this,
                        new BoundsToolEventArgs(BoundsToolAction.HIDE, null));
            }
        });
        
        // handle the save button
        saveButton.addListener(SWT.Selection, new Listener()
        {
            @Override
            public void handleEvent(Event event)
            {
                if (getMeasureTool().getPositions().isEmpty())
                {
                    messageLabel1.setText("No bounds provided.");
                    messageLabel2.setText("Draw some points.");
                    return;
                }

                // make sure name is not null
                if (boundsName.getText().isEmpty())
                {
                    messageLabel1.setText("No name provided.");
                    messageLabel2.setText("Choose a name.");
                    return;
                }

                // make sure name is not taken
                IMeerCATOrmService ormService = MeerCATOrmServiceFactory.createMeerCatOrmService();
                boolean exists = ormService.boundsExistsWithName(boundsName.getText());
                ormService.close();

                if (activeBounds == null && exists)
                {
                    messageLabel1.setText("Name already exists.");
                    messageLabel2.setText("Choose a different name.");
                    return;
                }

                // create or modify the bounds
                if (activeBounds == null)
                {
                    activeBounds = BoundUtils.createManagedBounds(boundsName.getText(),
                            getMeasureTool().getPositions());
                }
                else
                {
                    activeBounds = BoundUtils.modifyManagedBounds(activeBounds,
                            boundsName.getText(), getMeasureTool().getPositions());
                }

                resetMeasureTool(false);

                // close the tool
                MeerCatEventHelper.fireEvent(MeerCatEventManagerFactory.BOUNDS_TOOL, this,
                        new BoundsToolEventArgs(BoundsToolAction.HIDE, null));

                // tell the bounds view to refresh
                MeerCatEventHelper.fireEvent(MeerCatEventManagerFactory.BOUNDS_UPDATE, this,
                        new EventArgs());
            }
        });
    }

    /**
     * Verify that the active bounds are managed. Clear if not.
     */
    public void verifyBounds()
    {
        // see if the active location still exists
        if (activeBounds != null)
        {
            IMeerCATOrmService ormService = MeerCATOrmServiceFactory.createMeerCatOrmService();
            Bounds managedBounds = ormService.getEntityManagedVersion(activeBounds);
            // clear the tool if it doesn't exist
            if (managedBounds == null)
                resetMeasureTool(false);
        }
    }
}
sarahjor is offline   Reply With Quote
Old 08-09-2012, 07:25 PM   #6
sarahjor
Junior Member
 
Join Date: Jul 2012
Location: New York
Posts: 7
sarahjor is on a distinguished road
Default

Instead of modifying the bounds myself, I let WorldWind modify it for me since the code already exists. All the above code does is create the shapes, and save them as polygons.
sarahjor is offline   Reply With Quote
Old 08-10-2012, 06:02 PM   #7
pabercrombie
WW Dev. Team
 
Join Date: Sep 2010
Location: Boston, MA, USA
Posts: 325
pabercrombie is on a distinguished road
Default

Are you using the SWT/AWT bridge to use World Wind in an SWT app? I see that you're using asyncExec to manipulate the bounds. This will run the update on the SWT event thread, but World Wind is rendering on the AWT event thread (as indicated by the stack trace in your first post). Have you tried using SwingUtilities.invokeLater to run the bounds updates on the AWT event thread?
pabercrombie is offline   Reply With Quote
Old 08-13-2012, 02:51 PM   #8
sarahjor
Junior Member
 
Join Date: Jul 2012
Location: New York
Posts: 7
sarahjor is on a distinguished road
Default

Yes, I'm using the SWT/AWT bridge, and I've also tried using SwingUtilities.invokeLater to run the bounds updates... it only causes the exception to occur more frequently.
sarahjor is offline   Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may post new threads
You may post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Calculating bounds of map objects incubus Technical Support 2 06-09-2012 06:42 AM
Occassional index out of bounds in setting markers jas511 Bug Reports 12 06-03-2011 12:57 AM
Modifying LineBuilder Unregistered Development Help 1 06-26-2009 01:27 AM
Modifying SurfaceTileRenderer.renderTiles to avoid multitexturing Unregistered Development Help 0 05-15-2009 06:05 PM
Metes and Bounds description:utility tommoran Add-ons & Scripts 0 07-07-2006 08:55 PM


All times are GMT +1. The time now is 10:52 PM.


Powered by vBulletin® Version 3.7.1
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.