Skip to content

Commit b719593

Browse files
committed
style(swingui): simplify Generic2DDisplay rendering
1 parent 93a9f5b commit b719593

1 file changed

Lines changed: 121 additions & 90 deletions

File tree

alchemist-swingui/src/main/java/it/unibo/alchemist/boundary/swingui/monitor/impl/Generic2DDisplay.java

Lines changed: 121 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -338,110 +338,141 @@ protected void drawEnvOnView(final Graphics2D g) {
338338
return;
339339
}
340340
accessData();
341-
if (hooked.isPresent()) {
342-
final P hcoor = positions.get(hooked.get());
343-
final Point hp = wormhole.getViewPoint(hcoor);
344-
if (hp.distance(getCenter()) > FREEDOM_RADIUS) {
345-
wormhole.setViewPosition(hp);
346-
}
341+
updateHookedNodeView();
342+
final Map<Node<T>, Point> onView = computeNodesOnView();
343+
g.setColor(Color.BLACK);
344+
drawObstacles(g);
345+
drawLinks(g, onView);
346+
releaseData();
347+
moveSelectedNodesOnView(onView);
348+
g.setColor(Color.GREEN);
349+
if (effectStack != null) {
350+
effectStack.forEach(effect -> onView.forEach((node, point) ->
351+
effect.apply(g, node, currentEnv, wormhole)));
352+
}
353+
highlightClosestNode(g, onView);
354+
drawSelectionRectangle(g, onView);
355+
highlightSelectedNodes(g, onView);
356+
}
357+
358+
private Map<Node<T>, Point> computeNodesOnView() {
359+
return positions.entrySet().parallelStream()
360+
.map(pair -> new Pair<>(pair.getKey(), wormhole.getViewPoint(pair.getValue())))
361+
.filter(p -> wormhole.isInsideView(p.getSecond()))
362+
.collect(Collectors.toMap(Pair::getKey, Pair::getValue));
363+
}
364+
365+
private void updateHookedNodeView() {
366+
if (hooked.isEmpty()) {
367+
return;
368+
}
369+
final P hookedCoordinates = positions.get(hooked.get());
370+
final Point hookedPoint = wormhole.getViewPoint(hookedCoordinates);
371+
if (hookedPoint.distance(getCenter()) > FREEDOM_RADIUS) {
372+
wormhole.setViewPosition(hookedPoint);
373+
}
374+
}
375+
376+
private void drawObstacles(final Graphics2D g) {
377+
if (obstacles == null) {
378+
return;
347379
}
348380
/*
349-
* Compute nodes in sight and their screen position
381+
* This currently draws all obstacles, even when they are fully outside the viewport.
350382
*/
351-
final Map<Node<T>, Point> onView = positions.entrySet().parallelStream()
352-
.map(pair -> new Pair<>(pair.getKey(), wormhole.getViewPoint(pair.getValue())))
353-
.filter(p -> wormhole.isInsideView(p.getSecond()))
354-
.collect(Collectors.toMap(Pair::getKey, Pair::getValue));
355-
g.setColor(Color.BLACK);
356-
if (obstacles != null) {
357-
/*
358-
* TODO: only draw obstacles if on view
359-
*/
360-
obstacles.parallelStream()
361-
.map(this::convertObstacle)
362-
.forEachOrdered(g::fill);
383+
obstacles.parallelStream()
384+
.map(this::convertObstacle)
385+
.forEachOrdered(g::fill);
386+
}
387+
388+
private void drawLinks(final Graphics2D g, final Map<Node<T>, Point> onView) {
389+
if (!paintLinks) {
390+
return;
363391
}
364-
if (paintLinks) {
365-
g.setColor(Color.GRAY);
366-
onView.keySet().parallelStream()
367-
.map(neighbors::get)
368-
.flatMap(neigh ->
369-
neigh.getNeighbors().parallelStream()
370-
.map(node ->
371-
node.compareTo(neigh.getCenter()) > 0
372-
? new Pair<>(neigh.getCenter(), node)
373-
: new Pair<>(node, neigh.getCenter())
374-
)
375-
)
376-
.distinct()
377-
.map(pair ->
378-
mapPair(
379-
pair,
380-
node -> Optional
381-
.ofNullable(onView.get(node))
382-
.orElse(wormhole.getViewPoint(positions.get(node)))
392+
g.setColor(Color.GRAY);
393+
onView.keySet().parallelStream()
394+
.map(neighbors::get)
395+
.flatMap(neigh ->
396+
neigh.getNeighbors().parallelStream()
397+
.map(node ->
398+
node.compareTo(neigh.getCenter()) > 0
399+
? new Pair<>(neigh.getCenter(), node)
400+
: new Pair<>(node, neigh.getCenter())
383401
)
402+
)
403+
.distinct()
404+
.map(pair ->
405+
mapPair(
406+
pair,
407+
node -> Optional
408+
.ofNullable(onView.get(node))
409+
.orElse(wormhole.getViewPoint(positions.get(node)))
384410
)
385-
.forEachOrdered(line -> {
386-
final Point p1 = line.getFirst();
387-
final Point p2 = line.getSecond();
388-
g.drawLine(p1.x, p1.y, p2.x, p2.y);
389-
});
411+
)
412+
.forEachOrdered(line -> {
413+
final Point p1 = line.getFirst();
414+
final Point p2 = line.getSecond();
415+
g.drawLine(p1.x, p1.y, p2.x, p2.y);
416+
});
417+
}
418+
419+
private void moveSelectedNodesOnView(final Map<Node<T>, Point> onView) {
420+
if (!isDraggingMouse || status != ViewStatus.MOVING_SELECTED_NODES || originPoint == null || endingPoint == null) {
421+
return;
390422
}
391-
releaseData();
392-
if (
393-
isDraggingMouse
394-
&& status == ViewStatus.MOVING_SELECTED_NODES
395-
&& originPoint != null
396-
&& endingPoint != null
397-
) {
398-
for (final Node<T> n : selectedNodes) {
399-
if (onView.containsKey(n)) {
400-
onView.put(n, new Point(onView.get(n).x + (endingPoint.x - originPoint.x),
401-
onView.get(n).y + (endingPoint.y - originPoint.y)));
402-
}
423+
for (final Node<T> node : selectedNodes) {
424+
if (onView.containsKey(node)) {
425+
onView.put(
426+
node,
427+
new Point(
428+
onView.get(node).x + (endingPoint.x - originPoint.x),
429+
onView.get(node).y + (endingPoint.y - originPoint.y)
430+
)
431+
);
403432
}
404433
}
405-
g.setColor(Color.GREEN);
406-
if (effectStack != null) {
407-
effectStack.forEach(effect -> onView.forEach((node, point) ->
408-
effect.apply(g, node, currentEnv, wormhole)));
409-
}
410-
if (isCloserNodeMarked()) {
411-
final Optional<Map.Entry<Node<T>, Point>> closest = onView.entrySet().parallelStream()
412-
.min((pair1, pair2) -> {
413-
final Point p1 = pair1.getValue();
414-
final Point p2 = pair2.getValue();
415-
final double d1 = Math.hypot(p1.x - mouseX, p1.y - mouseY);
416-
final double d2 = Math.hypot(p2.x - mouseX, p2.y - mouseY);
417-
return Double.compare(d1, d2);
418-
});
419-
if (closest.isPresent()) {
420-
nearest = closest.get().getKey();
421-
final int nearestX = closest.get().getValue().x;
422-
final int nearestY = closest.get().getValue().y;
423-
drawFriedEgg(g, nearestX, nearestY, Color.RED, Color.YELLOW);
424-
}
425-
} else {
434+
}
435+
436+
private void highlightClosestNode(final Graphics2D g, final Map<Node<T>, Point> onView) {
437+
if (!isCloserNodeMarked()) {
426438
nearest = null;
439+
return;
427440
}
428-
if (isDraggingMouse && status == ViewStatus.SELECTING_NODES && originPoint != null && endingPoint != null) {
429-
g.setColor(Color.BLACK);
430-
final int x = Math.min(originPoint.x, endingPoint.x);
431-
final int y = Math.min(originPoint.y, endingPoint.y);
432-
final int width = Math.abs(endingPoint.x - originPoint.x);
433-
final int height = Math.abs(endingPoint.y - originPoint.y);
434-
g.drawRect(x, y, width, height);
435-
selectedNodes = onView.entrySet().parallelStream()
436-
.filter(nodes -> isInsideRectangle(nodes.getValue(), x, y, width, height))
437-
.map(Map.Entry::getKey)
438-
.collect(Collectors.toSet());
441+
onView.entrySet().parallelStream()
442+
.min((pair1, pair2) -> Double.compare(distanceFromMouse(pair1.getValue()), distanceFromMouse(pair2.getValue())))
443+
.ifPresent(closest -> {
444+
nearest = closest.getKey();
445+
final Point point = closest.getValue();
446+
drawFriedEgg(g, point.x, point.y, Color.RED, Color.YELLOW);
447+
});
448+
}
449+
450+
private double distanceFromMouse(final Point point) {
451+
return Math.hypot(point.x - mouseX, point.y - mouseY);
452+
}
453+
454+
private void drawSelectionRectangle(final Graphics2D g, final Map<Node<T>, Point> onView) {
455+
if (!isDraggingMouse || status != ViewStatus.SELECTING_NODES || originPoint == null || endingPoint == null) {
456+
return;
439457
}
458+
g.setColor(Color.BLACK);
459+
final int x = Math.min(originPoint.x, endingPoint.x);
460+
final int y = Math.min(originPoint.y, endingPoint.y);
461+
final int width = Math.abs(endingPoint.x - originPoint.x);
462+
final int height = Math.abs(endingPoint.y - originPoint.y);
463+
g.drawRect(x, y, width, height);
464+
selectedNodes = onView.entrySet().parallelStream()
465+
.filter(nodes -> isInsideRectangle(nodes.getValue(), x, y, width, height))
466+
.map(Map.Entry::getKey)
467+
.collect(Collectors.toSet());
468+
}
469+
470+
private void highlightSelectedNodes(final Graphics2D g, final Map<Node<T>, Point> onView) {
440471
selectedNodes.parallelStream()
441-
.map(e -> Optional.ofNullable(onView.get(e)))
472+
.map(node -> Optional.ofNullable(onView.get(node)))
442473
.filter(Optional::isPresent)
443474
.map(Optional::get)
444-
.forEachOrdered(p -> drawFriedEgg(g, p.x, p.y, Color.BLUE, Color.CYAN));
475+
.forEachOrdered(point -> drawFriedEgg(g, point.x, point.y, Color.BLUE, Color.CYAN));
445476
}
446477

447478
private void drawFriedEgg(final Graphics g, final int x, final int y, final Color c1, final Color c2) {
@@ -899,7 +930,7 @@ public void mouseReleased(final MouseEvent e) {
899930
});
900931
}
901932
} else {
902-
// TODO: display proper error message
933+
// Surface this warning through the UI if interactive feedback is added here.
903934
L.warn("Can not handle node movement on a finished simulation.");
904935
}
905936
} else {

0 commit comments

Comments
 (0)