diff --git a/src/main/java/com/opennars/applications/crossing/Crossing.java b/src/main/java/com/opennars/applications/crossing/Crossing.java index 5e04c6f..da9b744 100644 --- a/src/main/java/com/opennars/applications/crossing/Crossing.java +++ b/src/main/java/com/opennars/applications/crossing/Crossing.java @@ -34,6 +34,11 @@ import processing.event.MouseEvent; public class Crossing extends PApplet { + public static double hexagonWidth = 10.0; + public static double hexagonHeight = 10.0; + + static HexagonMapping hexagonMapping = new HexagonMapping(hexagonWidth, hexagonHeight); + Nar nar; int entityID = 1; @@ -49,6 +54,7 @@ public void setup() { nar.narParameters.VOLUME = 0; nar.narParameters.DURATION*=10; NarListener listener = new NarListener(cameras.get(0), nar, predictions, disappointments, entities); + listener.crossing = this; nar.on(Events.TaskAdd.class, listener); nar.on(DISAPPOINT.class, listener); } catch (Exception ex) { @@ -78,7 +84,31 @@ public void setup() { String narsese = "<(*,{" + l.id + "}," + pos + ") --> at>."; nar.addInput(narsese); }*/ - + + + /** + * test if the hexagon mapping works as expected + */ + /* + for(int y=500;y<500+60; y+=1) { + for(int x=500;x<500+60; x+= 1) { + + Vec2Int mapped = hexagonMapping.map(x, y); + + int color = mapped.hashCode() % 4; + + DebugObject d = new DebugObject(x, y); + d.colorR = (float)color / 4.0f; + + debugObjects.add(d); + } + } + */ + + + + + size(1000, 1000); frameRate(fps); new NarSimpleGUI(nar); @@ -88,6 +118,9 @@ public void setup() { List trafficLights = new ArrayList(); List entities = new ArrayList(); List cameras = new ArrayList(); + + List debugObjects = new ArrayList<>(); + int t = 0; public static boolean showAnomalies = false; @@ -111,12 +144,15 @@ public void draw() { nar.addInput(questions); } } - for (int i = 0; i < 1000; i += Util.discretization) { - stroke(128); - line(0, i, 1000, i); - line(i, 0, i, 1000); + + for (int y=50;y<80;y++) { + for (int x=40;x<65;x++) { + final double[] pos = hexagonMapping.calcPositionOfHexagon(x, y); + drawHexagon(pos[0], pos[1]); + } } + for (Entity e : entities) { e.draw(this, streets, trafficLights, entities, null, 0); } @@ -124,6 +160,12 @@ public void draw() { tl.draw(this, t); } + for (final DebugObject iDebug : debugObjects) { + this.stroke(0, 0); // no stroke + this.fill(iDebug.colorR * 255.0f, 0, 0); + this.rect((float)(iDebug.posX-0.5), (float)(iDebug.posY-0.5), 1, 1); + } + // tick for (Entity ie : entities) { ie.tick(); @@ -157,6 +199,21 @@ public void draw() { System.out.println("Concepts: " + nar.memory.concepts.size()); } + private void drawHexagon(final double x, final double y) { + stroke(0); + // used for debugging the "real position" + rect((float)x-1.5f, (float)y-1.5f, 3, 3); + + stroke(128); + + for (int i=0; i < hexagonMapping.verticesRelative.length; i++) { + final double[] aRel = hexagonMapping.verticesRelative[i]; + final double[] bRel = hexagonMapping.verticesRelative[(i+1) % hexagonMapping.verticesRelative.length]; + + line((float)(x + aRel[0]), (float)(y + aRel[1]), (float)(x + bRel[0]), (float)(y + bRel[1])); + } + } + public void removeOutdatedPredictions(List predictions) { List toDelete = new ArrayList(); for(Prediction pred : predictions) { @@ -213,4 +270,7 @@ public static void main(String[] args) { new IncidentSimulator().show(); PApplet.runSketch(args2, mp); } + + + } diff --git a/src/main/java/com/opennars/applications/crossing/DebugObject.java b/src/main/java/com/opennars/applications/crossing/DebugObject.java new file mode 100644 index 0000000..913e684 --- /dev/null +++ b/src/main/java/com/opennars/applications/crossing/DebugObject.java @@ -0,0 +1,14 @@ +package com.opennars.applications.crossing; + +public class DebugObject { + public double posX; + public double posY; + public int remainingTime = 100; + + public float colorR = 1.0f; + + public DebugObject(final double posX, final double posY) { + this.posX = posX; + this.posY = posY; + } +} diff --git a/src/main/java/com/opennars/applications/crossing/Entity.java b/src/main/java/com/opennars/applications/crossing/Entity.java index fa3dba9..9a8703b 100644 --- a/src/main/java/com/opennars/applications/crossing/Entity.java +++ b/src/main/java/com/opennars/applications/crossing/Entity.java @@ -81,13 +81,21 @@ public void draw(PApplet applet, List streets, List traffi //float posYDiscrete = (((int) this.posY)/Util.discretization * Util.discretization); applet.translate((float) posX, (float) posY); applet.rotate((float) angle); + if(truth == null) { - applet.rect(0, 0, Util.discretization*scale, Util.discretization/2*scale); + final float width = Util.discretization/2*scale; + applet.rect(0.0f*Util.discretization*scale, -0.5f*width, Util.discretization*scale, width); } - applet.ellipse(2.5f, 2.5f, Util.discretization*scale, Util.discretization*scale); + applet.ellipse(0, 0, Util.discretization*scale, Util.discretization*scale); + applet.popMatrix(); applet.fill(0); applet.text(String.valueOf(id), (float)posX, (float)posY); + + // used for debugging the "real position" + applet.rect((float)posX-1.5f, (float)posY-1.5f, 3, 3); + + if(truth != null) { return; } diff --git a/src/main/java/com/opennars/applications/crossing/HexagonMapping.java b/src/main/java/com/opennars/applications/crossing/HexagonMapping.java new file mode 100644 index 0000000..799283d --- /dev/null +++ b/src/main/java/com/opennars/applications/crossing/HexagonMapping.java @@ -0,0 +1,216 @@ +/* + * The MIT License + * + * Copyright 2018 The OpenNARS authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.opennars.applications.crossing; + +public class HexagonMapping { + //private final double[][] positions; + //private final double[] distances; + public final double[][] verticesRelative; + + public double width; // width of hexagon + public double height; // height of hexagon + + public HexagonMapping(final double width, final double height) { + this.width = width; + this.height = height; + + // relative positions of the vertices of a single hexagon + verticesRelative = new double[][]{ + {width * -0.5, height * -0.25}, + {width * -0.5, height * 0.25}, + + {0.0, height * 0.5}, + + {width * 0.5, height * 0.25}, + {width * 0.5, height * -0.25}, + + {0.0, height * -0.5}, + }; + + /* + positions = new double[][]{ + {0.5 * width, -0.25 * height}, + {1.5 * width, -0.25 * height}, + + {0.0, 0.5 * height}, + {width, 0.5 * height}, + {width + width, 0.5 * height}, + + {0.5 * width, 1.25 * height}, + {1.5 * width, 1.25 * height}, + }; + + distances = new double[positions.length]; + */ + } + + public double[] calcPositionOfHexagon(final int x, final int y) { + final double offsetX = (y % 2) == 0 ? 0.0 : -0.5*width; + + double resultX = (x + 1) * width + offsetX; + double resultY = 0.5*height + 0.75*height*y; + return new double[]{resultX, resultY}; + } + + public Vec2Int map(final double x, final double y) { + for(int ix=0;ix<100;ix++) { + for(int iy=0;iy<100;iy++) { + final double[] positionOfHexagon = calcPositionOfHexagon(ix, iy); + + + + boolean isInHexagon = isInHexagonRelative(x - positionOfHexagon[0], y - positionOfHexagon[1]); + + // HACK + /* + isInHexagon = isInPolygon(x - positionOfHexagon[0], y - positionOfHexagon[1], + 0, 0, + 5, 0, + 0, 5 + ); + */ + + if (isInHexagon) { + return new Vec2Int(ix, iy); + } + } + } + + // default! + return new Vec2Int(5, 0); + + /* + final int ix = (int)(x / (width*2.0)); + final int iy = (int)(y / (height*1.5)); + + final double relX = x - ix * (width*2.0); + final double relY = y - iy * (height*1.5); + + final Vec2Int relativeHexagonIndices = mapGroupToRelCell(relX, relY); + return new Vec2Int(relativeHexagonIndices.x + ix*2, relativeHexagonIndices.y + iy*2); + */ + } + + // public for testing + public boolean isInHexagonRelative(final double x, final double y) { + if (x==0 && y==0) { + return true; + } + + for(int i=0;i<6;i++) { + final int iNext = (i + 1) % 6; + final int iOtherSide = (i + 4) % 6; + + final boolean isInPolygonOfHexagon = isInPolygon( + x, y, + verticesRelative[iNext][0], verticesRelative[iNext][1], + verticesRelative[i][0], verticesRelative[i][1], + verticesRelative[iOtherSide][0], verticesRelative[iOtherSide][1] + ); + if (isInPolygonOfHexagon) { + return true; + } + } + + return false; + } + + + public static boolean isInPolygon(final double x, final double y, final double x0, final double y0, final double x1, final double y1, final double x2, final double y2) { + final boolean side0 = side(x, y, x0, y0, x1, y1); + final boolean side1 = side(x, y, x1, y1, x2, y2); + final boolean side2 = side(x, y, x2, y2, x0, y0); + + return side0 && side1 && side2; + } + + public static boolean side(final double x, final double y, final double ax, final double ay, final double bx, final double by) { + final double dx = bx - ax; + final double dy = by - ay; + + // perpendicular direction - which is the orientation of the edge + final double idx = -dy; + final double idy = dx; + + final double pdx = x - ax; + final double pdy = y - ay; + + // side is computed by direction and difference + return dot(idx, idy, pdx, pdy) >= 0.0; + } + + private static double dot(final double ax, final double ay, final double bx, final double by) { + return ax*bx + ay*by; + } + + + +/* + private Vec2Int mapGroupToRelCell(final double x, final double y) { + // see https://www.redblobgames.com/grids/hexagons/ for illustration + + + + for(int i=0;i disappointments; Nar nar; Camera camera; + + Crossing crossing; + public NarListener(Camera camera, Nar nar, List predictions, List disappointments, List entities) { this.predictions = predictions; this.disappointments = disappointments; @@ -109,8 +109,22 @@ public Prediction predictionFromTask(Task t) { String position = prod.term[1].toString(); if(position.contains("_")) { try { - int posX = camera.minX + Util.discretization * Integer.valueOf(position.split("_")[0]); - int posY = camera.minY + Util.discretization * Integer.valueOf(position.split("_")[1]); + + final int mappingCoordinateOfProductX = Integer.valueOf(position.split("_")[0]); + final int mappingCoordinateOfProductY = Integer.valueOf(position.split("_")[1]); + final double[] mappedCoordinate = Crossing.hexagonMapping.calcPositionOfHexagon(mappingCoordinateOfProductX, mappingCoordinateOfProductY); + + int posX = camera.minX + (int)mappedCoordinate[0];//camera.minX + Util.discretization * Integer.valueOf(position.split("_")[0]); + int posY = camera.minY + (int)mappedCoordinate[1];//camera.minY + Util.discretization * Integer.valueOf(position.split("_")[1]); + + // HACK + // Robert< no idea where the offset is comming from - seems to be only a visual issue > + posY -= 10; + + // used for debugging the "real position" + //crossing.rect((float)posX, (float)posY, 3, 3); + crossing.debugObjects.add(new DebugObject(posX, posY)); + //int id = 0; //Integer.valueOf(idStr.toString()); often a dep var Entity pred; if(type.toString().startsWith(car.toString())) { diff --git a/src/main/java/com/opennars/applications/crossing/Util.java b/src/main/java/com/opennars/applications/crossing/Util.java index f1442d0..84ae5c1 100644 --- a/src/main/java/com/opennars/applications/crossing/Util.java +++ b/src/main/java/com/opennars/applications/crossing/Util.java @@ -33,18 +33,19 @@ public class Util { public static Random rnd = new Random(); - public static final int discretization =10; - + + + public static int discretization = 10; + public static double distance(double posX, double posY, double posX2, double posY2) { double dx = posX - posX2; double dy = posY - posY2; return Math.sqrt(dx * dx + dy * dy); } - public static String positionToTerm(int X, int Y) { - int posX = X / discretization; - int posY = Y / discretization; - return posX + "_" + posY; + public static String positionToTerm(int x, int y) { + final Vec2Int pos = Crossing.hexagonMapping.map(x, y); + return pos.x + "_" + pos.y; } public static float truthToValue(TruthValue truth) { diff --git a/src/main/java/com/opennars/applications/crossing/Vec2Int.java b/src/main/java/com/opennars/applications/crossing/Vec2Int.java new file mode 100644 index 0000000..eaf0ca3 --- /dev/null +++ b/src/main/java/com/opennars/applications/crossing/Vec2Int.java @@ -0,0 +1,44 @@ +/* + * The MIT License + * + * Copyright 2018 The OpenNARS authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.opennars.applications.crossing; + +public class Vec2Int { + public int x; + public int y; + + public Vec2Int(final int x, final int y) { + this.x = x; + this.y = y; + } + + @Override + public int hashCode() { + return x + y * 13; + } + + @Override + public boolean equals(Object other) { + return other instanceof Vec2Int && x == ((Vec2Int)other).x && y == ((Vec2Int)other).y; + } +} \ No newline at end of file