Home » Eclipse Projects » GEF » Injecting custom UpdateManagers
Injecting custom UpdateManagers [message #182936] |
Mon, 30 May 2005 18:47 |
Eclipse User |
|
|
|
Originally posted by: kvdijken.tiscali.nl
Hi GEF people,
I am about to enter a new feature request for GEF, but before that I would
like to know if what I write in that request is right. I am using my own
UpdateManager which performs much better than DeferredUpdateManager on large
datasets of which many of the Figures are far away from the origin of the
coordinate space. I inject my own UpdateManager in the LightWeightSystem as
follows:
// Next piece of code is very dirty, but necessary because a cleaner
// way to inject a custom UpdateManager is not available.
final FigureCanvas figCanvas = (FigureCanvas) graphicalViewer
.getControl();
LightweightSystem lws = figCanvas.getLightweightSystem();
lws.setUpdateManager(new MinimizingUpdateManager());
lws.getUpdateManager().setGraphicsSource(
new BufferedGraphicsSource(figCanvas));
lws.getUpdateManager().addUpdateListener(new UpdateListener() {
public void notifyPainting(Rectangle damage,
java.util.Map dirtyRegions) {
}
public void notifyValidating() {
if (!figCanvas.isDisposed()) {
ScrollPaneSolver.Result result;
result = ScrollPaneSolver.solve(new Rectangle(figCanvas
.getBounds()).setLocation(0, 0), getViewport(),
figCanvas.getHorizontalScrollBarVisibility(),
figCanvas.getVerticalScrollBarVisibility(),
figCanvas.computeTrim(0, 0, 0, 0).width,
figCanvas
.computeTrim(0, 0, 0, 0).height);
if (figCanvas.getHorizontalBar().getVisible() !=
result.showH)
figCanvas.getHorizontalBar().setVisible(result.showH);
if (figCanvas.getVerticalBar().getVisible() !=
result.showV)
figCanvas.getVerticalBar().setVisible(result.showV);
}
}
});
// End of dirty code.
I think this is very dirty code, but (I think) necessary because I could not
find any other way to get it working.
My question is: is the above code necessary, or is there some better way to
inject my own UpdateManager.
The two UpdateManager's (ClusteringUpdateManager and
MinimizingUpdateManager) I am using are as follows. I had to copy much of
the source from DefferedUpdateManager because I could not get at the private
fields I needed.
public class ClusteringUpdateManager extends UpdateManager {
private boolean updating;
private GraphicsSource graphicsSource;
private IFigure root;
private boolean updateQueued = false;
private List invalidFigures = new ArrayList();
/**
* List of dirty areas, translated to absolute (canvas) coordinates.
*/
protected List dirtyRegions = new ArrayList();
/**
* The union of all dirty regions.
*/
private Rectangle dirtyUnion;
/**
* Map of all dirty figures and their unioned dirty regions.
*/
private Map dirtyFigures = new HashMap();
/**
* List of dirty clusters which are being processed at this moment.
*/
List work;
/**
* Constructs a new DererredUpdateManager with the given GraphicsSource.
*
* @param gs
* the graphics source
*/
public ClusteringUpdateManager(GraphicsSource gs) {
setGraphicsSource(gs);
}
/**
* Empty constructor.
*/
public ClusteringUpdateManager() {
}
/**
* Calls {@link DeferredUpdateManager#performUpdate()}.
*/
protected class UpdateRequest implements Runnable {
/**
* Calls {@link DeferredUpdateManager#performUpdate()}.
*/
public void run() {
performUpdate();
}
}
/**
* Adds a dirty region (defined by the rectangle <i>x, y, w, h </i>) to
the
* update queue. If the figure isn't visible or either the width or
height
* are 0, the method returns without queueing the dirty region.
*
* @param figure
* the figure that contains the dirty region
* @param x
* the x coordinate of the dirty region
* @param y
* the y coordinate of the dirty region
* @param w
* the width of the dirty region
* @param h
* the height of the dirty region
*/
public synchronized void addDirtyRegion(IFigure figure, int x, int y,
int w, int h) {
if (!figure.isShowing())
return;
if (w == 0 || h == 0)
return;
Rectangle rect = new Rectangle(x, y, w, h);
figure.translateToAbsolute(rect);
// First check if this region is not in the queue to be processed
// allready. This may occurr when during a repaint new dirty regions
// are added. When we discover that this happens for a dirty region
// which is still on the todo list of dirty regions to be repainted,
// we do not have to add it to the new list of dirty regions.
// The strategy employed is a simple one, try to find any of the
// clusters which completely contains the current dirty region. If
// such a cluster is found, there is no need to add it to the new
// dirty regions list.
// This strategy may be refined to find parts of the
// current dirty regions which are allready in the todo list and
// subtract them from the current dirty region. Finally make squares
// of the remaining dirty area and add those squares to the dirty
// regions list. This requires an algorithm to break up a polgon
with
// 90 degree angles into its contributing squares. This could be a
// non trivial task.
if (work != null)
for (Iterator iter = work.iterator(); iter.hasNext();) {
Rectangle cluster = (Rectangle) iter.next();
if(cluster.contains(rect))
return;
}
dirtyRegions.add(rect);
// Now fill the structures for the firePainting notification.
rect = (Rectangle) dirtyFigures.get(figure);
if (rect == null) {
rect = new Rectangle(x, y, w, h);
dirtyFigures.put(figure, rect);
} else
rect.union(x, y, w, h);
queueWork();
}
/**
* Adds the given figure to the update queue. Invalid figures will be
* validated before the damaged regions are repainted.
*
* @param f
* the invalid figure
*/
public synchronized void addInvalidFigure(IFigure f) {
if (invalidFigures.contains(f))
return;
queueWork();
invalidFigures.add(f);
}
/**
* Returns a Graphics object for the given region.
*
* @param region
* the region to be repainted
* @return the Graphics object
*/
protected Graphics getGraphics(Rectangle region) {
if (graphicsSource == null)
return null;
return graphicsSource.getGraphics(region);
}
/**
* Adds the given exposed region to the update queue and then performs
the
* update.
*
* @param exposed
* the exposed region
*/
public synchronized void performUpdate(Rectangle exposed) {
addDirtyRegion(root, exposed);
performUpdate();
}
/**
* Performs the update. Validates the invalid figures and then repaints
the
* dirty regions.
*
* @see #validateFigures()
* @see #repairDamage()
*/
public synchronized void performUpdate() {
if (isDisposed() || updating)
return;
updating = true;
try {
validateFigures();
updateQueued = false;
repairDamage();
} finally {
updating = false;
}
}
/**
* Posts an {@link UpdateRequest}using {@link
Display#asyncExec(Runnable)}.
* If work has already been queued, a new request is not needed.
*/
protected void queueWork() {
if (!updateQueued) {
Display.getCurrent().asyncExec(new UpdateRequest());
updateQueued = true;
}
}
/**
* Releases the graphics object, which causes the GraphicsSource to
flush.
*
* @param graphics
* the graphics object
*/
protected void releaseGraphics(Rectangle damage) {
graphicsSource.flushGraphics(damage);
}
/**
* Iterates over all dirty regions and clusters them into a smaller
number
* of dirty regions (the so-called clusters) which cover all original
dirty
* regions. What defines 'smaller' is up to the implementation, as long
as
* the original dirty regions are covered by the clusters.
*
* @return List of dirty clusters.
*/
protected List clusterDirtyRegions() {
List clusters = new ArrayList();
for (Iterator iter = dirtyRegions.iterator(); iter.hasNext();) {
Rectangle cluster = ((Rectangle) iter.next()).getCopy();
clusters.add(cluster);
}
// For every cluster, see if it can be clustered with any
// other cluster. Continue as long as there have been any
// succesfull clusterings.
boolean clusteredAny;
do {
clusteredAny = false;
for (int i = 0; i < clusters.size() - 1; i++) {
Rectangle cluster = (Rectangle) clusters.get(i);
// See if this cluster can be combined with any
// other cluster in the rest of the list.
for (int j = i + 1; j < clusters.size();) {
Rectangle candidate = (Rectangle) clusters.get(j);
if (candidate.intersects(cluster)) {
// Yes, this clusters overlap with the first
// cluster, combine them into the first cluster.
cluster.union(candidate);
// Remove this cluster, as it is now included
// in the first cluster.
clusters.remove(j);
clusteredAny = true;
} else
// No, this clusters could not be combined with
// the other cluster, try the next one.
j++;
}
}
} while (clusteredAny);
return clusters;
}
/**
* Repaints the dirty regions on the update queue and calls
* {@link UpdateManager#firePainting(Rectangle, Map)}, unless there are
no
* dirty regions.
*/
protected void repairDamage() {
// This is a list of Rectangles. It comprises all damaged areas
// which need to be repainted.
work = clusterDirtyRegions();
try {
dirtyRegions.clear();
// Het principe van firePainting() is in tegenspraak met het
// principe
// van ClusteringUpdateManager. ClusteringUpdateManager laat
// meerdere
// dirty regions per figure toe, firePainting verwacht een 1:1
// mapping
// van dirty regions en figures.
// Oplossing: houdt ook een oude stijl dirtyRegions bij voor
gebruik
// in firePainting.
firePainting(dirtyUnion, dirtyFigures);
dirtyUnion = null;
dirtyFigures.clear();
// Now repaint all clusters.
for (Iterator iter = work.iterator(); iter.hasNext();) {
final Rectangle cluster = (Rectangle) iter.next();
final Graphics graphics = getGraphics(cluster);
if (graphics != null) {
// Figures may originate in several plugins.
// Perform a safe paint operation.
new SafeRunnable() {
public void run() {
root.paint(graphics);
releaseGraphics(cluster);
}
}.run();
}
}
} finally {
work = null;
}
}
/**
* Sets the graphics source.
*
* @param gs
* the graphics source
*/
public void setGraphicsSource(GraphicsSource gs) {
graphicsSource = gs;
}
/**
* Sets the root figure.
*
* @param figure
* the root figure
*/
public void setRoot(IFigure figure) {
root = figure;
}
/**
* Validates the invalid figures on the update queue and calls
* {@link UpdateManager#fireValidating()}unless there are no invalid
* figures.
*/
protected void validateFigures() {
if (invalidFigures.isEmpty())
return;
try {
IFigure fig;
fireValidating();
for (int i = 0; i < invalidFigures.size(); i++) {
fig = (IFigure) invalidFigures.get(i);
invalidFigures.set(i, null);
fig.validate();
}
} finally {
invalidFigures.clear();
}
}
}
public class MinimizingUpdateManager extends ClusteringUpdateManager {
/*
* (non-Javadoc)
*
* @see
nl.juncus.spatial.display.ClusteringUpdateManager#clusterDir tyRegions()
*/
protected List clusterDirtyRegions() {
List clusters = new ArrayList();
for (Iterator iter = dirtyRegions.iterator(); iter.hasNext();) {
Rectangle cluster = ((Rectangle) iter.next()).getCopy();
clusters.add(cluster);
}
// For every cluster, see if it can be clustered with any
// other cluster. Continue as long as there have been any
// succesfull clusterings.
boolean clusteredAny;
do {
clusteredAny = false;
for (int i = 0; i < clusters.size() - 1; i++) {
// System.out.println(i);
Rectangle cluster = (Rectangle) clusters.get(i);
// See if this cluster can be combined with any
// other cluster in the rest of the list.
for (int j = i + 1; j < clusters.size();) {
Rectangle candidate = (Rectangle) clusters.get(j);
if (candidate.intersects(cluster)) {
// Yes, this clusters overlap with the first
// cluster, combine them into the first cluster.
double areaCluster = (double) cluster.height
* (double) cluster.width;
double areaCandidate = (double) candidate.height
* (double) candidate.width;
Rectangle union = cluster.getUnion(candidate);
double areaUnion = (double) union.height
* (double) union.width;
if (areaUnion <= areaCluster + areaCandidate) {
cluster.union(candidate);
// Remove this cluster, as it is now included
// in the first cluster.
clusters.remove(j);
clusteredAny = true;
} else
j++;
} else
// No, this clusters could not be combined with
// the other cluster, try the next one.
j++;
}
}
} while (clusteredAny);
return clusters;
}
}
I must admit that I did not check if all this is still necessary in in GEF
3.1, I developed this on 3.0.
Koen van Dijken
|
|
|
Re: Injecting custom UpdateManagers [message #182948 is a reply to message #182936] |
Mon, 30 May 2005 22:06 |
Pratik Shah Messages: 1077 Registered: July 2009 |
Senior Member |
|
|
What are you trying to do?
"Koen van Dijken" <kvdijken@tiscali.nl> wrote in message
news:d7fnda$g6$1@news.eclipse.org...
> Hi GEF people,
>
> I am about to enter a new feature request for GEF, but before that I would
> like to know if what I write in that request is right. I am using my own
> UpdateManager which performs much better than DeferredUpdateManager on
large
> datasets of which many of the Figures are far away from the origin of the
> coordinate space. I inject my own UpdateManager in the LightWeightSystem
as
> follows:
>
> // Next piece of code is very dirty, but necessary because a
cleaner
> // way to inject a custom UpdateManager is not available.
> final FigureCanvas figCanvas = (FigureCanvas) graphicalViewer
> .getControl();
> LightweightSystem lws = figCanvas.getLightweightSystem();
> lws.setUpdateManager(new MinimizingUpdateManager());
> lws.getUpdateManager().setGraphicsSource(
> new BufferedGraphicsSource(figCanvas));
> lws.getUpdateManager().addUpdateListener(new UpdateListener() {
> public void notifyPainting(Rectangle damage,
> java.util.Map dirtyRegions) {
> }
>
> public void notifyValidating() {
> if (!figCanvas.isDisposed()) {
> ScrollPaneSolver.Result result;
> result = ScrollPaneSolver.solve(new
Rectangle(figCanvas
> .getBounds()).setLocation(0, 0),
getViewport(),
> figCanvas.getHorizontalScrollBarVisibility(),
> figCanvas.getVerticalScrollBarVisibility(),
> figCanvas.computeTrim(0, 0, 0, 0).width,
> figCanvas
> .computeTrim(0, 0, 0, 0).height);
> if (figCanvas.getHorizontalBar().getVisible() !=
> result.showH)
>
figCanvas.getHorizontalBar().setVisible(result.showH);
> if (figCanvas.getVerticalBar().getVisible() !=
> result.showV)
>
figCanvas.getVerticalBar().setVisible(result.showV);
> }
> }
> });
> // End of dirty code.
>
> I think this is very dirty code, but (I think) necessary because I could
not
> find any other way to get it working.
>
> My question is: is the above code necessary, or is there some better way
to
> inject my own UpdateManager.
>
> The two UpdateManager's (ClusteringUpdateManager and
> MinimizingUpdateManager) I am using are as follows. I had to copy much of
> the source from DefferedUpdateManager because I could not get at the
private
> fields I needed.
>
> public class ClusteringUpdateManager extends UpdateManager {
>
> private boolean updating;
>
> private GraphicsSource graphicsSource;
>
> private IFigure root;
>
> private boolean updateQueued = false;
>
> private List invalidFigures = new ArrayList();
>
> /**
> * List of dirty areas, translated to absolute (canvas) coordinates.
> */
> protected List dirtyRegions = new ArrayList();
>
> /**
> * The union of all dirty regions.
> */
> private Rectangle dirtyUnion;
>
> /**
> * Map of all dirty figures and their unioned dirty regions.
> */
> private Map dirtyFigures = new HashMap();
>
> /**
> * List of dirty clusters which are being processed at this moment.
> */
> List work;
>
> /**
> * Constructs a new DererredUpdateManager with the given
GraphicsSource.
> *
> * @param gs
> * the graphics source
> */
> public ClusteringUpdateManager(GraphicsSource gs) {
> setGraphicsSource(gs);
> }
>
> /**
> * Empty constructor.
> */
> public ClusteringUpdateManager() {
> }
>
> /**
> * Calls {@link DeferredUpdateManager#performUpdate()}.
> */
> protected class UpdateRequest implements Runnable {
> /**
> * Calls {@link DeferredUpdateManager#performUpdate()}.
> */
> public void run() {
> performUpdate();
> }
> }
>
> /**
> * Adds a dirty region (defined by the rectangle <i>x, y, w, h </i>)
to
> the
> * update queue. If the figure isn't visible or either the width or
> height
> * are 0, the method returns without queueing the dirty region.
> *
> * @param figure
> * the figure that contains the dirty region
> * @param x
> * the x coordinate of the dirty region
> * @param y
> * the y coordinate of the dirty region
> * @param w
> * the width of the dirty region
> * @param h
> * the height of the dirty region
> */
> public synchronized void addDirtyRegion(IFigure figure, int x, int y,
> int w, int h) {
> if (!figure.isShowing())
> return;
> if (w == 0 || h == 0)
> return;
> Rectangle rect = new Rectangle(x, y, w, h);
> figure.translateToAbsolute(rect);
>
> // First check if this region is not in the queue to be processed
> // allready. This may occurr when during a repaint new dirty
regions
> // are added. When we discover that this happens for a dirty
region
> // which is still on the todo list of dirty regions to be
repainted,
> // we do not have to add it to the new list of dirty regions.
>
> // The strategy employed is a simple one, try to find any of the
> // clusters which completely contains the current dirty region. If
> // such a cluster is found, there is no need to add it to the new
> // dirty regions list.
>
> // This strategy may be refined to find parts of the
> // current dirty regions which are allready in the todo list and
> // subtract them from the current dirty region. Finally make
squares
> // of the remaining dirty area and add those squares to the dirty
> // regions list. This requires an algorithm to break up a polgon
> with
> // 90 degree angles into its contributing squares. This could be a
> // non trivial task.
> if (work != null)
> for (Iterator iter = work.iterator(); iter.hasNext();) {
> Rectangle cluster = (Rectangle) iter.next();
> if(cluster.contains(rect))
> return;
> }
>
> dirtyRegions.add(rect);
>
> // Now fill the structures for the firePainting notification.
> rect = (Rectangle) dirtyFigures.get(figure);
> if (rect == null) {
> rect = new Rectangle(x, y, w, h);
> dirtyFigures.put(figure, rect);
> } else
> rect.union(x, y, w, h);
>
> queueWork();
> }
>
> /**
> * Adds the given figure to the update queue. Invalid figures will be
> * validated before the damaged regions are repainted.
> *
> * @param f
> * the invalid figure
> */
> public synchronized void addInvalidFigure(IFigure f) {
> if (invalidFigures.contains(f))
> return;
> queueWork();
> invalidFigures.add(f);
> }
>
> /**
> * Returns a Graphics object for the given region.
> *
> * @param region
> * the region to be repainted
> * @return the Graphics object
> */
> protected Graphics getGraphics(Rectangle region) {
> if (graphicsSource == null)
> return null;
> return graphicsSource.getGraphics(region);
> }
>
> /**
> * Adds the given exposed region to the update queue and then performs
> the
> * update.
> *
> * @param exposed
> * the exposed region
> */
> public synchronized void performUpdate(Rectangle exposed) {
> addDirtyRegion(root, exposed);
> performUpdate();
> }
>
> /**
> * Performs the update. Validates the invalid figures and then
repaints
> the
> * dirty regions.
> *
> * @see #validateFigures()
> * @see #repairDamage()
> */
> public synchronized void performUpdate() {
> if (isDisposed() || updating)
> return;
> updating = true;
> try {
> validateFigures();
> updateQueued = false;
> repairDamage();
> } finally {
> updating = false;
> }
> }
>
> /**
> * Posts an {@link UpdateRequest}using {@link
> Display#asyncExec(Runnable)}.
> * If work has already been queued, a new request is not needed.
> */
> protected void queueWork() {
> if (!updateQueued) {
> Display.getCurrent().asyncExec(new UpdateRequest());
> updateQueued = true;
> }
> }
>
> /**
> * Releases the graphics object, which causes the GraphicsSource to
> flush.
> *
> * @param graphics
> * the graphics object
> */
> protected void releaseGraphics(Rectangle damage) {
> graphicsSource.flushGraphics(damage);
> }
>
> /**
> * Iterates over all dirty regions and clusters them into a smaller
> number
> * of dirty regions (the so-called clusters) which cover all original
> dirty
> * regions. What defines 'smaller' is up to the implementation, as
long
> as
> * the original dirty regions are covered by the clusters.
> *
> * @return List of dirty clusters.
> */
> protected List clusterDirtyRegions() {
> List clusters = new ArrayList();
> for (Iterator iter = dirtyRegions.iterator(); iter.hasNext();) {
> Rectangle cluster = ((Rectangle) iter.next()).getCopy();
> clusters.add(cluster);
> }
>
> // For every cluster, see if it can be clustered with any
> // other cluster. Continue as long as there have been any
> // succesfull clusterings.
> boolean clusteredAny;
> do {
> clusteredAny = false;
>
> for (int i = 0; i < clusters.size() - 1; i++) {
> Rectangle cluster = (Rectangle) clusters.get(i);
>
> // See if this cluster can be combined with any
> // other cluster in the rest of the list.
> for (int j = i + 1; j < clusters.size();) {
> Rectangle candidate = (Rectangle) clusters.get(j);
>
> if (candidate.intersects(cluster)) {
> // Yes, this clusters overlap with the first
> // cluster, combine them into the first cluster.
> cluster.union(candidate);
>
> // Remove this cluster, as it is now included
> // in the first cluster.
> clusters.remove(j);
>
> clusteredAny = true;
> } else
> // No, this clusters could not be combined with
> // the other cluster, try the next one.
> j++;
> }
> }
>
> } while (clusteredAny);
>
> return clusters;
> }
>
> /**
> * Repaints the dirty regions on the update queue and calls
> * {@link UpdateManager#firePainting(Rectangle, Map)}, unless there
are
> no
> * dirty regions.
> */
> protected void repairDamage() {
> // This is a list of Rectangles. It comprises all damaged areas
> // which need to be repainted.
> work = clusterDirtyRegions();
>
> try {
> dirtyRegions.clear();
>
> // Het principe van firePainting() is in tegenspraak met het
> // principe
> // van ClusteringUpdateManager. ClusteringUpdateManager laat
> // meerdere
> // dirty regions per figure toe, firePainting verwacht een 1:1
> // mapping
> // van dirty regions en figures.
>
> // Oplossing: houdt ook een oude stijl dirtyRegions bij voor
> gebruik
> // in firePainting.
>
> firePainting(dirtyUnion, dirtyFigures);
> dirtyUnion = null;
> dirtyFigures.clear();
>
> // Now repaint all clusters.
> for (Iterator iter = work.iterator(); iter.hasNext();) {
> final Rectangle cluster = (Rectangle) iter.next();
> final Graphics graphics = getGraphics(cluster);
> if (graphics != null) {
> // Figures may originate in several plugins.
> // Perform a safe paint operation.
> new SafeRunnable() {
>
> public void run() {
> root.paint(graphics);
> releaseGraphics(cluster);
> }
>
> }.run();
> }
> }
> } finally {
> work = null;
> }
> }
>
> /**
> * Sets the graphics source.
> *
> * @param gs
> * the graphics source
> */
> public void setGraphicsSource(GraphicsSource gs) {
> graphicsSource = gs;
> }
>
> /**
> * Sets the root figure.
> *
> * @param figure
> * the root figure
> */
> public void setRoot(IFigure figure) {
> root = figure;
> }
>
> /**
> * Validates the invalid figures on the update queue and calls
> * {@link UpdateManager#fireValidating()}unless there are no invalid
> * figures.
> */
> protected void validateFigures() {
> if (invalidFigures.isEmpty())
> return;
> try {
> IFigure fig;
> fireValidating();
> for (int i = 0; i < invalidFigures.size(); i++) {
> fig = (IFigure) invalidFigures.get(i);
> invalidFigures.set(i, null);
> fig.validate();
> }
> } finally {
> invalidFigures.clear();
> }
> }
> }
>
>
> public class MinimizingUpdateManager extends ClusteringUpdateManager {
>
> /*
> * (non-Javadoc)
> *
> * @see
> nl.juncus.spatial.display.ClusteringUpdateManager#clusterDir tyRegions()
> */
> protected List clusterDirtyRegions() {
> List clusters = new ArrayList();
> for (Iterator iter = dirtyRegions.iterator(); iter.hasNext();) {
> Rectangle cluster = ((Rectangle) iter.next()).getCopy();
> clusters.add(cluster);
> }
>
> // For every cluster, see if it can be clustered with any
> // other cluster. Continue as long as there have been any
> // succesfull clusterings.
> boolean clusteredAny;
> do {
> clusteredAny = false;
>
> for (int i = 0; i < clusters.size() - 1; i++) {
> // System.out.println(i);
> Rectangle cluster = (Rectangle) clusters.get(i);
>
> // See if this cluster can be combined with any
> // other cluster in the rest of the list.
> for (int j = i + 1; j < clusters.size();) {
> Rectangle candidate = (Rectangle) clusters.get(j);
> if (candidate.intersects(cluster)) {
> // Yes, this clusters overlap with the first
> // cluster, combine them into the first cluster.
>
> double areaCluster = (double) cluster.height
> * (double) cluster.width;
> double areaCandidate = (double) candidate.height
> * (double) candidate.width;
>
> Rectangle union = cluster.getUnion(candidate);
> double areaUnion = (double) union.height
> * (double) union.width;
>
> if (areaUnion <= areaCluster + areaCandidate) {
>
> cluster.union(candidate);
>
> // Remove this cluster, as it is now included
> // in the first cluster.
> clusters.remove(j);
>
> clusteredAny = true;
> } else
> j++;
> } else
> // No, this clusters could not be combined with
> // the other cluster, try the next one.
> j++;
> }
> }
>
> } while (clusteredAny);
>
> return clusters;
> }
>
> }
>
>
>
> I must admit that I did not check if all this is still necessary in in GEF
> 3.1, I developed this on 3.0.
>
> Koen van Dijken
>
>
>
|
|
|
Re: Injecting custom UpdateManagers [message #183090 is a reply to message #182948] |
Tue, 31 May 2005 06:51 |
Eclipse User |
|
|
|
Originally posted by: kvdijken.tiscali.nl
Hi Pratik,
I am using my own UpdateManagers (ClusteringUpdateManager and
MinimizingUpdateManager) for performance reasons. To replace the default
DeferredUpdateManager of the LightweightSystem I use the piece of 'dirty'
code. This all works fine, but I do not like the complexity of this 'dirty'
code. My question is if this is the way to use one's own UpdateManager or if
there is some cleaner way.
Something which would be even better would be to be able to use a different
UpdateManager per Layer, depending on the complexity of the layer. It was
suggested that this was possible but I could not get that to work. For now
however, it is good enough to use these UpdateManagers for the complete
LightweightSystem.
Koen
"Pratik Shah" <ppshah@us.ibm.com> wrote in message
news:d7g325$c7r$1@news.eclipse.org...
> What are you trying to do?
>
> "Koen van Dijken" <kvdijken@tiscali.nl> wrote in message
> news:d7fnda$g6$1@news.eclipse.org...
>> Hi GEF people,
>>
>> I am about to enter a new feature request for GEF, but before that I
>> would
>> like to know if what I write in that request is right. I am using my own
>> UpdateManager which performs much better than DeferredUpdateManager on
> large
>> datasets of which many of the Figures are far away from the origin of the
>> coordinate space. I inject my own UpdateManager in the LightWeightSystem
> as
>> follows:
>>
>> // Next piece of code is very dirty, but necessary because a
> cleaner
>> // way to inject a custom UpdateManager is not available.
>> final FigureCanvas figCanvas = (FigureCanvas) graphicalViewer
>> .getControl();
>> LightweightSystem lws = figCanvas.getLightweightSystem();
>> lws.setUpdateManager(new MinimizingUpdateManager());
>> lws.getUpdateManager().setGraphicsSource(
>> new BufferedGraphicsSource(figCanvas));
>> lws.getUpdateManager().addUpdateListener(new UpdateListener() {
>> public void notifyPainting(Rectangle damage,
>> java.util.Map dirtyRegions) {
>> }
>>
>> public void notifyValidating() {
>> if (!figCanvas.isDisposed()) {
>> ScrollPaneSolver.Result result;
>> result = ScrollPaneSolver.solve(new
> Rectangle(figCanvas
>> .getBounds()).setLocation(0, 0),
> getViewport(),
>> figCanvas.getHorizontalScrollBarVisibility(),
>> figCanvas.getVerticalScrollBarVisibility(),
>> figCanvas.computeTrim(0, 0, 0, 0).width,
>> figCanvas
>> .computeTrim(0, 0, 0, 0).height);
>> if (figCanvas.getHorizontalBar().getVisible() !=
>> result.showH)
>>
> figCanvas.getHorizontalBar().setVisible(result.showH);
>> if (figCanvas.getVerticalBar().getVisible() !=
>> result.showV)
>>
> figCanvas.getVerticalBar().setVisible(result.showV);
>> }
>> }
>> });
>> // End of dirty code.
>>
>> I think this is very dirty code, but (I think) necessary because I could
> not
>> find any other way to get it working.
>>
>> My question is: is the above code necessary, or is there some better way
> to
>> inject my own UpdateManager.
>>
>> The two UpdateManager's (ClusteringUpdateManager and
>> MinimizingUpdateManager) I am using are as follows. I had to copy much of
>> the source from DefferedUpdateManager because I could not get at the
> private
>> fields I needed.
>>
>> public class ClusteringUpdateManager extends UpdateManager {
>>
>> private boolean updating;
>>
>> private GraphicsSource graphicsSource;
>>
>> private IFigure root;
>>
>> private boolean updateQueued = false;
>>
>> private List invalidFigures = new ArrayList();
>>
>> /**
>> * List of dirty areas, translated to absolute (canvas) coordinates.
>> */
>> protected List dirtyRegions = new ArrayList();
>>
>> /**
>> * The union of all dirty regions.
>> */
>> private Rectangle dirtyUnion;
>>
>> /**
>> * Map of all dirty figures and their unioned dirty regions.
>> */
>> private Map dirtyFigures = new HashMap();
>>
>> /**
>> * List of dirty clusters which are being processed at this moment.
>> */
>> List work;
>>
>> /**
>> * Constructs a new DererredUpdateManager with the given
> GraphicsSource.
>> *
>> * @param gs
>> * the graphics source
>> */
>> public ClusteringUpdateManager(GraphicsSource gs) {
>> setGraphicsSource(gs);
>> }
>>
>> /**
>> * Empty constructor.
>> */
>> public ClusteringUpdateManager() {
>> }
>>
>> /**
>> * Calls {@link DeferredUpdateManager#performUpdate()}.
>> */
>> protected class UpdateRequest implements Runnable {
>> /**
>> * Calls {@link DeferredUpdateManager#performUpdate()}.
>> */
>> public void run() {
>> performUpdate();
>> }
>> }
>>
>> /**
>> * Adds a dirty region (defined by the rectangle <i>x, y, w, h </i>)
> to
>> the
>> * update queue. If the figure isn't visible or either the width or
>> height
>> * are 0, the method returns without queueing the dirty region.
>> *
>> * @param figure
>> * the figure that contains the dirty region
>> * @param x
>> * the x coordinate of the dirty region
>> * @param y
>> * the y coordinate of the dirty region
>> * @param w
>> * the width of the dirty region
>> * @param h
>> * the height of the dirty region
>> */
>> public synchronized void addDirtyRegion(IFigure figure, int x, int y,
>> int w, int h) {
>> if (!figure.isShowing())
>> return;
>> if (w == 0 || h == 0)
>> return;
>> Rectangle rect = new Rectangle(x, y, w, h);
>> figure.translateToAbsolute(rect);
>>
>> // First check if this region is not in the queue to be processed
>> // allready. This may occurr when during a repaint new dirty
> regions
>> // are added. When we discover that this happens for a dirty
> region
>> // which is still on the todo list of dirty regions to be
> repainted,
>> // we do not have to add it to the new list of dirty regions.
>>
>> // The strategy employed is a simple one, try to find any of the
>> // clusters which completely contains the current dirty region.
>> If
>> // such a cluster is found, there is no need to add it to the new
>> // dirty regions list.
>>
>> // This strategy may be refined to find parts of the
>> // current dirty regions which are allready in the todo list and
>> // subtract them from the current dirty region. Finally make
> squares
>> // of the remaining dirty area and add those squares to the dirty
>> // regions list. This requires an algorithm to break up a polgon
>> with
>> // 90 degree angles into its contributing squares. This could be
>> a
>> // non trivial task.
>> if (work != null)
>> for (Iterator iter = work.iterator(); iter.hasNext();) {
>> Rectangle cluster = (Rectangle) iter.next();
>> if(cluster.contains(rect))
>> return;
>> }
>>
>> dirtyRegions.add(rect);
>>
>> // Now fill the structures for the firePainting notification.
>> rect = (Rectangle) dirtyFigures.get(figure);
>> if (rect == null) {
>> rect = new Rectangle(x, y, w, h);
>> dirtyFigures.put(figure, rect);
>> } else
>> rect.union(x, y, w, h);
>>
>> queueWork();
>> }
>>
>> /**
>> * Adds the given figure to the update queue. Invalid figures will be
>> * validated before the damaged regions are repainted.
>> *
>> * @param f
>> * the invalid figure
>> */
>> public synchronized void addInvalidFigure(IFigure f) {
>> if (invalidFigures.contains(f))
>> return;
>> queueWork();
>> invalidFigures.add(f);
>> }
>>
>> /**
>> * Returns a Graphics object for the given region.
>> *
>> * @param region
>> * the region to be repainted
>> * @return the Graphics object
>> */
>> protected Graphics getGraphics(Rectangle region) {
>> if (graphicsSource == null)
>> return null;
>> return graphicsSource.getGraphics(region);
>> }
>>
>> /**
>> * Adds the given exposed region to the update queue and then
>> performs
>> the
>> * update.
>> *
>> * @param exposed
>> * the exposed region
>> */
>> public synchronized void performUpdate(Rectangle exposed) {
>> addDirtyRegion(root, exposed);
>> performUpdate();
>> }
>>
>> /**
>> * Performs the update. Validates the invalid figures and then
> repaints
>> the
>> * dirty regions.
>> *
>> * @see #validateFigures()
>> * @see #repairDamage()
>> */
>> public synchronized void performUpdate() {
>> if (isDisposed() || updating)
>> return;
>> updating = true;
>> try {
>> validateFigures();
>> updateQueued = false;
>> repairDamage();
>> } finally {
>> updating = false;
>> }
>> }
>>
>> /**
>> * Posts an {@link UpdateRequest}using {@link
>> Display#asyncExec(Runnable)}.
>> * If work has already been queued, a new request is not needed.
>> */
>> protected void queueWork() {
>> if (!updateQueued) {
>> Display.getCurrent().asyncExec(new UpdateRequest());
>> updateQueued = true;
>> }
>> }
>>
>> /**
>> * Releases the graphics object, which causes the GraphicsSource to
>> flush.
>> *
>> * @param graphics
>> * the graphics object
>> */
>> protected void releaseGraphics(Rectangle damage) {
>> graphicsSource.flushGraphics(damage);
>> }
>>
>> /**
>> * Iterates over all dirty regions and clusters them into a smaller
>> number
>> * of dirty regions (the so-called clusters) which cover all original
>> dirty
>> * regions. What defines 'smaller' is up to the implementation, as
> long
>> as
>> * the original dirty regions are covered by the clusters.
>> *
>> * @return List of dirty clusters.
>> */
>> protected List clusterDirtyRegions() {
>> List clusters = new ArrayList();
>> for (Iterator iter = dirtyRegions.iterator(); iter.hasNext();) {
>> Rectangle cluster = ((Rectangle) iter.next()).getCopy();
>> clusters.add(cluster);
>> }
>>
>> // For every cluster, see if it can be clustered with any
>> // other cluster. Continue as long as there have been any
>> // succesfull clusterings.
>> boolean clusteredAny;
>> do {
>> clusteredAny = false;
>>
>> for (int i = 0; i < clusters.size() - 1; i++) {
>> Rectangle cluster = (Rectangle) clusters.get(i);
>>
>> // See if this cluster can be combined with any
>> // other cluster in the rest of the list.
>> for (int j = i + 1; j < clusters.size();) {
>> Rectangle candidate = (Rectangle) clusters.get(j);
>>
>> if (candidate.intersects(cluster)) {
>> // Yes, this clusters overlap with the first
>> // cluster, combine them into the first cluster.
>> cluster.union(candidate);
>>
>> // Remove this cluster, as it is now included
>> // in the first cluster.
>> clusters.remove(j);
>>
>> clusteredAny = true;
>> } else
>> // No, this clusters could not be combined with
>> // the other cluster, try the next one.
>> j++;
>> }
>> }
>>
>> } while (clusteredAny);
>>
>> return clusters;
>> }
>>
>> /**
>> * Repaints the dirty regions on the update queue and calls
>> * {@link UpdateManager#firePainting(Rectangle, Map)}, unless there
> are
>> no
>> * dirty regions.
>> */
>> protected void repairDamage() {
>> // This is a list of Rectangles. It comprises all damaged areas
>> // which need to be repainted.
>> work = clusterDirtyRegions();
>>
>> try {
>> dirtyRegions.clear();
>>
>> // Het principe van firePainting() is in tegenspraak met het
>> // principe
>> // van ClusteringUpdateManager. ClusteringUpdateManager laat
>> // meerdere
>> // dirty regions per figure toe, firePainting verwacht een
>> 1:1
>> // mapping
>> // van dirty regions en figures.
>>
>> // Oplossing: houdt ook een oude stijl dirtyRegions bij voor
>> gebruik
>> // in firePainting.
>>
>> firePainting(dirtyUnion, dirtyFigures);
>> dirtyUnion = null;
>> dirtyFigures.clear();
>>
>> // Now repaint all clusters.
>> for (Iterator iter = work.iterator(); iter.hasNext();) {
>> final Rectangle cluster = (Rectangle) iter.next();
>> final Graphics graphics = getGraphics(cluster);
>> if (graphics != null) {
>> // Figures may originate in several plugins.
>> // Perform a safe paint operation.
>> new SafeRunnable() {
>>
>> public void run() {
>> root.paint(graphics);
>> releaseGraphics(cluster);
>> }
>>
>> }.run();
>> }
>> }
>> } finally {
>> work = null;
>> }
>> }
>>
>> /**
>> * Sets the graphics source.
>> *
>> * @param gs
>> * the graphics source
>> */
>> public void setGraphicsSource(GraphicsSource gs) {
>> graphicsSource = gs;
>> }
>>
>> /**
>> * Sets the root figure.
>> *
>> * @param figure
>> * the root figure
>> */
>> public void setRoot(IFigure figure) {
>> root = figure;
>> }
>>
>> /**
>> * Validates the invalid figures on the update queue and calls
>> * {@link UpdateManager#fireValidating()}unless there are no invalid
>> * figures.
>> */
>> protected void validateFigures() {
>> if (invalidFigures.isEmpty())
>> return;
>> try {
>> IFigure fig;
>> fireValidating();
>> for (int i = 0; i < invalidFigures.size(); i++) {
>> fig = (IFigure) invalidFigures.get(i);
>> invalidFigures.set(i, null);
>> fig.validate();
>> }
>> } finally {
>> invalidFigures.clear();
>> }
>> }
>> }
>>
>>
>> public class MinimizingUpdateManager extends ClusteringUpdateManager {
>>
>> /*
>> * (non-Javadoc)
>> *
>> * @see
>> nl.juncus.spatial.display.ClusteringUpdateManager#clusterDir tyRegions()
>> */
>> protected List clusterDirtyRegions() {
>> List clusters = new ArrayList();
>> for (Iterator iter = dirtyRegions.iterator(); iter.hasNext();) {
>> Rectangle cluster = ((Rectangle) iter.next()).getCopy();
>> clusters.add(cluster);
>> }
>>
>> // For every cluster, see if it can be clustered with any
>> // other cluster. Continue as long as there have been any
>> // succesfull clusterings.
>> boolean clusteredAny;
>> do {
>> clusteredAny = false;
>>
>> for (int i = 0; i < clusters.size() - 1; i++) {
>> // System.out.println(i);
>> Rectangle cluster = (Rectangle) clusters.get(i);
>>
>> // See if this cluster can be combined with any
>> // other cluster in the rest of the list.
>> for (int j = i + 1; j < clusters.size();) {
>> Rectangle candidate = (Rectangle) clusters.get(j);
>> if (candidate.intersects(cluster)) {
>> // Yes, this clusters overlap with the first
>> // cluster, combine them into the first cluster.
>>
>> double areaCluster = (double) cluster.height
>> * (double) cluster.width;
>> double areaCandidate = (double) candidate.height
>> * (double) candidate.width;
>>
>> Rectangle union = cluster.getUnion(candidate);
>> double areaUnion = (double) union.height
>> * (double) union.width;
>>
>> if (areaUnion <= areaCluster + areaCandidate) {
>>
>> cluster.union(candidate);
>>
>> // Remove this cluster, as it is now included
>> // in the first cluster.
>> clusters.remove(j);
>>
>> clusteredAny = true;
>> } else
>> j++;
>> } else
>> // No, this clusters could not be combined with
>> // the other cluster, try the next one.
>> j++;
>> }
>> }
>>
>> } while (clusteredAny);
>>
>> return clusters;
>> }
>>
>> }
>>
>>
>>
>> I must admit that I did not check if all this is still necessary in in
>> GEF
>> 3.1, I developed this on 3.0.
>>
>> Koen van Dijken
>>
>>
>>
>
>
|
|
|
Re: Injecting custom UpdateManagers [message #183099 is a reply to message #183090] |
Tue, 31 May 2005 07:18 |
Pratik Shah Messages: 1077 Registered: July 2009 |
Senior Member |
|
|
Better approach is to create the lightweight system and sets its update
manager first, and then pass that lightweight system to the FigureCanvas'
constructor.
Posting code directly in the message is only fine when it's a short snippet.
For future, keep in mind that code posted is usually hard to read...attached
java files would be better.
"Koen van Dijken" <kvdijken@tiscali.nl> wrote in message
news:d7h1qe$698$1@news.eclipse.org...
> Hi Pratik,
>
> I am using my own UpdateManagers (ClusteringUpdateManager and
> MinimizingUpdateManager) for performance reasons. To replace the default
> DeferredUpdateManager of the LightweightSystem I use the piece of 'dirty'
> code. This all works fine, but I do not like the complexity of this
'dirty'
> code. My question is if this is the way to use one's own UpdateManager or
if
> there is some cleaner way.
>
> Something which would be even better would be to be able to use a
different
> UpdateManager per Layer, depending on the complexity of the layer. It was
> suggested that this was possible but I could not get that to work. For now
> however, it is good enough to use these UpdateManagers for the complete
> LightweightSystem.
>
> Koen
>
>
> "Pratik Shah" <ppshah@us.ibm.com> wrote in message
> news:d7g325$c7r$1@news.eclipse.org...
> > What are you trying to do?
> >
> > "Koen van Dijken" <kvdijken@tiscali.nl> wrote in message
> > news:d7fnda$g6$1@news.eclipse.org...
> >> Hi GEF people,
> >>
> >> I am about to enter a new feature request for GEF, but before that I
> >> would
> >> like to know if what I write in that request is right. I am using my
own
> >> UpdateManager which performs much better than DeferredUpdateManager on
> > large
> >> datasets of which many of the Figures are far away from the origin of
the
> >> coordinate space. I inject my own UpdateManager in the
LightWeightSystem
> > as
> >> follows:
> >>
> >> // Next piece of code is very dirty, but necessary because a
> > cleaner
> >> // way to inject a custom UpdateManager is not available.
> >> final FigureCanvas figCanvas = (FigureCanvas) graphicalViewer
> >> .getControl();
> >> LightweightSystem lws = figCanvas.getLightweightSystem();
> >> lws.setUpdateManager(new MinimizingUpdateManager());
> >> lws.getUpdateManager().setGraphicsSource(
> >> new BufferedGraphicsSource(figCanvas));
> >> lws.getUpdateManager().addUpdateListener(new UpdateListener() {
> >> public void notifyPainting(Rectangle damage,
> >> java.util.Map dirtyRegions) {
> >> }
> >>
> >> public void notifyValidating() {
> >> if (!figCanvas.isDisposed()) {
> >> ScrollPaneSolver.Result result;
> >> result = ScrollPaneSolver.solve(new
> > Rectangle(figCanvas
> >> .getBounds()).setLocation(0, 0),
> > getViewport(),
> >>
figCanvas.getHorizontalScrollBarVisibility(),
> >> figCanvas.getVerticalScrollBarVisibility(),
> >> figCanvas.computeTrim(0, 0, 0, 0).width,
> >> figCanvas
> >> .computeTrim(0, 0, 0, 0).height);
> >> if (figCanvas.getHorizontalBar().getVisible() !=
> >> result.showH)
> >>
> > figCanvas.getHorizontalBar().setVisible(result.showH);
> >> if (figCanvas.getVerticalBar().getVisible() !=
> >> result.showV)
> >>
> > figCanvas.getVerticalBar().setVisible(result.showV);
> >> }
> >> }
> >> });
> >> // End of dirty code.
> >>
> >> I think this is very dirty code, but (I think) necessary because I
could
> > not
> >> find any other way to get it working.
> >>
> >> My question is: is the above code necessary, or is there some better
way
> > to
> >> inject my own UpdateManager.
> >>
> >> The two UpdateManager's (ClusteringUpdateManager and
> >> MinimizingUpdateManager) I am using are as follows. I had to copy much
of
> >> the source from DefferedUpdateManager because I could not get at the
> > private
> >> fields I needed.
> >>
> >> public class ClusteringUpdateManager extends UpdateManager {
> >>
> >> private boolean updating;
> >>
> >> private GraphicsSource graphicsSource;
> >>
> >> private IFigure root;
> >>
> >> private boolean updateQueued = false;
> >>
> >> private List invalidFigures = new ArrayList();
> >>
> >> /**
> >> * List of dirty areas, translated to absolute (canvas)
coordinates.
> >> */
> >> protected List dirtyRegions = new ArrayList();
> >>
> >> /**
> >> * The union of all dirty regions.
> >> */
> >> private Rectangle dirtyUnion;
> >>
> >> /**
> >> * Map of all dirty figures and their unioned dirty regions.
> >> */
> >> private Map dirtyFigures = new HashMap();
> >>
> >> /**
> >> * List of dirty clusters which are being processed at this moment.
> >> */
> >> List work;
> >>
> >> /**
> >> * Constructs a new DererredUpdateManager with the given
> > GraphicsSource.
> >> *
> >> * @param gs
> >> * the graphics source
> >> */
> >> public ClusteringUpdateManager(GraphicsSource gs) {
> >> setGraphicsSource(gs);
> >> }
> >>
> >> /**
> >> * Empty constructor.
> >> */
> >> public ClusteringUpdateManager() {
> >> }
> >>
> >> /**
> >> * Calls {@link DeferredUpdateManager#performUpdate()}.
> >> */
> >> protected class UpdateRequest implements Runnable {
> >> /**
> >> * Calls {@link DeferredUpdateManager#performUpdate()}.
> >> */
> >> public void run() {
> >> performUpdate();
> >> }
> >> }
> >>
> >> /**
> >> * Adds a dirty region (defined by the rectangle <i>x, y, w, h
</i>)
> > to
> >> the
> >> * update queue. If the figure isn't visible or either the width or
> >> height
> >> * are 0, the method returns without queueing the dirty region.
> >> *
> >> * @param figure
> >> * the figure that contains the dirty region
> >> * @param x
> >> * the x coordinate of the dirty region
> >> * @param y
> >> * the y coordinate of the dirty region
> >> * @param w
> >> * the width of the dirty region
> >> * @param h
> >> * the height of the dirty region
> >> */
> >> public synchronized void addDirtyRegion(IFigure figure, int x, int
y,
> >> int w, int h) {
> >> if (!figure.isShowing())
> >> return;
> >> if (w == 0 || h == 0)
> >> return;
> >> Rectangle rect = new Rectangle(x, y, w, h);
> >> figure.translateToAbsolute(rect);
> >>
> >> // First check if this region is not in the queue to be
processed
> >> // allready. This may occurr when during a repaint new dirty
> > regions
> >> // are added. When we discover that this happens for a dirty
> > region
> >> // which is still on the todo list of dirty regions to be
> > repainted,
> >> // we do not have to add it to the new list of dirty regions.
> >>
> >> // The strategy employed is a simple one, try to find any of
the
> >> // clusters which completely contains the current dirty region.
> >> If
> >> // such a cluster is found, there is no need to add it to the
new
> >> // dirty regions list.
> >>
> >> // This strategy may be refined to find parts of the
> >> // current dirty regions which are allready in the todo list
and
> >> // subtract them from the current dirty region. Finally make
> > squares
> >> // of the remaining dirty area and add those squares to the
dirty
> >> // regions list. This requires an algorithm to break up a
polgon
> >> with
> >> // 90 degree angles into its contributing squares. This could
be
> >> a
> >> // non trivial task.
> >> if (work != null)
> >> for (Iterator iter = work.iterator(); iter.hasNext();) {
> >> Rectangle cluster = (Rectangle) iter.next();
> >> if(cluster.contains(rect))
> >> return;
> >> }
> >>
> >> dirtyRegions.add(rect);
> >>
> >> // Now fill the structures for the firePainting notification.
> >> rect = (Rectangle) dirtyFigures.get(figure);
> >> if (rect == null) {
> >> rect = new Rectangle(x, y, w, h);
> >> dirtyFigures.put(figure, rect);
> >> } else
> >> rect.union(x, y, w, h);
> >>
> >> queueWork();
> >> }
> >>
> >> /**
> >> * Adds the given figure to the update queue. Invalid figures will
be
> >> * validated before the damaged regions are repainted.
> >> *
> >> * @param f
> >> * the invalid figure
> >> */
> >> public synchronized void addInvalidFigure(IFigure f) {
> >> if (invalidFigures.contains(f))
> >> return;
> >> queueWork();
> >> invalidFigures.add(f);
> >> }
> >>
> >> /**
> >> * Returns a Graphics object for the given region.
> >> *
> >> * @param region
> >> * the region to be repainted
> >> * @return the Graphics object
> >> */
> >> protected Graphics getGraphics(Rectangle region) {
> >> if (graphicsSource == null)
> >> return null;
> >> return graphicsSource.getGraphics(region);
> >> }
> >>
> >> /**
> >> * Adds the given exposed region to the update queue and then
> >> performs
> >> the
> >> * update.
> >> *
> >> * @param exposed
> >> * the exposed region
> >> */
> >> public synchronized void performUpdate(Rectangle exposed) {
> >> addDirtyRegion(root, exposed);
> >> performUpdate();
> >> }
> >>
> >> /**
> >> * Performs the update. Validates the invalid figures and then
> > repaints
> >> the
> >> * dirty regions.
> >> *
> >> * @see #validateFigures()
> >> * @see #repairDamage()
> >> */
> >> public synchronized void performUpdate() {
> >> if (isDisposed() || updating)
> >> return;
> >> updating = true;
> >> try {
> >> validateFigures();
> >> updateQueued = false;
> >> repairDamage();
> >> } finally {
> >> updating = false;
> >> }
> >> }
> >>
> >> /**
> >> * Posts an {@link UpdateRequest}using {@link
> >> Display#asyncExec(Runnable)}.
> >> * If work has already been queued, a new request is not needed.
> >> */
> >> protected void queueWork() {
> >> if (!updateQueued) {
> >> Display.getCurrent().asyncExec(new UpdateRequest());
> >> updateQueued = true;
> >> }
> >> }
> >>
> >> /**
> >> * Releases the graphics object, which causes the GraphicsSource to
> >> flush.
> >> *
> >> * @param graphics
> >> * the graphics object
> >> */
> >> protected void releaseGraphics(Rectangle damage) {
> >> graphicsSource.flushGraphics(damage);
> >> }
> >>
> >> /**
> >> * Iterates over all dirty regions and clusters them into a smaller
> >> number
> >> * of dirty regions (the so-called clusters) which cover all
original
> >> dirty
> >> * regions. What defines 'smaller' is up to the implementation, as
> > long
> >> as
> >> * the original dirty regions are covered by the clusters.
> >> *
> >> * @return List of dirty clusters.
> >> */
> >> protected List clusterDirtyRegions() {
> >> List clusters = new ArrayList();
> >> for (Iterator iter = dirtyRegions.iterator(); iter.hasNext();)
{
> >> Rectangle cluster = ((Rectangle) iter.next()).getCopy();
> >> clusters.add(cluster);
> >> }
> >>
> >> // For every cluster, see if it can be clustered with any
> >> // other cluster. Continue as long as there have been any
> >> // succesfull clusterings.
> >> boolean clusteredAny;
> >> do {
> >> clusteredAny = false;
> >>
> >> for (int i = 0; i < clusters.size() - 1; i++) {
> >> Rectangle cluster = (Rectangle) clusters.get(i);
> >>
> >> // See if this cluster can be combined with any
> >> // other cluster in the rest of the list.
> >> for (int j = i + 1; j < clusters.size();) {
> >> Rectangle candidate = (Rectangle) clusters.get(j);
> >>
> >> if (candidate.intersects(cluster)) {
> >> // Yes, this clusters overlap with the first
> >> // cluster, combine them into the first
cluster.
> >> cluster.union(candidate);
> >>
> >> // Remove this cluster, as it is now included
> >> // in the first cluster.
> >> clusters.remove(j);
> >>
> >> clusteredAny = true;
> >> } else
> >> // No, this clusters could not be combined with
> >> // the other cluster, try the next one.
> >> j++;
> >> }
> >> }
> >>
> >> } while (clusteredAny);
> >>
> >> return clusters;
> >> }
> >>
> >> /**
> >> * Repaints the dirty regions on the update queue and calls
> >> * {@link UpdateManager#firePainting(Rectangle, Map)}, unless there
> > are
> >> no
> >> * dirty regions.
> >> */
> >> protected void repairDamage() {
> >> // This is a list of Rectangles. It comprises all damaged areas
> >> // which need to be repainted.
> >> work = clusterDirtyRegions();
> >>
> >> try {
> >> dirtyRegions.clear();
> >>
> >> // Het principe van firePainting() is in tegenspraak met
het
> >> // principe
> >> // van ClusteringUpdateManager. ClusteringUpdateManager
laat
> >> // meerdere
> >> // dirty regions per figure toe, firePainting verwacht een
> >> 1:1
> >> // mapping
> >> // van dirty regions en figures.
> >>
> >> // Oplossing: houdt ook een oude stijl dirtyRegions bij
voor
> >> gebruik
> >> // in firePainting.
> >>
> >> firePainting(dirtyUnion, dirtyFigures);
> >> dirtyUnion = null;
> >> dirtyFigures.clear();
> >>
> >> // Now repaint all clusters.
> >> for (Iterator iter = work.iterator(); iter.hasNext();) {
> >> final Rectangle cluster = (Rectangle) iter.next();
> >> final Graphics graphics = getGraphics(cluster);
> >> if (graphics != null) {
> >> // Figures may originate in several plugins.
> >> // Perform a safe paint operation.
> >> new SafeRunnable() {
> >>
> >> public void run() {
> >> root.paint(graphics);
> >> releaseGraphics(cluster);
> >> }
> >>
> >> }.run();
> >> }
> >> }
> >> } finally {
> >> work = null;
> >> }
> >> }
> >>
> >> /**
> >> * Sets the graphics source.
> >> *
> >> * @param gs
> >> * the graphics source
> >> */
> >> public void setGraphicsSource(GraphicsSource gs) {
> >> graphicsSource = gs;
> >> }
> >>
> >> /**
> >> * Sets the root figure.
> >> *
> >> * @param figure
> >> * the root figure
> >> */
> >> public void setRoot(IFigure figure) {
> >> root = figure;
> >> }
> >>
> >> /**
> >> * Validates the invalid figures on the update queue and calls
> >> * {@link UpdateManager#fireValidating()}unless there are no
invalid
> >> * figures.
> >> */
> >> protected void validateFigures() {
> >> if (invalidFigures.isEmpty())
> >> return;
> >> try {
> >> IFigure fig;
> >> fireValidating();
> >> for (int i = 0; i < invalidFigures.size(); i++) {
> >> fig = (IFigure) invalidFigures.get(i);
> >> invalidFigures.set(i, null);
> >> fig.validate();
> >> }
> >> } finally {
> >> invalidFigures.clear();
> >> }
> >> }
> >> }
> >>
> >>
> >> public class MinimizingUpdateManager extends ClusteringUpdateManager {
> >>
> >> /*
> >> * (non-Javadoc)
> >> *
> >> * @see
> >> nl.juncus.spatial.display.ClusteringUpdateManager#clusterDir tyRegions()
> >> */
> >> protected List clusterDirtyRegions() {
> >> List clusters = new ArrayList();
> >> for (Iterator iter = dirtyRegions.iterator(); iter.hasNext();)
{
> >> Rectangle cluster = ((Rectangle) iter.next()).getCopy();
> >> clusters.add(cluster);
> >> }
> >>
> >> // For every cluster, see if it can be clustered with any
> >> // other cluster. Continue as long as there have been any
> >> // succesfull clusterings.
> >> boolean clusteredAny;
> >> do {
> >> clusteredAny = false;
> >>
> >> for (int i = 0; i < clusters.size() - 1; i++) {
> >> // System.out.println(i);
> >> Rectangle cluster = (Rectangle) clusters.get(i);
> >>
> >> // See if this cluster can be combined with any
> >> // other cluster in the rest of the list.
> >> for (int j = i + 1; j < clusters.size();) {
> >> Rectangle candidate = (Rectangle) clusters.get(j);
> >> if (candidate.intersects(cluster)) {
> >> // Yes, this clusters overlap with the first
> >> // cluster, combine them into the first
cluster.
> >>
> >> double areaCluster = (double) cluster.height
> >> * (double) cluster.width;
> >> double areaCandidate = (double)
candidate.height
> >> * (double) candidate.width;
> >>
> >> Rectangle union = cluster.getUnion(candidate);
> >> double areaUnion = (double) union.height
> >> * (double) union.width;
> >>
> >> if (areaUnion <= areaCluster + areaCandidate) {
> >>
> >> cluster.union(candidate);
> >>
> >> // Remove this cluster, as it is now
included
> >> // in the first cluster.
> >> clusters.remove(j);
> >>
> >> clusteredAny = true;
> >> } else
> >> j++;
> >> } else
> >> // No, this clusters could not be combined with
> >> // the other cluster, try the next one.
> >> j++;
> >> }
> >> }
> >>
> >> } while (clusteredAny);
> >>
> >> return clusters;
> >> }
> >>
> >> }
> >>
> >>
> >>
> >> I must admit that I did not check if all this is still necessary in in
> >> GEF
> >> 3.1, I developed this on 3.0.
> >>
> >> Koen van Dijken
> >>
> >>
> >>
> >
> >
>
>
|
|
|
Re: Injecting custom UpdateManagers [message #183166 is a reply to message #183090] |
Tue, 31 May 2005 18:41 |
Eclipse User |
|
|
|
Originally posted by: none.us.ibm.com
Clustering damage rectangles is a good idea. I would like to see some
numbers for how this helps your cases or if it applies to general things
like the logic example.
"Koen van Dijken" <kvdijken@tiscali.nl> wrote in message
news:d7h1qe$698$1@news.eclipse.org...
> Hi Pratik,
>
> I am using my own UpdateManagers (ClusteringUpdateManager and
> MinimizingUpdateManager) for performance reasons. To replace the default
> DeferredUpdateManager of the LightweightSystem I use the piece of 'dirty'
> code. This all works fine, but I do not like the complexity of this
> 'dirty' code. My question is if this is the way to use one's own
> UpdateManager or if there is some cleaner way.
>
> Something which would be even better would be to be able to use a
> different UpdateManager per Layer, depending on the complexity of the
> layer. It was suggested that this was possible but I could not get that to
> work. For now however, it is good enough to use these UpdateManagers for
> the complete LightweightSystem.
>
> Koen
>
|
|
|
Re: Injecting custom UpdateManagers [message #183744 is a reply to message #183166] |
Tue, 07 June 2005 14:14 |
Eclipse User |
|
|
|
Originally posted by: kvdijken.tiscali.nl
I do not have measurements of the improvements in performance. I don't think
however that in the Logic example it does make any difference. In our
application we have lots of Figures (several 10.000's) which are expensive
to paint. They are expensive to paint because of difficult geometries
(shapes with holes) and transparency. I found that selection of single
figures in this scenario (with the default DeferredUpdateManager) caused an
update of the LayeredPane from the origin (0,0) to and including the bounds
of the selected figure. Upon selection of another figure it could be even
worse because the range of both figures had to be painted. Those ranges are
unioned with the origin (0,0) and the resulting range is repainted. With so
many hard-to-paint figures the timelapse was too long to be comfortable.
With the two UpdateManagers I wrote selection is instantaneous.
Performance can be even improved, but that requires quite some effort, which
might not be worth it. Also since GEF 3.1 with the support of transparency
performance has improved quite a lot. Thanks for that.
Koen
"Randy Hudson" <none@us.ibm.com> wrote in message
news:d7ibdq$160$1@news.eclipse.org...
> Clustering damage rectangles is a good idea. I would like to see some
> numbers for how this helps your cases or if it applies to general things
> like the logic example.
>
> "Koen van Dijken" <kvdijken@tiscali.nl> wrote in message
> news:d7h1qe$698$1@news.eclipse.org...
>> Hi Pratik,
>>
>> I am using my own UpdateManagers (ClusteringUpdateManager and
>> MinimizingUpdateManager) for performance reasons. To replace the default
>> DeferredUpdateManager of the LightweightSystem I use the piece of 'dirty'
>> code. This all works fine, but I do not like the complexity of this
>> 'dirty' code. My question is if this is the way to use one's own
>> UpdateManager or if there is some cleaner way.
>>
>> Something which would be even better would be to be able to use a
>> different UpdateManager per Layer, depending on the complexity of the
>> layer. It was suggested that this was possible but I could not get that
>> to work. For now however, it is good enough to use these UpdateManagers
>> for the complete LightweightSystem.
>>
>> Koen
>>
>
|
|
|
Goto Forum:
Current Time: Fri Dec 13 03:03:33 GMT 2024
Powered by FUDForum. Page generated in 0.04010 seconds
|