RED-7141: Performance improvments

This commit is contained in:
Dominique Eifländer 2024-03-08 09:57:12 +01:00
parent cb9127b4f3
commit d659fe7234
5 changed files with 77 additions and 28 deletions

View File

@ -77,9 +77,9 @@ public class Character {
public double angle(Character character) { public double angle(Character character) {
if (getX() > character.getX()) { if (getX() > character.getX()) {
return FastAtan2.atan2(getY() - character.getY(), getX() - character.getX()); return FastAtan2.fastAtan2(getY() - character.getY(), getX() - character.getX());
} else { } else {
return FastAtan2.atan2(character.getY() - getY(), character.getX() - getX()); return FastAtan2.fastAtan2(character.getY() - getY(), character.getX() - getX());
} }
} }

View File

@ -6,8 +6,7 @@ public class Neighbor {
@Getter @Getter
private final double distance; private final double distance;
@Getter private Double angle;
private final double angle;
private final Character originCharacter; private final Character originCharacter;
@Getter @Getter
private final Character character; private final Character character;
@ -16,7 +15,6 @@ public class Neighbor {
public Neighbor(Character neighbor, Character origin) { public Neighbor(Character neighbor, Character origin) {
this.distance = neighbor.distance(origin); this.distance = neighbor.distance(origin);
this.angle = neighbor.angle(origin);
this.character = neighbor; this.character = neighbor;
this.originCharacter = origin; this.originCharacter = origin;
} }
@ -33,4 +31,13 @@ public class Neighbor {
return character.verticalDistance(originCharacter); return character.verticalDistance(originCharacter);
} }
public double getAngle() {
if (angle != null) {
return angle;
}
return this.character.angle(this.originCharacter);
}
} }

View File

@ -31,8 +31,9 @@ public class NearestNeighbourService {
for (int i = 0; i < characters.size(); i++) { for (int i = 0; i < characters.size(); i++) {
List<Neighbor> candidates = new ArrayList<>(); Neighbor[] candidates = new Neighbor[maxNeighborCount + 1];
int neighborInsertionIndex = 0;
int neighborCount = 0;
int start = i; int start = i;
int end = i + 1; int end = i + 1;
@ -45,42 +46,83 @@ public class NearestNeighbourService {
while (start > 0 && characters.get(i).getX() - characters.get(start - 1).getX() < searchDistance) { while (start > 0 && characters.get(i).getX() - characters.get(start - 1).getX() < searchDistance) {
start--; start--;
candidates.add(new Neighbor(characters.get(start), characters.get(i))); candidates[neighborInsertionIndex] = new Neighbor(characters.get(start), characters.get(i));
clearMostDistant(candidates, maxNeighborCount); neighborCount++;
if (neighborCount > maxNeighborCount) {
neighborInsertionIndex = clearMostDistant(candidates);
neighborCount--;
} else {
neighborInsertionIndex++;
}
newCandidatesFound = true; newCandidatesFound = true;
} }
while (end < characters.size() && characters.get(end).getX() - characters.get(i).getX() < searchDistance) { while (end < characters.size() && characters.get(end).getX() - characters.get(i).getX() < searchDistance) {
candidates.add(new Neighbor(characters.get(end), characters.get(i))); candidates[neighborInsertionIndex] = new Neighbor(characters.get(end), characters.get(i));
clearMostDistant(candidates, maxNeighborCount); neighborCount++;
if (neighborCount > maxNeighborCount) {
neighborInsertionIndex = clearMostDistant(candidates);
neighborCount--;
} else {
neighborInsertionIndex++;
}
end++; end++;
newCandidatesFound = true; newCandidatesFound = true;
} }
if (newCandidatesFound && candidates.size() >= maxNeighborCount) { if (newCandidatesFound && neighborCount >= maxNeighborCount) {
distance = candidates.stream().mapToDouble(Neighbor::getDistance).max().orElse(Double.POSITIVE_INFINITY); distance = maxDistance(candidates);
} }
} }
clearMostDistant(candidates, maxNeighborCount); if (neighborCount < maxNeighborCount) {
characters.get(i).setNeighbors(new ArrayList<>(candidates)); clearMostDistant(candidates);
}
List<Neighbor> 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<Neighbor> candidates, int maxNeighborCount) { private double maxDistance(Neighbor[] candidates) {
if (candidates.size() > maxNeighborCount) { double maxDistance = 0;
double maxDistance = 0; for (Neighbor candidate : candidates) {
int maxIndex = 0; if (candidate == null) {
for (int i = 0; i < candidates.size(); i++) { continue;
Neighbor candidate = candidates.get(i); }
if (candidate.getDistance() > maxDistance) { if (candidate.getDistance() > maxDistance) {
maxDistance = candidate.getDistance(); maxDistance = candidate.getDistance();
maxIndex = i;
}
} }
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;
} }
} }

View File

@ -37,7 +37,7 @@ public class FastAtan2 {
} }
@SuppressWarnings("ParameterAssignment") @SuppressWarnings("ParameterAssignment")
static public double atan2(double y, double x) { static public double fastAtan2(double y, double x) {
if (y < 0) { if (y < 0) {
if (x < 0) { if (x < 0) {

View File

@ -33,8 +33,8 @@ public class ViewerDocumentTest extends BuildDocumentTest {
ViewerDocumentService viewerDocumentService = new ViewerDocumentService(null); ViewerDocumentService viewerDocumentService = new ViewerDocumentService(null);
LayoutGridService layoutGridService = new LayoutGridService(viewerDocumentService); LayoutGridService layoutGridService = new LayoutGridService(viewerDocumentService);
Document document = buildGraph(fileName, LayoutParsingType.REDACT_MANAGER);
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
Document document = buildGraph(fileName, LayoutParsingType.REDACT_MANAGER);
layoutGridService.addLayoutGrid(documentFile, document, new File(tmpFileName), true); layoutGridService.addLayoutGrid(documentFile, document, new File(tmpFileName), true);
System.out.printf("Total time: %.2fs%n", ((float) (System.currentTimeMillis() - start)) / 1000); System.out.printf("Total time: %.2fs%n", ((float) (System.currentTimeMillis() - start)) / 1000);
} }