Commit 24907935 authored by Nico Mack's avatar Nico Mack

Generalized ClusterManager class

Added possibility to specify target coordinate system to
PositionalComparator
parent ef3f2f34
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
package lu.list.itis.dkd.tui.feature.cluster; package lu.list.itis.dkd.tui.feature.cluster;
import lu.list.itis.dkd.tui.utility.Positionable; import lu.list.itis.dkd.tui.utility.Positionable;
import lu.list.itis.dkd.tui.utility.ScreenCoordinates;
import lu.list.itis.dkd.tui.utility.kdtree.KdComparator;
import lu.list.itis.dkd.tui.utility.kdtree.KdTree; import lu.list.itis.dkd.tui.utility.kdtree.KdTree;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -26,16 +28,21 @@ import java.util.List; ...@@ -26,16 +28,21 @@ import java.util.List;
* @author nico.mack@list.lu * @author nico.mack@list.lu
* @since 2.6 * @since 2.6
* @version 1.0.0 * @version 1.0.0
* @param <P>
*/ */
// *************************************************************************** // ***************************************************************************
// * Class Definition and Members * // * Class Definition and Members *
// *************************************************************************** // ***************************************************************************
public class ClusterManager { public class ClusterManager<P extends Positionable> {
private KdTree<Positionable> kdTree;
private double radius; private double radius;
private KdComparator<P> comparator;
private List<P> constituents;
private List<P> clustered;
private KdTree<P> kdTree;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// *************************************************************************** // ***************************************************************************
...@@ -47,8 +54,13 @@ public class ClusterManager { ...@@ -47,8 +54,13 @@ public class ClusterManager {
*/ */
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@SuppressWarnings("unchecked")
public ClusterManager(double radius) { public ClusterManager(double radius) {
this.radius = radius; this.radius = radius;
this.constituents = new ArrayList<>();
this.clustered = new ArrayList<>();
this.comparator = (KdComparator<P>) new PositionableComparator();
((PositionableComparator) this.comparator).setReferenceState(ScreenCoordinates.class);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
...@@ -57,10 +69,10 @@ public class ClusterManager { ...@@ -57,10 +69,10 @@ public class ClusterManager {
// *************************************************************************** // ***************************************************************************
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
private synchronized List<Clusterable> getClusterable(List<Positionable> candidates) { private synchronized List<Clusterable> getClusterable(List<P> candidates) {
List<Clusterable> results = new ArrayList<>(); List<Clusterable> results = new ArrayList<>();
for (Positionable candidate : candidates) { for (P candidate : candidates) {
if (Clusterable.class.isAssignableFrom(candidate.getClass())) { if (Clusterable.class.isAssignableFrom(candidate.getClass())) {
results.add((Clusterable) candidate); results.add((Clusterable) candidate);
} }
...@@ -74,26 +86,62 @@ public class ClusterManager { ...@@ -74,26 +86,62 @@ public class ClusterManager {
// *************************************************************************** // ***************************************************************************
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** /**
* @param positionables *
*/ */
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
public void refresh(List<Positionable> positionables) { public void clear() {
kdTree = new KdTree<>(positionables, 2, new PositionableComparator()); this.kdTree = null;
List<Positionable> coallesced = new ArrayList<>(); this.constituents.clear();
List<Clusterable> clusters = new ArrayList<>(); }
for (Positionable candidate : positionables) { // ---------------------------------------------------------------------------
if ((candidate instanceof Clusterable) && coallesced.contains(candidate)) { /**
List<Positionable> coallescing = kdTree.findNearest(candidate, radius); * @param constituent
List<Clusterable> clusterable = this.getClusterable(coallescing); */
((Clusterable) candidate).coalesce(clusterable); // ---------------------------------------------------------------------------
coallesced.addAll(coallescing);
clusters.add((Clusterable) candidate); public void addConstituent(P constituent) {
if (!this.constituents.contains(constituent)) {
this.constituents.add(constituent);
}
}
// ---------------------------------------------------------------------------
/**
* @param positionables
*/
// ---------------------------------------------------------------------------
public void refresh() {
kdTree = new KdTree<>(this.constituents, 2, this.comparator);
clustered.clear();
List<P> coallesced = new ArrayList<>();
for (P candidate : this.constituents) {
if ((candidate instanceof Clusterable) && !coallesced.contains(candidate)) {
List<P> coallescing = kdTree.findNearest(candidate, radius);
if (coallescing.size() > 1) {
List<Clusterable> clusterable = this.getClusterable(coallescing);
coallesced.addAll(coallescing);
((Clusterable) candidate).coalesce(clusterable);
}
clustered.add(candidate);
} }
} }
} }
// ---------------------------------------------------------------------------
public boolean hasClusters() {
return !this.clustered.isEmpty();
}
// ---------------------------------------------------------------------------
public List<P> getClusters() {
return this.clustered;
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// *************************************************************************** // ***************************************************************************
// * End of Class // * End of Class
......
...@@ -16,8 +16,10 @@ ...@@ -16,8 +16,10 @@
*/ */
package lu.list.itis.dkd.tui.feature.cluster; package lu.list.itis.dkd.tui.feature.cluster;
import lu.list.itis.dkd.tui.utility.CoordinateState;
import lu.list.itis.dkd.tui.utility.Point; import lu.list.itis.dkd.tui.utility.Point;
import lu.list.itis.dkd.tui.utility.Positionable; import lu.list.itis.dkd.tui.utility.Positionable;
import lu.list.itis.dkd.tui.utility.ScreenCoordinates;
import lu.list.itis.dkd.tui.utility.kdtree.KdComparator; import lu.list.itis.dkd.tui.utility.kdtree.KdComparator;
/** /**
...@@ -27,27 +29,39 @@ import lu.list.itis.dkd.tui.utility.kdtree.KdComparator; ...@@ -27,27 +29,39 @@ import lu.list.itis.dkd.tui.utility.kdtree.KdComparator;
*/ */
public class PositionableComparator implements KdComparator<Positionable> { public class PositionableComparator implements KdComparator<Positionable> {
private Class<? extends CoordinateState> referenceState = ScreenCoordinates.class;
public void setReferenceState(Class<? extends CoordinateState> state) {
this.referenceState = state;
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public int compare(Positionable o1, Positionable o2, int axis) { public int compare(Positionable o1, Positionable o2, int axis) {
Point pos1 = o1.getPosition(); Point pos1 = o1.getPosition().clone();
Point pos2 = o2.getPosition(); Point pos2 = o2.getPosition().clone();
pos1.toCoordinates(this.referenceState);
pos2.toCoordinates(this.referenceState);
return pos1.compareTo(pos2, axis); return pos1.compareTo(pos2, axis);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public double getDistance(Positionable o1, Positionable o2) { public double getDistance(Positionable o1, Positionable o2) {
Point pos1 = o1.getPosition(); Point pos1 = o1.getPosition().clone();
Point pos2 = o2.getPosition(); Point pos2 = o2.getPosition().clone();
pos1.toCoordinates(this.referenceState);
pos2.toCoordinates(this.referenceState);
return pos1.getDistance(pos2); return pos1.getDistance(pos2);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public double getDistance(Positionable o1, Positionable o2, int axis) { public double getDistance(Positionable o1, Positionable o2, int axis) {
Point pos1 = o1.getPosition(); Point pos1 = o1.getPosition().clone();
Point pos2 = o2.getPosition(); Point pos2 = o2.getPosition().clone();
pos1.toCoordinates(this.referenceState);
pos2.toCoordinates(this.referenceState);
return pos1.getDistance(pos2, axis); return pos1.getDistance(pos2, axis);
} }
......
...@@ -58,6 +58,7 @@ public abstract class Marker implements Positionable, Clusterable, Cloneable { ...@@ -58,6 +58,7 @@ public abstract class Marker implements Positionable, Clusterable, Cloneable {
this.isClusterable = builder.isClusterable; this.isClusterable = builder.isClusterable;
this.coronas = builder.coronas; this.coronas = builder.coronas;
this.positions = builder.positions; this.positions = builder.positions;
this.clustered = new ArrayList<>();
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
...@@ -67,6 +68,7 @@ public abstract class Marker implements Positionable, Clusterable, Cloneable { ...@@ -67,6 +68,7 @@ public abstract class Marker implements Positionable, Clusterable, Cloneable {
this.isClusterable = original.isClusterable; this.isClusterable = original.isClusterable;
this.coronas = original.cloneCoronas(); this.coronas = original.cloneCoronas();
this.positions = original.clonePositions(); this.positions = original.clonePositions();
this.clustered = new ArrayList<>();
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment