Skip to content

Commit

Permalink
implement Visualizer multi select of bots
Browse files Browse the repository at this point in the history
See merge request main/Sumatra!1882

sumatra-commit: b6968c028d84b859804e6f9e72c9c7e7c1816c9e
  • Loading branch information
g3force authored and TIGERs GitLab committed Nov 9, 2024
1 parent 09f4f7a commit dec0f2c
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package edu.tigers.sumatra.drawable;

import edu.tigers.sumatra.ids.BotID;
import edu.tigers.sumatra.ids.ETeamColor;
import edu.tigers.sumatra.math.vector.IVector2;
import edu.tigers.sumatra.math.vector.Vector2;

Expand Down Expand Up @@ -108,8 +109,8 @@ public DrawableBotPattern(
super(pos, angle, radius, center2DribblerDist);
this.botID = botID;

setBorderColor(null);
setFillColor(Color.black);
setBorderColor(botID.getTeamColor() == ETeamColor.YELLOW ? Color.white : Color.black);
setFillColor(botID.getTeamColor() == ETeamColor.YELLOW ? Color.darkGray : Color.black);
setDrawDirection(false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public void process(final WorldFrameWrapper wfw, final ShapeMap shapeMap)

private void drawLine(List<IDrawableShape> list, IDrawableShape newShape)
{
list.add(newShape.setColor(Color.WHITE).setStrokeWidth(Geometry.getLineWidth()));
list.add(newShape.setColor(Color.WHITE).setStrokeWidth(Geometry.getLineWidth() * 2));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ public final class EFieldPanelShapeLayer
F.category(PANEL).layerName("Ruler").visibleByDefault(true));
public static final IShapeLayerIdentifier RECORDING = F.create(
F.category(PANEL).layerName("Recording").visibleByDefault(true));
public static final IShapeLayerIdentifier SELECTION = F.create(
F.category(PANEL).layerName("Selection").visibleByDefault(true));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2009 - 2024, DHBW Mannheim - TIGERs Mannheim
*/

package edu.tigers.sumatra.visualizer.field;

import edu.tigers.sumatra.ids.BotID;

import java.util.List;


public interface ISelectedRobotsChanged
{
void selectedRobotsChanged(List<BotID> selectedBots);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,48 @@
package edu.tigers.sumatra.visualizer.field;

import edu.tigers.sumatra.clock.FpsCounter;
import edu.tigers.sumatra.drawable.DrawableCircle;
import edu.tigers.sumatra.drawable.DrawableFieldBackground;
import edu.tigers.sumatra.drawable.DrawableLine;
import edu.tigers.sumatra.drawable.DrawableRectangle;
import edu.tigers.sumatra.drawable.EFieldTurn;
import edu.tigers.sumatra.drawable.ShapeMap;
import edu.tigers.sumatra.drawable.ShapeMapSource;
import edu.tigers.sumatra.geometry.Geometry;
import edu.tigers.sumatra.ids.BotID;
import edu.tigers.sumatra.math.circle.Circle;
import edu.tigers.sumatra.math.line.ILineSegment;
import edu.tigers.sumatra.math.rectangle.Rectangle;
import edu.tigers.sumatra.math.vector.IVector2;
import edu.tigers.sumatra.math.vector.Vector2;
import edu.tigers.sumatra.views.ISumatraPresenter;
import edu.tigers.sumatra.visualizer.field.components.CoordinatesMouseAdapter;
import edu.tigers.sumatra.visualizer.field.components.DragMouseAdapter;
import edu.tigers.sumatra.visualizer.field.components.DrawableCoordinates;
import edu.tigers.sumatra.visualizer.field.components.DrawableFps;
import edu.tigers.sumatra.visualizer.field.components.DrawableRuler;
import edu.tigers.sumatra.visualizer.field.components.RobotPositionerMouseAdapter;
import edu.tigers.sumatra.visualizer.field.components.RulerMouseAdapter;
import edu.tigers.sumatra.visualizer.field.components.SelectionRectangleMouseAdapter;
import edu.tigers.sumatra.visualizer.field.components.ZoomMouseAdapter;
import edu.tigers.sumatra.visualizer.field.recorder.DrawableRecordingAnimation;
import edu.tigers.sumatra.wp.IWorldFrameObserver;
import edu.tigers.sumatra.wp.data.ITrackedBot;
import edu.tigers.sumatra.wp.data.WorldFrameWrapper;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;

import javax.swing.SwingUtilities;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -58,17 +74,38 @@ public class VisualizerFieldPresenter implements ISumatraPresenter, IWorldFrameO

@Setter
private DrawableRuler drawableRuler = null;

@Setter
private DrawableRectangle drawableSelectionBox = null;
@Setter
private Rectangle selectionBox = null;

@Setter
private ILineSegment robotPositionerLine = null;
@Setter
private DrawableLine drawableRobotPositionerLine = null;

private Map<BotID, ITrackedBot> bots = new HashMap<>();

@Setter
private List<BotID> selectedBots = new ArrayList<>();

@Setter
private List<DrawableCoordinates> coordinates = List.of();
private final FpsCounter fpsCounter = new FpsCounter();
private final DrawableFps drawableFps = new DrawableFps(fpsCounter);
@Setter
private DrawableRecordingAnimation drawableRecordingAnimation;

@Setter
private ISelectedRobotsChanged selectedRobotsChangedListener;

@Getter
private final List<FieldMouseInteraction> onFieldClicks = new ArrayList<>();
@Getter
private final List<FieldMouseInteraction> onMouseMoves = new ArrayList<>();
@Getter
private final List<FieldRobotMoveInteraction> onRobotMove = new ArrayList<>();

private List<MouseAdapter> mouseAdapters = List.of();

Expand All @@ -85,7 +122,11 @@ public void onStart()
new RulerMouseAdapter(this::getMousePointGlobal, this::setDrawableRuler),
new ZoomMouseAdapter(fieldPane::scale),
new DragMouseAdapter(fieldPane::drag),
new InteractionMouseEvents()
new SelectionRectangleMouseAdapter(this::getMousePointGlobal, this::setDrawableSelectionBox,
this::setSelectionBox),
new InteractionMouseEvents(),
new RobotPositionerMouseAdapter(this::getMousePointGlobal, this::setDrawableRobotPositionerLine,
this::setRobotPositionerLine)
);
mouseAdapters.forEach(fieldPanel::addMouseAdapter);
fieldPanel.setVisible(true);
Expand All @@ -105,6 +146,13 @@ public void onStop()
}


@Override
public void onNewWorldFrame(WorldFrameWrapper wFrameWrapper)
{
this.bots = wFrameWrapper.getSimpleWorldFrame().getBots();
}


@Override
public void onNewShapeMap(final long timestamp, final ShapeMap shapeMap, final ShapeMapSource source)
{
Expand Down Expand Up @@ -224,6 +272,54 @@ private void updateInternalShapeLayers()
panelShapeMap.get(EFieldPanelShapeLayer.COORDINATES).clear();
panelShapeMap.get(EFieldPanelShapeLayer.COORDINATES).addAll(coordinates);

panelShapeMap.get(EFieldPanelShapeLayer.SELECTION).clear();
Optional.ofNullable(drawableSelectionBox)
.ifPresent(box -> panelShapeMap.get(EFieldPanelShapeLayer.SELECTION).add(box));

Optional.ofNullable(drawableRobotPositionerLine)
.ifPresent(line -> panelShapeMap.get(EFieldPanelShapeLayer.SELECTION).add(line));

if (selectionBox != null)
{
selectedBots.clear();
bots.values()
.stream()
.filter(bot -> selectionBox.isPointInShape(bot.getPos()))
.forEach(bot ->
{
panelShapeMap.get(EFieldPanelShapeLayer.SELECTION).add(new DrawableCircle(
Circle.createCircle(bot.getPos(), Geometry.getBotRadius() + 4))
.setColor(new Color(255, 180, 0, 255)));
selectedBots.add(bot.getBotId());
});
selectedRobotsChangedListener.selectedRobotsChanged(selectedBots);
} else if (bots != null)
{
bots.values()
.stream()
.filter(bot -> selectedBots.contains(bot.getBotId()))
.forEach(bot -> panelShapeMap.get(EFieldPanelShapeLayer.SELECTION).add(new DrawableCircle(
Circle.createCircle(bot.getPos(), Geometry.getBotRadius() + 4))
.setColor(new Color(0, 225, 255, 255))));
}

if (robotPositionerLine != null && selectedBots != null && !selectedBots.isEmpty())
{
int numBots = selectedBots.size();
var start = robotPositionerLine.getPathStart();
var end = robotPositionerLine.getPathEnd();
var startToEnd = end.subtractNew(start);

double step = getStepSize(startToEnd, numBots);
for (int i = 0; i < numBots; i++)
{
var pos = start.addNew(startToEnd.scaleToNew(step * i));
panelShapeMap.get(EFieldPanelShapeLayer.SELECTION).add(new DrawableCircle(
Circle.createCircle(pos, Geometry.getBotRadius() + 4))
.setColor(new Color(0, 225, 255, 255)));
}
}

panelShapeMap.get(EFieldPanelShapeLayer.RULER).clear();
Optional.ofNullable(drawableRuler)
.ifPresent(ruler -> panelShapeMap.get(EFieldPanelShapeLayer.RULER).add(ruler));
Expand Down Expand Up @@ -265,7 +361,35 @@ private class InteractionMouseEvents extends MouseAdapter
public void mouseClicked(final MouseEvent e)
{
IVector2 globalPos = getMousePointGlobal(e.getX(), e.getY());
onFieldClicks.forEach(c -> c.onInteraction(globalPos, e));
if (e.isControlDown())
{
selectedBots.clear();
} else
{
onFieldClicks.forEach(c -> c.onInteraction(globalPos, e));
}
}


@Override
public void mouseReleased(MouseEvent e)
{
if (e.isControlDown() && SwingUtilities.isRightMouseButton(e) && robotPositionerLine != null
&& selectedBots != null && !selectedBots.isEmpty())
{
var start = robotPositionerLine.getPathStart();
var end = robotPositionerLine.getPathEnd();
var startToEnd = end.subtractNew(start);
int numBots = selectedBots.size();

double step = getStepSize(startToEnd, numBots);
for (int i = 0; i < numBots; i++)
{
var pos = start.addNew(startToEnd.scaleToNew(step * i));
final BotID botId = selectedBots.get(i);
onRobotMove.forEach(c -> c.onInteraction(botId, pos));
}
}
}


Expand All @@ -274,9 +398,29 @@ public void mouseMoved(final MouseEvent e)
{
IVector2 lastMousePoint = getMousePointGlobal(e.getX(), e.getY());
onMouseMoves.forEach(c -> c.onInteraction(lastMousePoint, e));
update();
}
}


private static double getStepSize(Vector2 startToEnd, int numBots)
{
var distance = startToEnd.getLength();
double step = distance / 2;
if (numBots > 1)
{
step = distance / (numBots - 1);
}
return step;
}


@FunctionalInterface
public interface FieldRobotMoveInteraction
{
void onInteraction(BotID id, IVector2 pos);
}

@FunctionalInterface
public interface FieldMouseInteraction
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2009 - 2022, DHBW Mannheim - TIGERs Mannheim
*/

package edu.tigers.sumatra.visualizer.field.components;

import edu.tigers.sumatra.drawable.DrawableLine;
import edu.tigers.sumatra.math.line.ILineSegment;
import edu.tigers.sumatra.math.line.Lines;
import edu.tigers.sumatra.math.vector.IVector2;
import edu.tigers.sumatra.visualizer.field.callbacks.MousePointTransformer;
import lombok.RequiredArgsConstructor;

import javax.swing.SwingUtilities;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.function.Consumer;


@RequiredArgsConstructor
public class RobotPositionerMouseAdapter extends MouseAdapter
{
private final MousePointTransformer mousePointTransformer;
private final Consumer<DrawableLine> drawableLineConsumer;
private final Consumer<ILineSegment> lineConsumer;
private IVector2 dragPointStart;

@Override
public void mousePressed(final MouseEvent e)
{
dragPointStart = mousePointTransformer.toGlobal(e.getX(), e.getY());
}


@Override
public void mouseDragged(final MouseEvent e)
{
if (SwingUtilities.isRightMouseButton(e) && (e.isControlDown()) && dragPointStart != null)
{
IVector2 dragPointEnd = mousePointTransformer.toGlobal(e.getX(), e.getY());
ILineSegment line = Lines.segmentFromPoints(dragPointStart, dragPointEnd);
DrawableLine drawableLine = new DrawableLine(line);
drawableLineConsumer.accept(drawableLine);
lineConsumer.accept(line);
}
}


@Override
public void mouseReleased(final MouseEvent e)
{
dragPointStart = null;
drawableLineConsumer.accept(null);
lineConsumer.accept(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void mousePressed(final MouseEvent e)
@Override
public void mouseDragged(final MouseEvent e)
{
if (SwingUtilities.isLeftMouseButton(e) && (e.isControlDown() || e.isAltDown()) && dragPointStart != null)
if (SwingUtilities.isLeftMouseButton(e) && (e.isAltDown()) && dragPointStart != null)
{
IVector2 dragPointEnd = mousePointTransformer.toGlobal(e.getX(), e.getY());
DrawableRuler ruler = new DrawableRuler(dragPointStart, dragPointEnd);
Expand Down
Loading

0 comments on commit dec0f2c

Please sign in to comment.