diff --git a/SeatingMap-addon/pom.xml b/SeatingMap-addon/pom.xml
index 0e3aff3..f4be9f9 100644
--- a/SeatingMap-addon/pom.xml
+++ b/SeatingMap-addon/pom.xml
@@ -6,7 +6,7 @@
SeatingMap
jar
0.1-SNAPSHOT
- Seating map add-on for showing where people are seated at the office
+ Seating map
3
diff --git a/SeatingMap-addon/src/main/java/org/percepta/mgrankvi/SeatingMap.java b/SeatingMap-addon/src/main/java/org/percepta/mgrankvi/SeatingMap.java
index eb6fc5f..66fce85 100644
--- a/SeatingMap-addon/src/main/java/org/percepta/mgrankvi/SeatingMap.java
+++ b/SeatingMap-addon/src/main/java/org/percepta/mgrankvi/SeatingMap.java
@@ -58,7 +58,6 @@ public void setVisibleFloor(int floor) {
@Override
public void itemClick(String roomId, String tableId) {
- System.out.println("Got item selection!");
Room clickedRoom = floors.get(visibleFloor).getRoomById(roomId);
Table clickedTable = clickedRoom.getTableById(tableId);
@@ -75,16 +74,54 @@ public void itemClick(String roomId, String tableId) {
});
}
+ /**
+ * Add a room to the map for given floor from lines.
+ *
+ * @param floor
+ * floor to add room to
+ * @param lines
+ * lines of room
+ * @return created room object
+ */
public Room addRoom(int floor, List lines) {
FloorMap map = getFloor(floor);
return map.addRoom(lines);
}
+ /**
+ * Add room for given floor to map.
+ *
+ * @param floor
+ * floor to add room to
+ * @param room
+ * room to add
+ */
+ public void addRoom(int floor, Room room) {
+ FloorMap map = getFloor(floor);
+ map.addComponent(room);
+ }
+
+ /**
+ * Add lines to map. These will be drawn, but won't have any special
+ * functionality.
+ *
+ * @param floor
+ * floor to add lines to
+ * @param lines
+ * lines to add
+ */
public void addLines(int floor, List lines) {
FloorMap map = getFloor(floor);
map.addLines(lines);
}
+ /**
+ * Add listener to be notified of click selection for room and table in map.
+ *
+ * @param listener
+ * selection listener
+ * @return handler to remove listener with
+ */
public RemoveHandler addSelectionListener(SelectionListener listener) {
selectionEvents.add(listener);
return () -> selectionEvents.remove(listener);
@@ -101,32 +138,6 @@ public void setAutoToggleTableName(boolean autoToggleName) {
this.autoToggleName = autoToggleName;
}
- /**
- * Returns first match for name
- *
- * @param name
- * Name to search for
- * @return First match or null
- */
- private SearchResult getSingleByName(String name) {
- SearchResult result = new SearchResult();
- for (FloorMap floor : floors.values()) {
- for (Room room : floor.getRooms()) {
- for (Table table : room.getTables()) {
- if (table.getName().toLowerCase()
- .contains(name.toLowerCase())) {
- result.setFloor(floor);
- result.setRoom(room);
- result.setTable(table);
- return result;
- }
- }
- }
- }
-
- return null;
- }
-
/**
* Get the first match for name
*
@@ -327,4 +338,30 @@ private FloorMap getFloor(int floor) {
}
return map;
}
+
+ /**
+ * Returns first match for name
+ *
+ * @param name
+ * Name to search for
+ * @return First match or null
+ */
+ private SearchResult getSingleByName(String name) {
+ SearchResult result = new SearchResult();
+ for (FloorMap floor : floors.values()) {
+ for (Room room : floor.getRooms()) {
+ for (Table table : room.getTables()) {
+ if (table.getName().toLowerCase()
+ .contains(name.toLowerCase())) {
+ result.setFloor(floor);
+ result.setRoom(room);
+ result.setTable(table);
+ return result;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
}
diff --git a/SeatingMap-addon/src/main/java/org/percepta/mgrankvi/util/ImageToLines.java b/SeatingMap-addon/src/main/java/org/percepta/mgrankvi/util/ImageToLines.java
index b95ab3a..db5039d 100644
--- a/SeatingMap-addon/src/main/java/org/percepta/mgrankvi/util/ImageToLines.java
+++ b/SeatingMap-addon/src/main/java/org/percepta/mgrankvi/util/ImageToLines.java
@@ -1,11 +1,5 @@
package org.percepta.mgrankvi.util;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import org.apache.commons.codec.binary.Base64;
-import org.percepta.mgrankvi.client.geometry.Line;
-import org.percepta.mgrankvi.client.geometry.Point;
-
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Graphics2D;
@@ -15,12 +9,21 @@
import java.io.File;
import java.io.IOException;
import java.net.URL;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedList;
import java.util.List;
import java.util.Set;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.commons.codec.binary.Base64;
+import org.percepta.mgrankvi.client.geometry.Line;
+import org.percepta.mgrankvi.client.geometry.Point;
+
/**
- * Utility to get the lines in a image file to generate lines for the VisibilityMap.
+ * Utility to get the lines in a image file to generate lines for the
+ * VisibilityMap.
*
* Note! Horizontal lines only get the left point marked by the Harris corner,
* so a light colored crossing is needed to get the right side!
@@ -32,7 +35,8 @@ public class ImageToLines {
/**
* Get lines for given image.
*
- * @param imageFile File containing "map" to generate lines from
+ * @param imageFile
+ * File containing "map" to generate lines from
* @return List of lines found in image.
*/
public List getLines(String imageFile) {
@@ -53,17 +57,71 @@ public List getLines(String imageFile, Point offset) {
// Set offset for lines
lines.forEach(line -> {
- line.start = new Point(line.start.getX()+offset.getX(), line.start.getY()+offset.getY());
- line.end = new Point(line.end.getX()+offset.getX(), line.end.getY()+offset.getY());
+ line.start = new Point(line.start.getX() + offset.getX(),
+ line.start.getY() + offset.getY());
+ line.end = new Point(line.end.getX() + offset.getX(),
+ line.end.getY() + offset.getY());
});
return lines;
}
+ public List> getLineGroups(String imageFile) {
+ List lines = getLines(imageFile);
+
+ return collectLinesToConvexPolygonGroup(lines, imageFile);
+ }
+
+ public List> getLineGroups(String imageFile, Point offset) {
+ List lines = getLines(imageFile, offset);
+
+ return collectLinesToConvexPolygonGroup(lines, imageFile);
+ }
+
+ private List> collectLinesToConvexPolygonGroup(List lines,
+ String file) {
+ LinkedList linesToHandle = new LinkedList<>(lines);
+ List> groups = new ArrayList<>();
+
+ while (!linesToHandle.isEmpty()) {
+ List group = new ArrayList<>();
+ Line pop = linesToHandle.pop();
+ group.add(pop);
+
+ Point start = pop.start;
+ Point current = pop.end;
+
+ while (!current.equals(start)) {
+ Line nextLine = null;
+ for (Line line : linesToHandle) {
+ if (line.start.equals(current)
+ || line.end.equals(current)) {
+ nextLine = line;
+ break;
+ }
+ }
+ if (nextLine == null) {
+ String msg = String.format(
+ "No continuation line found! Check that all points create a convex polygon in image %s",
+ file);
+ throw new IllegalArgumentException(msg);
+ }
+ group.add(nextLine);
+ linesToHandle.remove(nextLine);
+ current = nextLine.end.equals(current) ? nextLine.start
+ : nextLine.end;
+ }
+ groups.add(group);
+ }
+
+ return groups;
+ }
+
/**
* Load the image from classpath or file system.
*
- * @param filename File to get image for.
+ * @param filename
+ * File to get image for.
* @return File or null if not found.
*/
private BufferedImage getImage(String filename) {
@@ -83,10 +141,10 @@ private BufferedImage getImage(String filename) {
}
/**
- * Get corner points for image.
- * Uses HarrisFast corner detection.
+ * Get corner points for image. Uses HarrisFast corner detection.
*
- * @param image Image to search for points
+ * @param image
+ * Image to search for points
* @return
*/
private static List getCornerPoints(BufferedImage image) {
@@ -102,19 +160,22 @@ private static List getCornerPoints(BufferedImage image) {
}
/**
- * Generate lines from found points by referring to the image to check if a line should be drawn.
+ * Generate lines from found points by referring to the image to check if a
+ * line should be drawn.
*
* @param image
* @param points
* @return
*/
- private List getLinesForPoints(BufferedImage image, List points) {
+ private List getLinesForPoints(BufferedImage image,
+ List points) {
List lines = Lists.newLinkedList();
List pointsLeft = Lists.newArrayList(points);
- //Luminance threshold
+ // Luminance threshold
double luminance = 25.0;
- // Iterate from point to point and reference to image to see if we have a line between the points.
+ // Iterate from point to point and reference to image to see if we have
+ // a line between the points.
for (Point p : points) {
pointsLeft.remove(p);
for (Point p2 : pointsLeft) {
@@ -127,7 +188,8 @@ private List getLinesForPoints(BufferedImage image, List points) {
min = Math.min(p.getY(), p2.getY());
max = Math.max(p.getY(), p2.getY());
for (double y = min; y < max; y++) {
- if (getLuminance(image.getRGB((int) p.getX(), (int) y)) > luminance) {
+ if (getLuminance(image.getRGB((int) p.getX(),
+ (int) y)) > luminance) {
foundLine = false;
break;
}
@@ -137,13 +199,15 @@ private List getLinesForPoints(BufferedImage image, List points) {
min = Math.min(p.getX(), p2.getX());
max = Math.max(p.getX(), p2.getX());
for (double x = min; x < max; x++) {
- if (getLuminance(image.getRGB((int) x, (int) p.getY())) > luminance) {
+ if (getLuminance(image.getRGB((int) x,
+ (int) p.getY())) > luminance) {
foundLine = false;
break;
}
}
} else {
- // Check line with a slope (eg. not fully vertical or horizontal)
+ // Check line with a slope (eg. not fully vertical or
+ // horizontal)
Double m = getSlope(p, p2);
Double b = intercept(p, m);
@@ -151,8 +215,10 @@ private List getLinesForPoints(BufferedImage image, List points) {
max = Math.max(p.getX(), p2.getX());
for (double x = min; x <= max; x += 0.1) {
double y = m * x + b;
- // Not on a line if even one non black pixel is found on line
- if (getLuminance(image.getRGB((int) x, (int) y)) > luminance) {
+ // Not on a line if even one non black pixel is found on
+ // line
+ if (getLuminance(
+ image.getRGB((int) x, (int) y)) > luminance) {
foundLine = false;
break;
}
@@ -175,8 +241,10 @@ private List getLinesForPoints(BufferedImage image, List points) {
/**
* Calculate the slope for the line between two points
*
- * @param a Point A
- * @param b Point B
+ * @param a
+ * Point A
+ * @param b
+ * Point B
* @return Slope of line
*/
private static Double getSlope(Point a, Point b) {
@@ -201,14 +269,18 @@ private static Double intercept(Point p, Double slope) {
/**
* Scan for corners in image using the Harris Fast Scan algorithm.
*
- * @param image Image to search for corners
+ * @param image
+ * Image to search for corners
* @return corners found
*/
private static List getCorners(BufferedImage image) {
- if (image == null) return Lists.newArrayList();
- int width = image.getWidth(); // largeur de l'image
- int height = image.getHeight(); // hauteur de l'image
- int[][] input = new int[width][height]; // tableau 2D [x][y] contenant l'image en niveau de gris (0-255)
+ if (image == null)
+ return Lists.newArrayList();
+ int width = image.getWidth(); // largeur de l'image
+ int height = image.getHeight(); // hauteur de l'image
+ int[][] input = new int[width][height]; // tableau 2D [x][y] contenant
+ // l'image en niveau de gris
+ // (0-255)
for (int i = 0; i < width - 1; i++) {
for (int j = 0; j < height - 1; j++) {
@@ -219,8 +291,8 @@ private static List getCorners(BufferedImage image) {
//////////////////////
double sigma = 1.2; // parametre du filtre gaussien
- double k = 0.06; // parametre de la formule de la mesure
- int spacing = 2; // minimun distance between 2 corners
+ double k = 0.06; // parametre de la formule de la mesure
+ int spacing = 2; // minimun distance between 2 corners
// Init
HarrisFast hf = new HarrisFast(input, width, height);
@@ -228,21 +300,24 @@ private static List getCorners(BufferedImage image) {
hf.filter(sigma, k, spacing);
List corners = hf.corners;
- // Remove the last corner as it is always the lower right corner of image enen though there was no point there.
+ // Remove the last corner as it is always the lower right corner of
+ // image enen though there was no point there.
corners.remove(corners.size() - 1);
- // Harris can have corners positioned a bit differently dependent on the scan direction
+ // Harris can have corners positioned a bit differently dependent on the
+ // scan direction
// Position corners so they align for straighter lines.
for (HarrisFast.Corner corner : corners) {
moveUntilEnd(image, corner);
}
// Uncomment if a base64 image is needed for debugging purposes!!!
-// outputResult(image, corners);
+ // outputResult(image, corners);
return corners;
}
- private static void outputResult(BufferedImage image, List corners) {
+ private static void outputResult(BufferedImage image,
+ List corners) {
BufferedImage bufferedImage = duplicateImage(image);
Graphics2D g2d = bufferedImage.createGraphics();
g2d.setColor(Color.RED);
@@ -250,7 +325,7 @@ private static void outputResult(BufferedImage image, List co
for (HarrisFast.Corner corner : corners) {
g2d.fill(new Rectangle2D.Float(corner.x, corner.y, 1, 1));
-// g2d.drawString("" + nr++, corner.x - 15, corner.y - 5);
+ // g2d.drawString("" + nr++, corner.x - 15, corner.y - 5);
}
g2d.dispose();
System.out.println(encodeImageToBase64(bufferedImage));
@@ -267,7 +342,8 @@ private static void outputResult(BufferedImage image, List co
* @param image
* @param corner
*/
- private static void moveUntilEnd(BufferedImage image, HarrisFast.Corner corner) {
+ private static void moveUntilEnd(BufferedImage image,
+ HarrisFast.Corner corner) {
int rasterSize = 4;
double lum = 25.0;
@@ -276,8 +352,10 @@ private static void moveUntilEnd(BufferedImage image, HarrisFast.Corner corner)
int x = corner.x - rasterOffset;
int y = corner.y - rasterOffset;
- if(x < 0) x = 0;
- if(y < 0) y = 0;
+ if (x < 0)
+ x = 0;
+ if (y < 0)
+ y = 0;
int[] xS = new int[rasterSize];
int[] yS = new int[rasterSize];
@@ -287,14 +365,20 @@ private static void moveUntilEnd(BufferedImage image, HarrisFast.Corner corner)
// collect x positions
for (int j = 0; j < rasterSize && j + y < image.getHeight(); j++) {
for (int i = 0; i < rasterSize && i + x < image.getWidth(); i++) {
- // if X on line Y is "black" and pixel before is also "black" (or no marking yet made)
+ // if X on line Y is "black" and pixel before is also "black"
+ // (or no marking yet made)
// add pixel in line
- if (getLuminance(image.getRGB(i + x, j + y)) < lum && (xS[j] == 0 || getLuminance(image.getRGB(i + x - 1, j + y)) < lum)) {
+ if (getLuminance(image.getRGB(i + x, j + y)) < lum
+ && (xS[j] == 0 || getLuminance(
+ image.getRGB(i + x - 1, j + y)) < lum)) {
xS[j]++;
}
- // if Y on line X is "black" and pixel before is also "black" (or no marking yet made)
+ // if Y on line X is "black" and pixel before is also "black"
+ // (or no marking yet made)
// add pixel in line
- if (getLuminance(image.getRGB(i + x, j + y)) < lum && (yS[i] == 0 || getLuminance(image.getRGB(i + x, j - 1 + y)) < lum)) {
+ if (getLuminance(image.getRGB(i + x, j + y)) < lum
+ && (yS[i] == 0 || getLuminance(
+ image.getRGB(i + x, j - 1 + y)) < lum)) {
yS[i]++;
}
}
@@ -314,7 +398,8 @@ private static void moveUntilEnd(BufferedImage image, HarrisFast.Corner corner)
}
}
// cancel positioning if we have a point on a "helper" line
- if (yOffset == -1 && xOffset == -1) return;
+ if (yOffset == -1 && xOffset == -1)
+ return;
// Update corner position
corner.x = xOffset + x;
@@ -325,7 +410,8 @@ private static void moveUntilEnd(BufferedImage image, HarrisFast.Corner corner)
/**
* Clones the given BufferedImage
*
- * @param sourceImage The image to copy
+ * @param sourceImage
+ * The image to copy
* @return A copy of sourceImage
*/
public static BufferedImage duplicateImage(BufferedImage sourceImage) {
@@ -346,7 +432,8 @@ public static BufferedImage duplicateImage(BufferedImage sourceImage) {
/**
* Get the luminance value for given rgb value
*
- * @param rgb RGB value to get luminance for
+ * @param rgb
+ * RGB value to get luminance for
* @return Luminance
*/
public static double getLuminance(int rgb) {
@@ -360,9 +447,12 @@ public static double getLuminance(int rgb) {
/**
* Get the luminance value for given rgb value
*
- * @param r Red value
- * @param g Green value
- * @param b Blue value
+ * @param r
+ * Red value
+ * @param g
+ * Green value
+ * @param b
+ * Blue value
* @return Luminance
*/
private static double getLuminance(int r, int g, int b) {
@@ -372,7 +462,8 @@ private static double getLuminance(int r, int g, int b) {
/**
* Encode image to a Base64 string.
*
- * @param image Image to encode
+ * @param image
+ * Image to encode
* @return encoded image
*/
public static String encodeImageToBase64(BufferedImage image) {
diff --git a/SeatingMap-demo/pom.xml b/SeatingMap-demo/pom.xml
index 59f47f7..f26ee10 100644
--- a/SeatingMap-demo/pom.xml
+++ b/SeatingMap-demo/pom.xml
@@ -6,7 +6,7 @@
SeatingMap-demo
war
0.1-SNAPSHOT
- MyComponent Add-on Demo
+ Seating map Add-on Demo
3
diff --git a/SeatingMap-demo/src/main/java/org/percepta/mgrankvi/demo/DemoUI.java b/SeatingMap-demo/src/main/java/org/percepta/mgrankvi/demo/DemoUI.java
index 5c43197..dd7b417 100644
--- a/SeatingMap-demo/src/main/java/org/percepta/mgrankvi/demo/DemoUI.java
+++ b/SeatingMap-demo/src/main/java/org/percepta/mgrankvi/demo/DemoUI.java
@@ -49,21 +49,32 @@ protected void init(VaadinRequest request) {
"/org/percepta/mgrankvi/demo/LeftSide.png",
new Point(150, 150));
room = component.addRoom(1, thirdLines);
- Table table = new Table(imageToLines.getLines(
- "/org/percepta/mgrankvi/demo/Table1.png", new Point(150, 150)));
+ List> lineGroups = imageToLines
+ .getLineGroups("/org/percepta/mgrankvi/demo/Tables.png",
+ new Point(150, 150));
+ for(List lines: lineGroups) {
+ Table table = new Table(lines);
+ room.addComponent(table);
+ }
+ Table table = room.getTables().get(0);
table.setName("Terhi Testi");
- table.setImageUrl(
- "https://vaadin.com/vaadin-theme/images/vaadin/vaadin-logo-small.png");
- room.addComponent(table);
- room.addComponent(new Table(
- imageToLines.getLines("/org/percepta/mgrankvi/demo/Table2.png",
- new Point(150, 150))));
- room.addComponent(new Table(
- imageToLines.getLines("/org/percepta/mgrankvi/demo/Table3.png",
- new Point(150, 150))));
- room.addComponent(new Table(
- imageToLines.getLines("/org/percepta/mgrankvi/demo/Table4.png",
- new Point(150, 150))));
+ table.setImageUrl(
+ "https://vaadin.com/vaadin-theme/images/vaadin/vaadin-logo-small.png");
+ // Table table = new Table(imageToLines.getLines(
+// "/org/percepta/mgrankvi/demo/Table1.png", new Point(150, 150)));
+// table.setName("Terhi Testi");
+// table.setImageUrl(
+// "https://vaadin.com/vaadin-theme/images/vaadin/vaadin-logo-small.png");
+// room.addComponent(table);
+// room.addComponent(new Table(
+// imageToLines.getLines("/org/percepta/mgrankvi/demo/Table2.png",
+// new Point(150, 150))));
+// room.addComponent(new Table(
+// imageToLines.getLines("/org/percepta/mgrankvi/demo/Table3.png",
+// new Point(150, 150))));
+// room.addComponent(new Table(
+// imageToLines.getLines("/org/percepta/mgrankvi/demo/Table4.png",
+// new Point(150, 150))));
thirdLines = imageToLines.getLines(
"/org/percepta/mgrankvi/demo/FloorUtilities.png",
@@ -76,10 +87,10 @@ protected void init(VaadinRequest request) {
component.addPaths(pathLines, 1);
component.connectTablesToPaths();
- component.getPath(table.getNodeId(), table2.getNodeId());
+// component.getPath(table.getNodeId(), table2.getNodeId());
component.addSelectionListener(event -> {
- System.out.println("Click selection event recieved with payload: "
+ System.out.println("Click selection event received with payload: "
+ event.getRoom() + " :: " + event.getTable());
});
diff --git a/SeatingMap-demo/src/main/resources/org/percepta/mgrankvi/demo/Tables.png b/SeatingMap-demo/src/main/resources/org/percepta/mgrankvi/demo/Tables.png
new file mode 100644
index 0000000..d592fd8
Binary files /dev/null and b/SeatingMap-demo/src/main/resources/org/percepta/mgrankvi/demo/Tables.png differ