package photogrammetry.util.model.models;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import photogrammetry.util.model.Feature;
import photogrammetry.util.model.HasCoordinates3d;
import photogrammetry.util.model.Point3d;
public class Model {
private Map<Feature, Point3d> points;
private Point3d center = null;
private Double maxDistance = null;
/**
* Construct a new model.
*/
public Model() {
points = new HashMap<>();
}
/**
* Add a point to this model.
*
* @param feature the feature the point belongs to.
* @param point the value of the point.
*/
public synchronized void addPoint(Feature feature, HasCoordinates3d point) {
points.put(feature, new Point3d(point.getX(), point.getY(), point.getZ()));
center = null;
maxDistance = null;
}
/**
* Get the center (average) of all points in this model.
*
* @return the average of all the points of this model.
*/
public synchronized HasCoordinates3d getCenter() {
if (center == null) {
double x = 0, y = 0, z = 0;
for (Point3d p : getPoints()) {
x += p.x;
y += p.y;
z += p.z;
}
int count = getPoints().size();
center = new Point3d(x / count, y / count, z / count);
}
return center;
}
/**
* Get the maximum distance of a point to the center of this model.
*
* @return the maximum distance.
*/
public synchronized double getMaximumDistanceFromCenter() {
if (maxDistance == null) {
HasCoordinates3d center = getCenter();
double maxd2 = 0;
for (Point3d p : getPoints()) {
double dx = p.x - center.getX();
double dy = p.y - center.getY();
double dz = p.z - center.getZ();
double d2 = dx * dx + dy * dy + dz * dz;
maxd2 = Math.max(maxd2, d2);
}
maxDistance = Math.sqrt(maxd2);
}
return maxDistance;
}
/**
* <p>
* Get all points in this model, in no particular order.
* </p>
* <p>
* See {@link HashMap#values()} for details.
* </p>
*
* @return a collection with all points in this model.
*/
public Collection<Point3d> getPoints() {
return points.values();
}
public Map<Feature, Point3d> getPointMap() {
return points;
}
public Set<Feature> getCommonFeatures(Model other) {
Set<Feature> result = new HashSet<>();
for (Feature f : points.keySet()) {
if (other.points.containsKey(f)) {
result.add(f);
}
}
return result;
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
str.append("Model [\n");
for (Point3d p : points.values()) {
str.append(" " + p + "\n");
}
str.append("\n");
return str.toString();
}
/**
* Merge the points from
* <code>pts</code> into this model.
*
* @param pts the points to merge
* @param featureCount the number points that have been found for each
* feature so far.
*/
public void merge(Map<Feature, Point3d> pts, Map<Feature, Integer> featureCount) {
for (Entry<Feature, Point3d> f : pts.entrySet()) {
if (points.containsKey(f.getKey())) {
Integer count = featureCount.get(f.getKey());
if (count == null) {
count = 1;
}
Point3d p = points.get(f.getKey());
p.x = (p.x * count + f.getValue().x) / (count + 1);
p.y = (p.y * count + f.getValue().y) / (count + 1);
p.z = (p.z * count + f.getValue().z) / (count + 1);
featureCount.put(f.getKey(), count + 1);
} else {
points.put(f.getKey(), f.getValue());
featureCount.put(f.getKey(), 1);
}
}
}
}