Thoughts on trying to speed up a map display app

C

Charles Packer

Here's a graphics problem, the solution to which is conceptually simple.
The goal is to speed up the refreshing of a map after changing the
geographic vector data from which it is developed. What's obscure to me
is how to go from the ingredients provided in the Java API to an actual
recipe.

In an application that displays a map with overlays of different types
of data as individual layers -- state boundaries, airports, flight tracks
of aircraft, etc. we want to be able to change the data in a layer or turn
one off or on without having to redraw all the layers each time. From a Google
search of Java newsgroups I see that related forms of this question have
come up before, but with no decisive answers (in several instances, no
followups at all). Therefore I've expended extra effort in this rather
lengthy query to try to be clear about what the issues are.

We're using an open source product, OpenMap, that takes several seconds
to do this redrawing of all the layers. When a user does a pan or a zoom,
OR makes a change to the data in any one layer, OpenMap cycles through
all the active layers. Each layer extends JComponent and overrides the
"paint" method to draw its data into the graphics context. Layer order
can be chosen by the user such that layers showing opaque things, like
countries and water, are drawn first, and then lines and points of interest
are drawn last. For a pan or a zoom, of course, the positions of all these
have to be recomputed first, but the amount of time that this computation takes
is _insignificant_ compared to the paint operation.

Note that the parameterized paint method, for restricting drawing to a subset
of the window, is of little use here, since typically the data of interest
in any one layer are scattered all over the map.

From a Java tip page I learned that I could override "update" instead of
paint for incremental drawing, and this would avoid repaintng the whole
window. However, I discovered that this method wasn't even called (!) when I
coded an override of it in my test class.

Conceptually, what I want to do is this: Draw the data vector of each layer
to its own invisible pixel buffer. Then, where I actually want to see the
contents of one or more layers, combine them quickly into one visible image.
Given that each layer's pixel buffer has identical dimensions and covers the
same geographic area, the combining would involve simple pixel-by-pixel
overlay logic. For example, to turn off one of the layers, simply refresh
the visible image with all the pixel buffers of all the layers _except_ the
one I want to turn off.

I'm disappointed that Java hasn't solved the problem I had with Motif in
another life: there's a Grand Disconnect between drawing vectors and pixel
images. I can create a line by a drawing operation into a graphics
"context", which is...well, whatever it is, once my line is drawn, I can't
change its color...I can't do anything to it; it may be visible...but it's
out of reach. I can't save it as pixels and simply flip it back to the
screen later without redrawing it. On the other hand, I can create an array
that can become a pixel image...but how do I get a line into it in the first
place? Answer: I have to reinvent the wheel and write a drawing routine. Or
so it seems...where's the bridge between these two domains?
 
M

Michiel Konstapel

Conceptually, what I want to do is this: Draw the data vector of each
layer
to its own invisible pixel buffer. Then, where I actually want to see the
contents of one or more layers, combine them quickly into one visible
image.
Given that each layer's pixel buffer has identical dimensions and covers
the
same geographic area, the combining would involve simple pixel-by-pixel
overlay logic. For example, to turn off one of the layers, simply refresh
the visible image with all the pixel buffers of all the layers _except_
the
one I want to turn off.

So, why not just create a bunch of offscreen images
(java.awt.image.BufferedImage), paint your vector data on them, and blit
them to the screen on demand? If you use transparency, you wouldn't even
need "overlay logic", you could just paint them on top each other in the
right order.
HTH,
Michiel
 
C

Charles Packer

Michiel Konstapel said:
So, why not just create a bunch of offscreen images
(java.awt.image.BufferedImage), paint your vector data on them, and blit
them to the screen on demand? If you use transparency, you wouldn't even
need "overlay logic", you could just paint them on top each other in the
right order.

But how do I draw a line in a BufferedImage? In the Java reference
book on my desk, there is this sentence: "All graphics are drawn
relative to a window." I need to know how to connect all those useful
functions in the Graphics class to a BufferedImage instead.
 
W

William Brogden

But how do I draw a line in a BufferedImage? In the Java reference
book on my desk, there is this sentence: "All graphics are drawn
relative to a window." I need to know how to connect all those useful
functions in the Graphics class to a BufferedImage instead.

Look at the BufferedImage API.
See the method createGraphics - note the comment
"Creates a Graphics2D which can be used to draw into the BufferedImage"
 
M

Michiel Konstapel

But how do I draw a line in a BufferedImage? In the Java reference
book on my desk, there is this sentence: "All graphics are drawn
relative to a window." I need to know how to connect all those useful
functions in the Graphics class to a BufferedImage instead.

BufferedImage.getGraphics() and paint away :)
You might want to cast it to Graphics2D to use its more advanced painting
operations.
TH,
Michiel
 
T

The Ghost In The Machine

In comp.lang.java.advocacy, Charles Packer
<[email protected]>
wrote
But how do I draw a line in a BufferedImage? In the Java reference
book on my desk, there is this sentence: "All graphics are drawn
relative to a window." I need to know how to connect all those useful
functions in the Graphics class to a BufferedImage instead.

This should work:

public void paintOnImage(java.awt.image.BufferedImage bim)
{
java.awt.Graphics g = bim.createGraphics();
paint(g);
g.dispose();
}

The dispose() may or may not be required. The paint() method is
as specified in java.awt.Component. There's no equivalent here
to XFlush() or XSync(), and I don't know how well this would
work with paintComponent(g) on a Swing JComponent composite object.
However, this works for simple widgets such as a text label, and of
course one can simply derive from Component, implementing one's own
paint() method.
 
T

Tim Tyler

Charles Packer said:
In the Java reference book on my desk, there is this sentence:
"All graphics are drawn relative to a window."

A misleading sentence at best - but /maybe/ the context might rescue it
a little.

Still - it might be worth naming and shaming the book.
 
C

Charles Packer

Tim Tyler said:
A misleading sentence at best - but /maybe/ the context might rescue it
a little.

Still - it might be worth naming and shaming the book.


The book is so old, if I named it, I'd end up shaming my employer
by implication for not providing us with up-to-date materials!
After I posted that quote, I did a Google search on the exact string
"draw into +a BufferedImage" and there were 17 hits, one of which was
a nice tutorial:
http://www.dickbaldwin.com/java/Java316.htm
....that quotes another reference as saying "Anything you can draw on
the screen, you can draw into a BufferedImage." As the several followups
pointed out, BufferedImage has a method createGraphics(), and that is the
"bridge" I was looking for. Thanks to everybody for your help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top