Skip to content

Commit 03c36b8

Browse files
committed
Merge pull request #222 from ThomasJClark/nt
NetworkTables
2 parents 1583fc7 + c1554a3 commit 03c36b8

28 files changed

+570
-50
lines changed

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ project(":core") {
9191
repositories {
9292
flatDir {
9393
dirs 'libs'
94+
maven {
95+
url = "http://first.wpi.edu/FRC/roborio/maven/development"
96+
}
9497
}
9598
}
9699

@@ -106,6 +109,7 @@ project(":core") {
106109
compile group: 'com.google.guava', name: 'guava', version: '18.0'
107110
compile group: 'com.google.inject', name: 'guice', version: '4.0'
108111
compile group: 'com.google.inject.extensions', name: 'guice-assistedinject', version: '4.0'
112+
compile group: 'edu.wpi.first.wpilib.networktables.java', name: 'NetworkTables', version: '3.0.0-SNAPSHOT', classifier: 'desktop'
109113
}
110114

111115
mainClassName = 'edu.wpi.grip.core.Main'

buildSrc/src/main/java/edu/wpi/gripgenerator/defaults/PrimitiveDefaultValue.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,28 +45,28 @@ public PrimitiveDefaultValue(PrimitiveType type) {
4545
);
4646
break;
4747
case Int:
48-
this.viewValue = "SPINNER";
48+
this.viewValue = "TEXT";
4949
this.domainValue = createDomainValueExpression(
5050
new IntegerLiteralExpr("Integer.MIN_VALUE"),
5151
new IntegerLiteralExpr("Integer.MAX_VALUE")
5252
);
5353
break;
5454
case Float:
55-
this.viewValue = "SPINNER";
55+
this.viewValue = "TEXT";
5656
this.domainValue = createDomainValueExpression(
5757
new DoubleLiteralExpr("-Float.MAX_VALUE"),
5858
new DoubleLiteralExpr("Float.MAX_VALUE")
5959
);
6060
break;
6161
case Double:
62-
this.viewValue = "SPINNER";
62+
this.viewValue = "TEXT";
6363
this.domainValue = createDomainValueExpression(
6464
new DoubleLiteralExpr("-Double.MAX_VALUE"),
6565
new DoubleLiteralExpr("Double.MAX_VALUE")
6666
);
6767
break;
6868
case Char:
69-
this.viewValue = "SPINNER";
69+
this.viewValue = "TEXT";
7070
this.domainValue = createDomainValueExpression(
7171
new CharLiteralExpr(Character.toString(Character.MIN_VALUE)),
7272
new CharLiteralExpr(Character.toString(Character.MAX_VALUE))

core/src/main/java/edu/wpi/grip/core/Operation.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ default void perform(InputSocket<?>[] inputs, OutputSocket<?>[] outputs, Optiona
6161
perform(inputs, outputs);
6262
}
6363

64-
@Deprecated
6564
default void perform(InputSocket<?>[] inputs, OutputSocket<?>[] outputs) {
6665
throw new UnsupportedOperationException("Perform was not overridden");
6766
}

core/src/main/java/edu/wpi/grip/core/Pipeline.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,18 @@ public class Pipeline {
3232
private final List<Source> sources = new ArrayList<>();
3333
private final List<Step> steps = new ArrayList<>();
3434
private final Set<Connection> connections = new HashSet<>();
35+
private ProjectSettings settings = new ProjectSettings();
3536

3637
/**
3738
* Remove everything in the pipeline
3839
*/
3940
public void clear() {
4041
// These streams are both collected into lists because streams cannot modify their source. Sending a
4142
// StepRemovedEvent or SourceRemovedEvent modifies this.steps or this.sources.
42-
this.steps.stream().collect(Collectors.toList()).forEach(this::removeStep);
43+
this.steps.stream()
44+
.map(StepRemovedEvent::new)
45+
.collect(Collectors.toList())
46+
.forEach(this.eventBus::post);
4347

4448
this.sources.stream()
4549
.map(SourceRemovedEvent::new)
@@ -69,6 +73,15 @@ public Set<Connection> getConnections() {
6973
return Collections.unmodifiableSet(this.connections);
7074
}
7175

76+
/*
77+
* @return The current per-project settings. This object may become out of date if the settings are edited
78+
* by the user, so objects requiring a preference value should also subscribe to {@link ProjectSettingsChangedEvent}
79+
* to get updates.
80+
*/
81+
public ProjectSettings getProjectSettings() {
82+
return settings;
83+
}
84+
7285
/**
7386
* @return true if a connection can be made from the given output socket to the given input socket
7487
*/
@@ -183,4 +196,9 @@ public void onConnectionRemoved(ConnectionRemovedEvent event) {
183196
this.connections.remove(event.getConnection());
184197
this.eventBus.unregister(event.getConnection());
185198
}
199+
200+
@Subscribe
201+
public void onProjectSettingsChanged(ProjectSettingsChangedEvent event) {
202+
this.settings = event.getProjectSettings();
203+
}
186204
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package edu.wpi.grip.core;
2+
3+
import com.google.common.base.MoreObjects;
4+
5+
/**
6+
* This object holds settings that are saved in project files. This includes things like team numbers, which need to
7+
* be preserved when deploying the project.
8+
*/
9+
public class ProjectSettings implements Cloneable {
10+
11+
/**
12+
* What protocol to use to publish values. Only NetworkTables is supported right now, but in the future we may
13+
* make the publish operations work with other protocols like ROS.
14+
*/
15+
public enum NetworkProtocol {
16+
NETWORK_TABLES,
17+
NONE
18+
}
19+
20+
private NetworkProtocol networkProtocol = NetworkProtocol.NETWORK_TABLES;
21+
private int teamNumber = 0;
22+
23+
public void setNetworkProtocol(NetworkProtocol networkProtocol) {
24+
this.networkProtocol = networkProtocol;
25+
}
26+
27+
public NetworkProtocol getNetworkProtocol() {
28+
return networkProtocol;
29+
}
30+
31+
public void setTeamNumber(int teamNumber) {
32+
this.teamNumber = teamNumber;
33+
}
34+
35+
public int getTeamNumber() {
36+
return teamNumber;
37+
}
38+
39+
@Override
40+
public String toString() {
41+
return MoreObjects.toStringHelper(this)
42+
.add("networkProtocol", networkProtocol)
43+
.add("teamNumber", teamNumber)
44+
.toString();
45+
}
46+
47+
@Override
48+
public ProjectSettings clone() {
49+
try {
50+
return (ProjectSettings) super.clone();
51+
} catch (CloneNotSupportedException impossible) {
52+
return null;
53+
}
54+
}
55+
}

core/src/main/java/edu/wpi/grip/core/SocketHint.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* interface to learn how to talk to <code>Algorithm</code>s.
1616
*/
1717
public class SocketHint<T> {
18-
public enum View {NONE, SPINNER, SLIDER, RANGE, SELECT, CHECKBOX}
18+
public enum View {NONE, TEXT, SLIDER, RANGE, SELECT, CHECKBOX}
1919

2020
private final String identifier;
2121
private final Class<T> type;

core/src/main/java/edu/wpi/grip/core/SocketHints.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,26 @@ public static SocketHint<Number> createNumberSliderSocketHint(final String ident
4343

4444
public static SocketHint<Number> createNumberSpinnerSocketHint(final String identifier, final Number number,
4545
final Number low, final Number high) {
46-
return createNumberSocketHintBuilder(identifier, number, new Number[]{low, high}).view(SocketHint.View.SPINNER).build();
46+
return createNumberSocketHintBuilder(identifier, number, new Number[]{low, high}).view(SocketHint.View.TEXT).build();
4747
}
4848

4949
public static SocketHint<Number> createNumberSpinnerSocketHint(final String identifier, final Number number) {
50-
return createNumberSocketHintBuilder(identifier, number).view(SocketHint.View.SPINNER).build();
50+
return createNumberSocketHintBuilder(identifier, number).view(SocketHint.View.TEXT).build();
5151
}
5252

5353
public static SocketHint<List> createNumberListRangeSocketHint(final String identifier, final Number low, final Number high) {
5454
return createNumberListSocketHintBuilder(identifier, new Number[]{low, high})
5555
.view(SocketHint.View.RANGE)
5656
.build();
5757
}
58+
59+
public static SocketHint<String> createTextSocketHint(final String identifier, final String str) {
60+
return new SocketHint.Builder<>(String.class)
61+
.identifier(identifier)
62+
.initialValue(str)
63+
.view(SocketHint.View.TEXT)
64+
.build();
65+
}
5866
}
5967

6068
/**
@@ -84,7 +92,6 @@ public static SocketHint<Number> createNumberSocketHint(final String identifier,
8492
}
8593
}
8694

87-
@SuppressWarnings("unchecked")
8895
public static <T extends Enum<T>> SocketHint<T> createEnumSocketHint(final String identifier,
8996
final T defaultValue) {
9097
return new SocketHint.Builder(defaultValue.getClass())
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package edu.wpi.grip.core.events;
2+
3+
import edu.wpi.grip.core.ProjectSettings;
4+
5+
import static com.google.common.base.Preconditions.checkNotNull;
6+
7+
/**
8+
* This event is posted after the {@link ProjectSettings} are changed so anything that relies on them can immediately
9+
* update without restarting the application.
10+
*/
11+
public class ProjectSettingsChangedEvent {
12+
private final ProjectSettings projectSettings;
13+
14+
public ProjectSettingsChangedEvent(ProjectSettings projectSettings) {
15+
this.projectSettings = checkNotNull(projectSettings, "Project settings cannot be null");
16+
}
17+
18+
public ProjectSettings getProjectSettings() {
19+
return projectSettings;
20+
}
21+
}

core/src/main/java/edu/wpi/grip/core/operations/Operations.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package edu.wpi.grip.core.operations;
22

33
import com.google.common.eventbus.EventBus;
4+
import edu.wpi.grip.core.Operation;
45
import edu.wpi.grip.core.events.OperationAddedEvent;
56
import edu.wpi.grip.core.operations.composite.*;
7+
import edu.wpi.grip.core.operations.networktables.NTPublishOperation;
68
import edu.wpi.grip.core.operations.opencv.MatFieldAccessor;
79
import edu.wpi.grip.core.operations.opencv.MinMaxLoc;
810
import edu.wpi.grip.core.operations.opencv.NewPointOperation;
@@ -30,5 +32,9 @@ public static void addOperations(EventBus eventBus) {
3032
eventBus.post(new OperationAddedEvent(new NewPointOperation()));
3133
eventBus.post(new OperationAddedEvent(new NewSizeOperation()));
3234
eventBus.post(new OperationAddedEvent(new MatFieldAccessor()));
35+
36+
Operation publishContours = new NTPublishOperation<>(ContoursReport.class);
37+
eventBus.register(publishContours);
38+
eventBus.post(new OperationAddedEvent(publishContours));
3339
}
3440
}
Lines changed: 84 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
package edu.wpi.grip.core.operations.composite;
22

3-
import static org.bytedeco.javacpp.opencv_core.*;
3+
import edu.wpi.grip.core.operations.networktables.NTPublishable;
4+
import edu.wpi.grip.core.operations.networktables.NTValue;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
import java.util.Optional;
9+
10+
import static org.bytedeco.javacpp.opencv_core.MatVector;
11+
import static org.bytedeco.javacpp.opencv_core.Rect;
12+
import static org.bytedeco.javacpp.opencv_imgproc.boundingRect;
13+
import static org.bytedeco.javacpp.opencv_imgproc.contourArea;
414

515
/**
616
* The output of {@link FindContoursOperation}. This stores a list of contours (which is basically a list of points) in
717
* OpenCV objects, as well as the width and height of the image that the contours are from, to give context to the
818
* points.
919
*/
10-
public final class ContoursReport {
11-
private int rows, cols;
12-
private MatVector contours = new MatVector();
20+
public final class ContoursReport implements NTPublishable {
21+
private final int rows, cols;
22+
private final MatVector contours;
23+
private Optional<List<Rect>> boundingBoxes = Optional.empty();
1324

25+
/**
26+
* Construct an empty report. This is used as a default value for {@link edu.wpi.grip.core.Socket}s containing
27+
* ContoursReports.
28+
*/
1429
public ContoursReport() {
15-
this(new MatVector(), -1, -1);
30+
this(new MatVector(), 0, 0);
1631
}
1732

1833
public ContoursReport(MatVector contours, int rows, int cols) {
@@ -21,27 +36,81 @@ public ContoursReport(MatVector contours, int rows, int cols) {
2136
this.cols = cols;
2237
}
2338

24-
public void setContours(MatVector contours) {
25-
this.contours = contours;
39+
public int getRows() {
40+
return this.rows;
41+
}
42+
43+
public int getCols() {
44+
return this.cols;
2645
}
2746

2847
public MatVector getContours() {
2948
return this.contours;
3049
}
3150

32-
public void setRows(int rows) {
33-
this.rows = rows;
51+
/**
52+
* Compute the bounding boxes of all contours (if they haven't already been computed). Bounding boxes are used
53+
* to compute several different properties, so it's probably not a good idea to compute them over and over again.
54+
*/
55+
private synchronized List<Rect> computeBoundingBoxes() {
56+
if (!boundingBoxes.isPresent()) {
57+
List<Rect> bb = new ArrayList<>();
58+
for (int i = 0; i < contours.size(); i++) {
59+
bb.add(boundingRect(contours.get(i)));
60+
}
61+
62+
boundingBoxes = Optional.of(bb);
63+
}
64+
65+
return boundingBoxes.get();
3466
}
3567

36-
public void setCols(int cols) {
37-
this.cols = cols;
68+
@NTValue(key = "area")
69+
public double[] getArea() {
70+
final double[] areas = new double[(int) contours.size()];
71+
for (int i = 0; i < contours.size(); i++) {
72+
areas[i] = contourArea(contours.get(i));
73+
}
74+
return areas;
3875
}
3976

40-
public int getRows() {
41-
return this.rows;
77+
@NTValue(key = "centerX")
78+
public double[] getCenterX() {
79+
final double[] centers = new double[(int) contours.size()];
80+
final List<Rect> boundingBoxes = computeBoundingBoxes();
81+
for (int i = 0; i < contours.size(); i++) {
82+
centers[i] = boundingBoxes.get(i).x() + boundingBoxes.get(i).width() / 2;
83+
}
84+
return centers;
4285
}
4386

44-
public int getCols() {
45-
return this.cols;
87+
@NTValue(key = "centerY")
88+
public double[] getCenterY() {
89+
final double[] centers = new double[(int) contours.size()];
90+
final List<Rect> boundingBoxes = computeBoundingBoxes();
91+
for (int i = 0; i < contours.size(); i++) {
92+
centers[i] = boundingBoxes.get(i).y() + boundingBoxes.get(i).height() / 2;
93+
}
94+
return centers;
95+
}
96+
97+
@NTValue(key = "width")
98+
public synchronized double[] getWidth() {
99+
final double[] widths = new double[(int) contours.size()];
100+
final List<Rect> boundingBoxes = computeBoundingBoxes();
101+
for (int i = 0; i < contours.size(); i++) {
102+
widths[i] = boundingBoxes.get(i).width();
103+
}
104+
return widths;
105+
}
106+
107+
@NTValue(key = "height")
108+
public synchronized double[] getHeights() {
109+
final double[] heights = new double[(int) contours.size()];
110+
final List<Rect> boundingBoxes = computeBoundingBoxes();
111+
for (int i = 0; i < contours.size(); i++) {
112+
heights[i] = boundingBoxes.get(i).height();
113+
}
114+
return heights;
46115
}
47116
}

0 commit comments

Comments
 (0)