use of org.apache.sis.portrayal.RenderException in project sis by apache.
the class CoverageCanvas method toString.
/**
* Returns a string representation for debugging purposes.
* The string content may change in any future version.
*/
@Override
public String toString() {
if (!Platform.isFxApplicationThread()) {
return super.toString();
}
final String lineSeparator = System.lineSeparator();
final StringBuilder buffer = new StringBuilder(1000);
final TableAppender table = new TableAppender(buffer);
table.setMultiLinesCells(true);
try {
table.nextLine('═');
getGridGeometry().getGeographicExtent().ifPresent((bbox) -> {
table.append(String.format("Canvas geographic bounding box (λ,ɸ):%n" + "Max: % 10.5f° % 10.5f°%n" + "Min: % 10.5f° % 10.5f°", bbox.getEastBoundLongitude(), bbox.getNorthBoundLatitude(), bbox.getWestBoundLongitude(), bbox.getSouthBoundLatitude())).appendHorizontalSeparator();
});
final Rectangle2D aoi = getAreaOfInterest();
final DirectPosition poi = getPointOfInterest(true);
if (aoi != null && poi != null) {
table.append(String.format("A/P of interest in objective CRS (x,y):%n" + "Max: %, 16.4f %, 16.4f%n" + "POI: %, 16.4f %, 16.4f%n" + "Min: %, 16.4f %, 16.4f%n", aoi.getMaxX(), aoi.getMaxY(), poi.getOrdinate(0), poi.getOrdinate(1), aoi.getMinX(), aoi.getMinY())).appendHorizontalSeparator();
}
final Rectangle source = data.objectiveToData(aoi);
if (source != null) {
table.append("Extent in source coverage:").append(lineSeparator).append(String.valueOf(new GridExtent(source))).append(lineSeparator).nextLine();
}
table.nextLine('═');
table.flush();
} catch (RenderException | TransformException | IOException e) {
buffer.append(e).append(lineSeparator);
}
return buffer.toString();
}
use of org.apache.sis.portrayal.RenderException in project sis by apache.
the class MapCanvas method repaint.
/**
* Invoked when the map content needs to be rendered again.
* It may be because the map has new content, or because the viewed region moved or has been zoomed.
* This method starts the rendering process immediately, unless a rendering is already in progress.
*
* @see #requestRepaint()
*/
final void repaint() {
assert Platform.isFxApplicationThread();
/*
* If a rendering is already in progress, do not send a new request now.
* Wait for current rendering to finish; a new one will be automatically
* requested if content changes are detected after the rendering.
*/
if (renderingInProgress != null) {
if (renderingInProgress instanceof Delayed) {
renderingInProgress.cancel(true);
renderingInProgress = null;
} else {
contentChangeCount++;
return;
}
}
hasError = false;
// Avoid that `requestRepaint(…)` trig new paints.
isRendering.set(true);
renderingStartTime = System.nanoTime();
try {
/*
* If a new canvas size is known, inform the parent `PlanarCanvas` about that.
* It may cause a recomputation of the "objective to display" transform.
*/
if (sizeChanged) {
sizeChanged = false;
final Pane view = floatingPane;
Envelope2D bounds = new Envelope2D(null, view.getLayoutX(), view.getLayoutY(), view.getWidth(), view.getHeight());
if (bounds.isEmpty())
return;
setDisplayBounds(bounds);
}
/*
* Compute the `objectiveToDisplay` only before the first rendering, because the display
* bounds may not be known before (it may be zero at the time `MapCanvas` is initialized).
* This code is executed only once for a new map.
*/
if (invalidObjectiveToDisplay) {
final Envelope2D target = getDisplayBounds();
if (target == null) {
// Bounds are still unknown. Another repaint event will happen when they will become known.
return;
}
invalidObjectiveToDisplay = false;
final GridExtent extent = new GridExtent(null, new long[] { Math.round(target.getMinX()), Math.round(target.getMinY()) }, new long[] { Math.round(target.getMaxX()), Math.round(target.getMaxY()) }, false);
/*
* If `setObjectiveBounds(…)` has been invoked (as it should be), initialize the affine
* transform to values which will allow this canvas to contain fully the objective bounds.
* Otherwise the transform is initialized to an identity transform (should not happen often).
* If a CRS is present, it is used for deciding if we need to swap or flip axes.
*/
CoordinateReferenceSystem objectiveCRS;
final LinearTransform crsToDisplay;
if (objectiveBounds != null) {
objectiveCRS = objectiveBounds.getCoordinateReferenceSystem();
final MatrixSIS m;
if (objectiveCRS != null) {
AxisDirection[] srcAxes = CoordinateSystems.getAxisDirections(objectiveCRS.getCoordinateSystem());
m = Matrices.createTransform(objectiveBounds, srcAxes, target, toDisplayDirections(srcAxes));
} else {
m = Matrices.createTransform(objectiveBounds, target);
}
Matrices.forceUniformScale(m, 0, new double[] { target.getCenterX(), target.getCenterY() });
crsToDisplay = MathTransforms.linear(m);
if (objectiveCRS == null) {
objectiveCRS = extent.toEnvelope(crsToDisplay.inverse()).getCoordinateReferenceSystem();
/*
* Above code tried to provide a non-null CRS on a "best effort" basis. The objective CRS
* may still be null, there is no obvious answer against that. It is not the display CRS
* if the "display to objective" transform is not identity. A grid CRS is not appropriate
* neither, otherwise `extent.toEnvelope(…)` would have found it.
*/
}
} else {
objectiveCRS = getDisplayCRS();
crsToDisplay = MathTransforms.identity(BIDIMENSIONAL);
}
setGridGeometry(new GridGeometry(extent, PixelInCell.CELL_CORNER, crsToDisplay.inverse(), objectiveCRS));
transform.setToIdentity();
}
} catch (TransformException | RenderException ex) {
restoreCursorAfterPaint();
isRendering.set(false);
errorOccurred(ex);
return;
}
/*
* If a temporary zoom, rotation or translation has been applied using JavaFX transform API,
* replace that temporary transform by a "permanent" adjustment of the `objectiveToDisplay`
* transform. It allows SIS to get new data for the new visible area and resolution.
* Do not reset `transform` to identity now; we need to continue accumulating gestures
* that may happen while the rendering is done in a background thread.
*/
changeInProgress.setToTransform(transform);
if (!transform.isIdentity()) {
transformDisplayCoordinates(new AffineTransform(transform.getMxx(), transform.getMyx(), transform.getMxy(), transform.getMyy(), transform.getTx(), transform.getTy()));
}
/*
* Invoke `createWorker(…)` only after we finished above configuration, because that method
* may take a snapshot of current canvas state in preparation for use in background threads.
* Take the value of `contentChangeCount` only now because above code may have indirect calls
* to `requestRepaint()`.
*/
renderedContentStamp = contentChangeCount;
final Renderer context = createRenderer();
if (context != null && context.initialize(floatingPane)) {
final Task<?> worker = createWorker(context);
assert renderingInProgress == null;
BackgroundThreads.execute(worker);
// Set after we know that the task has been scheduled.
renderingInProgress = worker;
if (!isMouseChangeScheduled) {
DelayedExecutor.schedule(new CursorChange());
isMouseChangeScheduled = true;
}
} else {
if (!hasError) {
clearError();
}
isRendering.set(false);
restoreCursorAfterPaint();
}
}
Aggregations