package org.codemap; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.codemap.util.MapScheme; import ch.akuhn.foreach.Collect; import ch.akuhn.foreach.Each; /** A set of documents on the visualization pane. * Each document is placed at a logical coordinate. * When normalized, most coordinates are between 0 and 1. * Such a placement of the documents is the result the Multidimensional Scaling (MDS) algorithm. *<P> * Instances of this class are immutable. * * @author Adrian Kuhn * */ public class Configuration implements Serializable { private static final long serialVersionUID = 1337; private static final int VERSION_1 = 0x20090830; private Point[] points; private Configuration(Point... locations) { this.points = locations; } public Configuration() { this(new Point[] {}); } public Configuration(Configuration map) { this(Arrays.copyOf(map.points, map.points.length)); } private void readObject(ObjectInputStream in) throws Exception { int version = in.readInt(); if (version != VERSION_1) throw new Error(); points = (Point[]) in.readObject(); } private void writeObject(ObjectOutputStream out) throws Exception { out.writeInt(VERSION_1); out.writeObject(points); } public Configuration(Collection<? extends Point> locations) { this(locations.toArray(new Point[locations.size()])); } public Configuration normalize() { if (points.length < 2) return this; double minX = points[0].x; double maxX = points[0].x; double minY = points[0].y; double maxY = points[0].y; for (Point each: this.points()) { minY = Math.min(minY, each.y); maxY = Math.max(maxY, each.y); minX = Math.min(minX, each.x); maxX = Math.max(maxX, each.x); } double width = maxX - minX; double height = maxY - minY; Collect<Point> query = Collect.from(points); for (Each<Point> each: query) { each.yield = each.value.normalize(minX, minY, width, height); } return new Configuration(query.getResultArray()); } public MapInstance withSize(int size, MapScheme<Double> elevation) { return new MapInstance(this, size, elevation).normalizeElevation(); } public Iterable<Point> points() { return Arrays.asList(points); } public int size() { return points.length; } public static class Builder { private Collection<Point> fPoints = new ArrayList<Point>(); public Builder add(String document, double x, double y) { fPoints.add(new Point(x,y,document)); return this; } public Configuration build() { return new Configuration(fPoints.toArray(new Point[fPoints.size()])); } } public static Builder builder() { return new Builder(); } public Map<String, Point> asMap() { Map<String, Point> map = new HashMap<String, Point>(); for (Point p: points) { map.put(p.getDocument(), p); } return map; } }