Skip to content

Commit

Permalink
add getEdgesToRoot()
Browse files Browse the repository at this point in the history
  • Loading branch information
micycle1 committed Jul 28, 2023
1 parent b2d29f0 commit 5207bec
Showing 1 changed file with 79 additions and 26 deletions.
105 changes: 79 additions & 26 deletions src/main/java/micycle/medialAxis/MedialAxis.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,14 @@

import org.locationtech.jts.algorithm.Orientation;
import org.locationtech.jts.algorithm.locate.IndexedPointInAreaLocator;
import org.locationtech.jts.densify.Densifier;
import org.locationtech.jts.dissolve.LineDissolver;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.Location;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.operation.linemerge.LineMergeGraph;
import org.locationtech.jts.simplify.DouglasPeuckerSimplifier;
import org.locationtech.jts.simplify.TopologyPreservingSimplifier;
import org.tinfour.common.IConstraint;
import org.tinfour.common.IIncrementalTin;
import org.tinfour.common.IQuadEdge;
Expand Down Expand Up @@ -77,10 +72,11 @@ public class MedialAxis {

// TODO see https://www.youtube.com/watch?v=WiU0foXVSsM
// also see https://lgg.epfl.ch/publications/2009/scale_axis_transform_2009.pdf

// TODO convert disks into undirected graph (e.g. to find the distance from the furthest node to every other node).
// to enable traversal up and down the direction (And find loop connected loops)


// TODO convert disks into undirected graph (e.g. to find the distance from the
// furthest node to every other node).
// to enable traversal up and down the direction (And find loop connected loops)

/*
* or have a map of bifurcations
*/
Expand All @@ -100,6 +96,9 @@ public class MedialAxis {
private List<MedialDisk> leaves;
private List<MedialDisk> bifurcations; // birfurcating/forking nodes
private List<Branch> branches;
/**
* Gives a mapping for the edge 'parent->e' for a given edge e.
*/
private final HashMap<MedialDisk, Edge> edges; // a map of edge-tail -> edge for easier access in pruning methods

public static boolean debug = false;
Expand Down Expand Up @@ -365,8 +364,9 @@ public LineMergeGraph getLineMergeGraph() {
}
return lineMergeGraph;
}

private void asGraph() {
// directed jGraphT graph
// convert to ?cyclical? jGrapt graph // TOD// then org.jgrapht.alg.cycle.CycleDetector
}

Expand All @@ -387,7 +387,7 @@ public MedialDisk getDeepestDisk() {
// return leaves.get(0); // TODO copy array first
return deepestNode;
}

public MedialDisk getFurthestDisk() {
// getLeaves().sort((a, b) -> Double.compare(b.id, a.id));
// return leaves.get(0); // TODO copy array first
Expand Down Expand Up @@ -420,7 +420,7 @@ public List<MedialDisk> getBifurcations() {
public Collection<Edge> getEdges() {
return edges.values();
}

/**
*
* @return a map of edge-tail -> edge for easier access in pruning methods
Expand All @@ -429,6 +429,17 @@ public Map<MedialDisk, Edge> getEdgeMap() {
return edges;
}

/**
* Returns the edges comprising the path from the given disk to the root of the
* medial axis.
*
* @param d
* @return
*/
public List<Edge> getEdgesToRoot(MedialDisk d) {
return getAncestors(d).stream().map(a -> edges.get(a)).collect(Collectors.toList());
}

/**
* Aka features, aka branches Segment is a linear portion of medial disks.
*
Expand Down Expand Up @@ -573,7 +584,8 @@ public List<Edge> getPrunedEdges(double axialThreshold, double distanceThreshold
* @param consumer
*/
public void iteratorBF(Consumer<MedialDisk> consumer) { // accept starting node as parameter
// TODO consumer integer arg, corresponding to recursion depth (Same for all children) (or user can reference depthBF int?)
// TODO consumer integer arg, corresponding to recursion depth (Same for all
// children) (or user can reference depthBF int?)
ArrayDeque<MedialDisk> stack = new ArrayDeque<>();
stack.add(rootNode);

Expand All @@ -591,11 +603,11 @@ public void iteratorDF(Consumer<MedialDisk> consumer) { // accept enum to determ
while (!stack.isEmpty()) {
MedialDisk live = stack.pop(); // pop first of queue
consumer.accept(live);
live.children.sort((a,b) -> Double.compare(a.distance, b.distance)); // NOTE EXAMPLE
live.children.sort((a, b) -> Double.compare(a.distance, b.distance)); // NOTE EXAMPLE
live.children.forEach(stack::push); // insert at start of queue
}
}

public void iteratorBfUp(Consumer<MedialDisk> consumer) {
// start at leaves, add parent, cleanup leaves, continue
ArrayDeque<MedialDisk> stack = new ArrayDeque<>();
Expand All @@ -609,22 +621,53 @@ public void iteratorBfUp(Consumer<MedialDisk> consumer) {
}
}
}

public void iteratorDfUp(Consumer<MedialDisk> consumer) {
// start at leaf, add parents until either root node, or next bifurcating node
// when stack not empty, stop when parent has been seen, and pop next leaf.
Set<MedialDisk> seen = new HashSet<>(getDisks().size());
ArrayDeque<MedialDisk> stack = new ArrayDeque<>();
getLeaves().sort((a,b) -> Double.compare(a.distance, b.distance) ); // NOTE
getLeaves().sort((a, b) -> Double.compare(a.distance, b.distance)); // NOTE
getLeaves().forEach(stack::push);
while (!stack.isEmpty()) {
MedialDisk live = stack.pop(); // pop first of queue
consumer.accept(live);
if (live.parent != null && seen.add(live.parent)) {
stack.push(live.parent); // insert at start of queue
}
while (!stack.isEmpty()) {
MedialDisk live = stack.pop(); // pop first of queue
consumer.accept(live);
if (live.parent != null && seen.add(live.parent)) {
stack.push(live.parent); // insert at start of queue
}

}

}

/**
* Is disk A a parent of disk B?
*
* @param a
* @param b
* @return
*/
private boolean isParentOf(MedialDisk a, MedialDisk b) {
return false; // TODO
}

private boolean isChildOf(MedialDisk a, MedialDisk b) {
return false; // TODO
}

private boolean isRelated(MedialDisk a, MedialDisk b) {
return false; // TODO
}

private void longestPath() {
/*-
* TODO
* find the two disks that make up the longest path of the medial axis.
* the path must pass through the root node.
* To compute, find non-related (i.e. not child/parent) disk pairs and sum their distance values.
* Pair with largest value denotes longest path.
* Group the disks into 3 groups, depending on which of the three root branches they belong to,
* then use pairs from distinct groups.
*/
}

/**
Expand Down Expand Up @@ -760,7 +803,7 @@ public void calcFeatureArea() {
recurseFeatureArea(rootNode);
}
}

private static double recurseFeatureArea(MedialDisk node) {
// TODO do as part of initial build?
if (node.degree == 0) {
Expand All @@ -771,7 +814,7 @@ private static double recurseFeatureArea(MedialDisk node) {
}
return node.featureArea;
}

public void drawVDM(PApplet p) {
// looks different when drawing with DFS vs BFS
p.pushStyle();
Expand Down Expand Up @@ -1005,6 +1048,16 @@ public class MedialDisk {

public final int id; // BFS id from root node, unique for each disk (unlike depthDF)

private int bifurcationDepth; // TODO, determines how many bifurcations ("hops") are between this disk and the
// root

/**
* the "kink" angle (0...PI) this disk makes with its parent and child node (if
* it has only one child). if the node has 0 or more than 1 child, this value is
* NaN
*/
private double angle = Double.NaN; // TODO initially unknown until axis is completed.

MedialDisk(MedialDisk parent, int id, SimpleTriangle t, double[] circumcircle, int depthBF) {
this.parent = parent;
this.id = id;
Expand Down

0 comments on commit 5207bec

Please sign in to comment.