diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/model/Character.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/model/Character.java index 0b299aa..7df77ea 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/model/Character.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/model/Character.java @@ -77,9 +77,9 @@ public class Character { public double angle(Character character) { if (getX() > character.getX()) { - return FastAtan2.atan2(getY() - character.getY(), getX() - character.getX()); + return FastAtan2.fastAtan2(getY() - character.getY(), getX() - character.getX()); } else { - return FastAtan2.atan2(character.getY() - getY(), character.getX() - getX()); + return FastAtan2.fastAtan2(character.getY() - getY(), character.getX() - getX()); } } diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/model/Neighbor.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/model/Neighbor.java index b2b4174..b06d5e0 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/model/Neighbor.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/model/Neighbor.java @@ -6,8 +6,7 @@ public class Neighbor { @Getter private final double distance; - @Getter - private final double angle; + private Double angle; private final Character originCharacter; @Getter private final Character character; @@ -16,7 +15,6 @@ public class Neighbor { public Neighbor(Character neighbor, Character origin) { this.distance = neighbor.distance(origin); - this.angle = neighbor.angle(origin); this.character = neighbor; this.originCharacter = origin; } @@ -33,4 +31,13 @@ public class Neighbor { return character.verticalDistance(originCharacter); } + + public double getAngle() { + + if (angle != null) { + return angle; + } + return this.character.angle(this.originCharacter); + } + } \ No newline at end of file diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/service/NearestNeighbourService.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/service/NearestNeighbourService.java index 4a8338e..cf402d8 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/service/NearestNeighbourService.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/service/NearestNeighbourService.java @@ -31,8 +31,9 @@ public class NearestNeighbourService { for (int i = 0; i < characters.size(); i++) { - List candidates = new ArrayList<>(); - + Neighbor[] candidates = new Neighbor[maxNeighborCount + 1]; + int neighborInsertionIndex = 0; + int neighborCount = 0; int start = i; int end = i + 1; @@ -45,42 +46,83 @@ public class NearestNeighbourService { while (start > 0 && characters.get(i).getX() - characters.get(start - 1).getX() < searchDistance) { start--; - candidates.add(new Neighbor(characters.get(start), characters.get(i))); - clearMostDistant(candidates, maxNeighborCount); + candidates[neighborInsertionIndex] = new Neighbor(characters.get(start), characters.get(i)); + neighborCount++; + if (neighborCount > maxNeighborCount) { + neighborInsertionIndex = clearMostDistant(candidates); + neighborCount--; + } else { + neighborInsertionIndex++; + } newCandidatesFound = true; } while (end < characters.size() && characters.get(end).getX() - characters.get(i).getX() < searchDistance) { - candidates.add(new Neighbor(characters.get(end), characters.get(i))); - clearMostDistant(candidates, maxNeighborCount); + candidates[neighborInsertionIndex] = new Neighbor(characters.get(end), characters.get(i)); + neighborCount++; + if (neighborCount > maxNeighborCount) { + neighborInsertionIndex = clearMostDistant(candidates); + neighborCount--; + } else { + neighborInsertionIndex++; + } end++; newCandidatesFound = true; } - if (newCandidatesFound && candidates.size() >= maxNeighborCount) { - distance = candidates.stream().mapToDouble(Neighbor::getDistance).max().orElse(Double.POSITIVE_INFINITY); + if (newCandidatesFound && neighborCount >= maxNeighborCount) { + distance = maxDistance(candidates); } } - clearMostDistant(candidates, maxNeighborCount); - characters.get(i).setNeighbors(new ArrayList<>(candidates)); + if (neighborCount < maxNeighborCount) { + clearMostDistant(candidates); + } + + List candidatesList = new ArrayList<>(maxNeighborCount); + for (Neighbor candidate : candidates) { + if (candidate != null) { + candidatesList.add(candidate); + } + } + candidatesList.sort(Comparator.comparingDouble(Neighbor::getDistance)); + assert candidatesList.size() == maxNeighborCount; + characters.get(i).setNeighbors(candidatesList); } } - private void clearMostDistant(List candidates, int maxNeighborCount) { + private double maxDistance(Neighbor[] candidates) { - if (candidates.size() > maxNeighborCount) { - double maxDistance = 0; - int maxIndex = 0; - for (int i = 0; i < candidates.size(); i++) { - Neighbor candidate = candidates.get(i); - if (candidate.getDistance() > maxDistance) { - maxDistance = candidate.getDistance(); - maxIndex = i; - } + double maxDistance = 0; + for (Neighbor candidate : candidates) { + if (candidate == null) { + continue; + } + if (candidate.getDistance() > maxDistance) { + maxDistance = candidate.getDistance(); } - candidates.remove(maxIndex); } + return maxDistance; + } + + + private int clearMostDistant(Neighbor[] candidates) { + + double maxDistance = 0; + int maxIndex = 0; + for (int i = 0; i < candidates.length; i++) { + Neighbor candidate = candidates[i]; + if (candidate == null) { + continue; + } + if (candidate.getDistance() > maxDistance) { + maxDistance = candidate.getDistance(); + maxIndex = i; + } + } + candidates[maxIndex] = null; + return maxIndex; } } + diff --git a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/utils/FastAtan2.java b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/utils/FastAtan2.java index 753fa2b..6d6cb36 100644 --- a/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/utils/FastAtan2.java +++ b/layoutparser-service/layoutparser-service-processor/src/main/java/com/knecon/fforesight/service/layoutparser/processor/services/docstrum/utils/FastAtan2.java @@ -37,7 +37,7 @@ public class FastAtan2 { } @SuppressWarnings("ParameterAssignment") - static public double atan2(double y, double x) { + static public double fastAtan2(double y, double x) { if (y < 0) { if (x < 0) { diff --git a/layoutparser-service/layoutparser-service-server/src/test/java/com/knecon/fforesight/service/layoutparser/server/graph/ViewerDocumentTest.java b/layoutparser-service/layoutparser-service-server/src/test/java/com/knecon/fforesight/service/layoutparser/server/graph/ViewerDocumentTest.java index 246d9aa..89d489f 100644 --- a/layoutparser-service/layoutparser-service-server/src/test/java/com/knecon/fforesight/service/layoutparser/server/graph/ViewerDocumentTest.java +++ b/layoutparser-service/layoutparser-service-server/src/test/java/com/knecon/fforesight/service/layoutparser/server/graph/ViewerDocumentTest.java @@ -33,8 +33,8 @@ public class ViewerDocumentTest extends BuildDocumentTest { ViewerDocumentService viewerDocumentService = new ViewerDocumentService(null); LayoutGridService layoutGridService = new LayoutGridService(viewerDocumentService); - Document document = buildGraph(fileName, LayoutParsingType.REDACT_MANAGER); long start = System.currentTimeMillis(); + Document document = buildGraph(fileName, LayoutParsingType.REDACT_MANAGER); layoutGridService.addLayoutGrid(documentFile, document, new File(tmpFileName), true); System.out.printf("Total time: %.2fs%n", ((float) (System.currentTimeMillis() - start)) / 1000); }