Skip to content

Commit

Permalink
Housekeeping
Browse files Browse the repository at this point in the history
  • Loading branch information
behrangsa committed Oct 23, 2023
1 parent db92517 commit d0c64f6
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 146 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ repositories {
}

dependencies {
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.13.0'

testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1'
}

Expand Down
20 changes: 10 additions & 10 deletions src/main/java/org/behrang/algorithm/tree/DimensionCalculator.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

public class DimensionCalculator {
public static <T> Dimension2D calculateTreeDimension(Node<T> root) {
final AtomicReference<Double> minX = new AtomicReference<>(Double.MAX_VALUE);
final AtomicReference<Double> minY = new AtomicReference<>(Double.MAX_VALUE);
final AtomicReference<Double> maxX = new AtomicReference<>(Double.MIN_VALUE);
final AtomicReference<Double> maxY = new AtomicReference<>(Double.MIN_VALUE);
final AtomicReference<Float> minX = new AtomicReference<>(Float.MAX_VALUE);
final AtomicReference<Float> minY = new AtomicReference<>(Float.MAX_VALUE);
final AtomicReference<Float> maxX = new AtomicReference<>(Float.MIN_VALUE);
final AtomicReference<Float> maxY = new AtomicReference<>(Float.MIN_VALUE);

TreeTraversal.preorder(root, n -> {
if (n.getX() < minX.get()) {
Expand All @@ -20,19 +20,19 @@ public static <T> Dimension2D calculateTreeDimension(Node<T> root) {
minY.set(n.getY());
}

double x2 = n.getX() + n.getWidth();
float x2 = n.getX() + n.getWidth();
if (x2 > maxX.get()) {
maxX.set(x2);
}

double y2 = n.getY() + n.getHeight();
float y2 = n.getY() + n.getHeight();
if (y2 > maxY.get()) {
maxY.set(y2);
}
});

double width = (maxX.get() - minX.get());
double height = (maxY.get() - minY.get());
float width = (maxX.get() - minX.get());
float height = (maxY.get() - minY.get());

Dimension dim = new Dimension();
dim.setSize(width, height);
Expand All @@ -41,8 +41,8 @@ public static <T> Dimension2D calculateTreeDimension(Node<T> root) {
}

public static <T> Dimension2D calculateMaxNodeDimension(Node<T> root) {
final AtomicReference<Double> width = new AtomicReference<>(Double.MIN_VALUE);
final AtomicReference<Double> height = new AtomicReference<>(Double.MIN_VALUE);
final AtomicReference<Float> width = new AtomicReference<>(Float.MIN_VALUE);
final AtomicReference<Float> height = new AtomicReference<>(Float.MIN_VALUE);

TreeTraversal.preorder(root, n -> {
if (width.get() < n.getWidth()) {
Expand Down
40 changes: 40 additions & 0 deletions src/main/java/org/behrang/algorithm/tree/Functions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.behrang.algorithm.tree;

import java.util.function.Consumer;

public final class Functions {
private Functions() {
throw new RuntimeException();
}

public static Node<?> leftmostDescendantAtDepth(Node<?> node, int depth) {
return leftmostDescendantAtDepth(node, 0, depth);
}

private static Node<?> leftmostDescendantAtDepth(Node<?> node, int level, int depth) {
if (level >= depth) {
return node;
} else if (node.isLeaf()) {
return null;
} else {
var leftChild = node.getLeftChild();
var leftmost = leftmostDescendantAtDepth(leftChild, level + 1, depth);
while (leftmost == null && leftChild.hasRightSibling()) {
leftChild = leftChild.getRightSibling();
leftmost = leftmostDescendantAtDepth(leftChild, level + 1, depth);
}

return leftmost;
}
}

public static <T> void prePostOrder(Node<T> node, Consumer<Node<T>> preConsumer, Consumer<Node<T>> postConsumer) {
preConsumer.accept(node);

node.getChildren().forEach(n -> {
prePostOrder(n, preConsumer, postConsumer);
});

postConsumer.accept(node);
}
}
70 changes: 43 additions & 27 deletions src/main/java/org/behrang/algorithm/tree/Node.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,38 @@
package org.behrang.algorithm.tree;

import org.apache.commons.lang3.Validate;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class Node<T> {

private static final double DEFAULT_MODIFIER = 0.0;
private static final float DEFAULT_MODIFIER = 0.0f;

private static final float DEFAULT_PRELIM = 0.0f;

private static final double DEFAULT_PRELIM = 0.0;
private static final float DEFAULT_WIDTH = 2.0f;

private static final float DEFAULT_HEIGHT = 2.0f;

private Node<T> parent;

private final List<Node<T>> children;

private T value;

private double x;
private float x;

private double y;
private float y;

private double width;
private float width;

private double height;
private float height;

private double prelim = DEFAULT_PRELIM;
private float prelim = DEFAULT_PRELIM;

private double modifier = DEFAULT_MODIFIER;
private float modifier = DEFAULT_MODIFIER;

private Node<T> leftNeighbor;

Expand All @@ -35,7 +41,17 @@ public Node() {
}

public Node(T value) {
this(value, DEFAULT_WIDTH, DEFAULT_HEIGHT);
}

public Node(T value, float width, float height) {
Validate.notNull(value, "value must be non-null");
Validate.isTrue(width > 0);
Validate.isTrue(height > 0);

this.value = value;
this.width = width;
this.height = height;
this.children = new ArrayList<>();
}

Expand Down Expand Up @@ -67,51 +83,51 @@ public void setValue(T value) {
this.value = value;
}

public double getX() {
public float getX() {
return x;
}

public void setX(double x) {
public void setX(float x) {
this.x = x;
}

public double getY() {
public float getY() {
return y;
}

public void setY(double y) {
public void setY(float y) {
this.y = y;
}

public double getWidth() {
public float getWidth() {
return width;
}

public void setWidth(double width) {
public void setWidth(float width) {
this.width = width;
}

public double getHeight() {
public float getHeight() {
return height;
}

public void setHeight(double height) {
public void setHeight(float height) {
this.height = height;
}

public double getPrelim() {
public float getPrelim() {
return prelim;
}

public void setPrelim(double prelim) {
public void setPrelim(float prelim) {
this.prelim = prelim;
}

public double getModifier() {
public float getModifier() {
return modifier;
}

public void setModifier(double modifier) {
public void setModifier(float modifier) {
this.modifier = modifier;
}

Expand Down Expand Up @@ -217,25 +233,25 @@ public Node<T> getLeftmost(int targetLevel) {
return null;
}

public void incrementPrelimBy(double delta) {
public void incrementPrelimBy(float delta) {
setPrelim(prelim + delta);
}

public void incrementModifierBy(double delta) {
public void incrementModifierBy(float delta) {
setModifier(modifier + delta);
}

public int getMaxDepth() {
public int getDepth() {
Node<T> tree = this;
if (tree.getChildren().isEmpty()) {
return 1;
}

return tree.getChildren()
.stream()
.mapToInt(Node::getMaxDepth)
.max()
.orElse(0) + 1;
.stream()
.mapToInt(Node::getDepth)
.max()
.orElse(0) + 1;
}

@Override
Expand Down
48 changes: 23 additions & 25 deletions src/main/java/org/behrang/algorithm/tree/WalkerAlgorithm.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,19 @@

public class WalkerAlgorithm<T> {

private static final long MAX_DEPTH = Long.MAX_VALUE;

private final Map<Integer, Node<T>> previousNodeAtLevel;

private final double siblingSeparation;
private final float siblingSeparation;

private final double subtreeSeparation;
private final float subtreeSeparation;

private final double levelSeparation;
private final float levelSeparation;

private final double xTopAdjustment;
private final float xTopAdjustment;

private final double yTopAdjustment;
private final float yTopAdjustment;

public WalkerAlgorithm(double siblingSeparation, double subtreeSeparation, double xTopAdjustment, double yTopAdjustment, double levelSeparation) {
public WalkerAlgorithm(float siblingSeparation, float subtreeSeparation, float xTopAdjustment, float yTopAdjustment, float levelSeparation) {
this.previousNodeAtLevel = new HashMap<>();
this.siblingSeparation = siblingSeparation;
this.subtreeSeparation = subtreeSeparation;
Expand All @@ -41,21 +39,22 @@ public void position(Node<T> node) {
}

void firstWalk(Node<T> thisNode, int currentLevel) {
// We need to maintain
Node<T> leftNeighbor = getPreviousNodeAtLevel(currentLevel);
thisNode.setLeftNeighbor(leftNeighbor);
setPreviousNodeAtLevel(currentLevel, thisNode);
thisNode.getChildren().forEach(child -> {
firstWalk(child, currentLevel + 1);
});

if (thisNode.isLeaf() || currentLevel == MAX_DEPTH) {
if (thisNode.isLeaf()) {
if (thisNode.hasLeftSibling()) {
thisNode.setPrelim(thisNode.getLeftSibling().getPrelim() + siblingSeparation + meanWidth(thisNode.getLeftSibling(), thisNode));
} else {
thisNode.setPrelim(0);
}
} else {
double midpoint = (thisNode.getLeftChild().getPrelim() + thisNode.getRightChild().getPrelim()) / 2;
float midpoint = (thisNode.getLeftChild().getPrelim() + thisNode.getRightChild().getPrelim()) / 2;

if (thisNode.hasLeftSibling()) {
thisNode.setPrelim(thisNode.getLeftSibling().getPrelim() + siblingSeparation + meanWidth(thisNode.getLeftSibling(), thisNode));
Expand All @@ -68,9 +67,9 @@ void firstWalk(Node<T> thisNode, int currentLevel) {
}
}

void secondWalk(Node<T> node, int level, double modSum) {
double xTemp = xTopAdjustment + node.getPrelim() + modSum;
double yTemp = yTopAdjustment + (level * levelSeparation);
void secondWalk(Node<T> node, int level, float modSum) {
float xTemp = xTopAdjustment + node.getPrelim() + modSum;
float yTemp = yTopAdjustment + (level * levelSeparation);

node.setX(xTemp);
node.setY(yTemp);
Expand All @@ -84,15 +83,15 @@ void apportion(Node<T> treeNode, int baseLevel) {
Node<T> leftMost = treeNode.getLeftChild();
Node<T> leftNeighbor;

for (int level = baseLevel; level < treeNode.getMaxDepth(); level++) {
for (int level = baseLevel; level < treeNode.getDepth(); level++) {
leftNeighbor = leftMost.getLeftNeighbor();

if (leftMost == null || leftNeighbor == null) {
return;
}

double leftModSum = 0.0;
double rightModSum = 0.0;
float leftModSum = 0.0f;
float rightModSum = 0.0f;
Node<T> ancestorLeftmost = leftMost;
Node<T> ancestorNeighbor = leftNeighbor;
while (ancestorLeftmost != treeNode) {
Expand All @@ -102,11 +101,11 @@ void apportion(Node<T> treeNode, int baseLevel) {
leftModSum += ancestorNeighbor.getModifier();
}

double moveDistance = (
leftNeighbor.getPrelim() +
leftModSum +
subtreeSeparation +
meanWidth(treeNode.getLeftSibling(), treeNode)
float moveDistance = (
leftNeighbor.getPrelim() +
leftModSum +
subtreeSeparation +
meanWidth(treeNode.getLeftSibling(), treeNode)
) - (leftMost.getPrelim() + rightModSum);

if (moveDistance > 0) {
Expand All @@ -119,7 +118,7 @@ void apportion(Node<T> treeNode, int baseLevel) {
}

if (tempNode != null) {
double portion = moveDistance / numLeftSiblings;
float portion = moveDistance / numLeftSiblings;
tempNode = treeNode;

while (tempNode != ancestorNeighbor) {
Expand All @@ -133,7 +132,6 @@ void apportion(Node<T> treeNode, int baseLevel) {
}
}


if (leftMost.getChildren().isEmpty()) {
leftMost = treeNode.getLeftmost(level + 2);
} else {
Expand Down Expand Up @@ -170,7 +168,7 @@ Node<T> getLeftmostDescendant(Node<T> node, int level, int depth) {
return leftmost;
}

double meanWidth(Node<T> n1, Node<T> n2) {
return (n1.getWidth() + n2.getWidth()) / 2.0;
float meanWidth(Node<T> n1, Node<T> n2) {
return (n1.getWidth() + n2.getWidth()) / 2.0f;
}
}
Loading

0 comments on commit d0c64f6

Please sign in to comment.