|
|
|
@@ -8,10 +8,13 @@ import java.awt.geom.Point2D;
|
|
|
|
|
import java.awt.geom.Rectangle2D;
|
|
|
|
|
import java.awt.geom.RectangularShape;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.Comparator;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Optional;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
|
@@ -33,7 +36,7 @@ public class LayoutGridService {
|
|
|
|
|
private static final Color INNER_LINES_COLOR = new Color(255, 175, 175);
|
|
|
|
|
private static final Color PARAGRAPH_COLOR = new Color(70, 130, 180);
|
|
|
|
|
public static final Color TABLE_COLOR = new Color(102, 205, 170);
|
|
|
|
|
public static final Color SECTION_COLOR = new Color(23, 23, 23);
|
|
|
|
|
public static final Color SECTION_COLOR = new Color(50, 50, 50);
|
|
|
|
|
public static final Color HEADLINE_COLOR = new Color(162, 56, 56);
|
|
|
|
|
public static final Color HEADER_COLOR = new Color(171, 131, 6);
|
|
|
|
|
public static final Color IMAGE_COLOR = new Color(253, 63, 146);
|
|
|
|
@@ -60,7 +63,7 @@ public class LayoutGridService {
|
|
|
|
|
}
|
|
|
|
|
if (semanticNode.getType().equals(NodeType.TABLE)) {
|
|
|
|
|
Table table = (Table) semanticNode;
|
|
|
|
|
addInnerTableLines(table, layoutGrid, INNER_LINES_COLOR);
|
|
|
|
|
addInnerTableLines(table, layoutGrid);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
@@ -68,26 +71,51 @@ public class LayoutGridService {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void addInnerTableLines(Table table, LayoutGrid layoutGrid, Color color) {
|
|
|
|
|
private void addInnerTableLines(Table table, LayoutGrid layoutGrid) {
|
|
|
|
|
|
|
|
|
|
if (table.getNumberOfCols() < 1 || table.getNumberOfRows() < 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// only draw inner lines -> remove first values
|
|
|
|
|
List<Double> xs = table.streamRow(0).map(TableCell::getBBox).map(map -> map.values().stream().findAny().get()).map(RectangularShape::getMinX).collect(Collectors.toList());
|
|
|
|
|
xs.remove(0);
|
|
|
|
|
List<Double> ys = table.streamCol(0).map(TableCell::getBBox).map(map -> map.values().stream().findAny().get()).map(RectangularShape::getMaxY).collect(Collectors.toList());
|
|
|
|
|
ys.remove(0);
|
|
|
|
|
Rectangle2D tableBBox = table.getBBox().get(table.getFirstPage());
|
|
|
|
|
List<ColoredLine> coloredLines = layoutGrid.getVisualizationsPerPages().get(table.getFirstPage().getNumber() - 1).getColoredLines();
|
|
|
|
|
xs.forEach(x -> {
|
|
|
|
|
Line2D line = new Line2D.Double(new Point2D.Double(x, tableBBox.getMaxY()), new Point2D.Double(x, tableBBox.getMinY()));
|
|
|
|
|
coloredLines.add(new ColoredLine(line, color));
|
|
|
|
|
});
|
|
|
|
|
ys.forEach(y -> {
|
|
|
|
|
Line2D line = new Line2D.Double(new Point2D.Double(tableBBox.getMinX(), y), new Point2D.Double(tableBBox.getMaxX(), y));
|
|
|
|
|
coloredLines.add(new ColoredLine(line, color));
|
|
|
|
|
});
|
|
|
|
|
for (Page page : table.getPages()) {
|
|
|
|
|
Optional<Integer> optionalFirstRowOnPage = table.streamCol(0).filter(tableCell -> tableCell.isOnPage(page.getNumber())).map(TableCell::getRow).findFirst();
|
|
|
|
|
if (optionalFirstRowOnPage.isEmpty()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
int firstRowOnPage = optionalFirstRowOnPage.get();
|
|
|
|
|
Stream<Double> xStream = switch (page.getRotation()) {
|
|
|
|
|
case 90 -> streamBBoxOfCellsOnPage(table.streamCol(0), page).map(RectangularShape::getMinX);
|
|
|
|
|
case 180 -> streamBBoxOfCellsOnPage(table.streamRow(firstRowOnPage), page).map(RectangularShape::getMaxX);
|
|
|
|
|
case 270 -> streamBBoxOfCellsOnPage(table.streamCol(0), page).map(RectangularShape::getMaxX);
|
|
|
|
|
default -> streamBBoxOfCellsOnPage(table.streamRow(firstRowOnPage), page).map(RectangularShape::getMinX);
|
|
|
|
|
};
|
|
|
|
|
List<Double> xs = xStream.collect(Collectors.toList());
|
|
|
|
|
xs.remove(0);
|
|
|
|
|
Stream<Double> yStream = switch (page.getRotation()) {
|
|
|
|
|
case 90 -> streamBBoxOfCellsOnPage(table.streamRow(firstRowOnPage), page).map(RectangularShape::getMinY);
|
|
|
|
|
case 180 -> streamBBoxOfCellsOnPage(table.streamCol(0), page).map(RectangularShape::getMinY);
|
|
|
|
|
case 270 -> streamBBoxOfCellsOnPage(table.streamRow(firstRowOnPage), page).map(RectangularShape::getMaxY);
|
|
|
|
|
default -> streamBBoxOfCellsOnPage(table.streamCol(0), page).map(RectangularShape::getMaxY);
|
|
|
|
|
};
|
|
|
|
|
List<Double> ys = yStream.collect(Collectors.toList());
|
|
|
|
|
ys.remove(0);
|
|
|
|
|
|
|
|
|
|
Rectangle2D tableBBox = table.getBBox().get(table.getFirstPage());
|
|
|
|
|
List<ColoredLine> coloredLines = layoutGrid.getVisualizationsPerPages().get(page.getNumber() - 1).getColoredLines();
|
|
|
|
|
xs.forEach(x -> {
|
|
|
|
|
Line2D line = new Line2D.Double(new Point2D.Double(x, tableBBox.getMaxY()), new Point2D.Double(x, tableBBox.getMinY()));
|
|
|
|
|
coloredLines.add(new ColoredLine(line, INNER_LINES_COLOR));
|
|
|
|
|
});
|
|
|
|
|
ys.forEach(y -> {
|
|
|
|
|
Line2D line = new Line2D.Double(new Point2D.Double(tableBBox.getMinX(), y), new Point2D.Double(tableBBox.getMaxX(), y));
|
|
|
|
|
coloredLines.add(new ColoredLine(line, INNER_LINES_COLOR));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static Stream<Rectangle2D> streamBBoxOfCellsOnPage(Stream<TableCell> table, Page page) {
|
|
|
|
|
|
|
|
|
|
return table.filter(tableCell -> tableCell.isOnPage(page.getNumber())).map(TableCell::getBBox).map(bBoxMap -> bBoxMap.get(page));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -95,17 +123,16 @@ public class LayoutGridService {
|
|
|
|
|
|
|
|
|
|
Map<Page, Rectangle2D> bBoxMap = semanticNode.getBBox();
|
|
|
|
|
List<SemanticNode> subSections = semanticNode.streamAllSubNodesOfType(NodeType.SECTION).toList();
|
|
|
|
|
Page firstPage = semanticNode.getFirstPage();
|
|
|
|
|
if (!subSections.isEmpty()) {
|
|
|
|
|
Page firstPage = semanticNode.getFirstPage();
|
|
|
|
|
addPlacedText(firstPage, bBoxMap.get(firstPage), buildTreeIdString(semanticNode), layoutGrid);
|
|
|
|
|
} else {
|
|
|
|
|
bBoxMap.forEach(((page, textBBox) -> addPlacedText(page, textBBox, buildTreeIdString(semanticNode), layoutGrid)));
|
|
|
|
|
}
|
|
|
|
|
if (bBoxMap.values().size() == 1) {
|
|
|
|
|
Rectangle2D r = RectangleTransformations.pad(bBoxMap.values().stream().findFirst().get(), LINE_WIDTH, LINE_WIDTH);
|
|
|
|
|
int pageNumber = bBoxMap.keySet().stream().findFirst().get().getNumber() - 1;
|
|
|
|
|
List<ColoredLine> coloredLines = layoutGrid.getVisualizationsPerPages().get(pageNumber).getColoredLines();
|
|
|
|
|
List<Line2D> lines = createLinesFromRectangle(r);
|
|
|
|
|
Rectangle2D r = RectangleTransformations.pad(bBoxMap.get(firstPage), LINE_WIDTH, LINE_WIDTH);
|
|
|
|
|
List<ColoredLine> coloredLines = layoutGrid.getVisualizationsPerPages().get(firstPage.getNumber() - 1).getColoredLines();
|
|
|
|
|
List<Line2D> lines = createLinesFromRectangle(r, firstPage.getRotation());
|
|
|
|
|
// add string to top line
|
|
|
|
|
var firstLine = lines.remove(0);
|
|
|
|
|
coloredLines.add(new ColoredLine(firstLine, color));
|
|
|
|
@@ -115,7 +142,7 @@ public class LayoutGridService {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
List<Page> pagesInOrder = bBoxMap.keySet().stream().sorted(Comparator.comparingInt(Page::getNumber)).collect(Collectors.toList());
|
|
|
|
|
var firstPage = pagesInOrder.remove(0);
|
|
|
|
|
pagesInOrder.remove(0);
|
|
|
|
|
addLinesForFirstPageOfSection(semanticNode, color, firstPage, layoutGrid);
|
|
|
|
|
var lastPage = pagesInOrder.remove(pagesInOrder.size() - 1);
|
|
|
|
|
addLinesForLastPageOfSection(semanticNode, color, lastPage, layoutGrid);
|
|
|
|
@@ -127,8 +154,14 @@ public class LayoutGridService {
|
|
|
|
|
|
|
|
|
|
private void addPlacedText(Page page, Rectangle2D textBBox, String s, LayoutGrid layoutGrid) {
|
|
|
|
|
|
|
|
|
|
Point2D.Float upperLeftCorner = switch (page.getRotation()) {
|
|
|
|
|
case 90 -> new Point2D.Float((float) (textBBox.getMinX()), (float) textBBox.getMinY());
|
|
|
|
|
case 180 -> new Point2D.Float((float) (textBBox.getMaxX()), (float) textBBox.getMinY());
|
|
|
|
|
case 270 -> new Point2D.Float((float) (textBBox.getMaxX()), (float) textBBox.getMaxY());
|
|
|
|
|
default -> new Point2D.Float((float) (textBBox.getMinX()), (float) textBBox.getMaxY());
|
|
|
|
|
};
|
|
|
|
|
var placedTexts = layoutGrid.getVisualizationsPerPages().get(page.getNumber() - 1).getPlacedTexts();
|
|
|
|
|
placedTexts.add(new PlacedText(s, new Point2D.Float((float) (textBBox.getMinX()), (float) textBBox.getMaxY())));
|
|
|
|
|
placedTexts.add(new PlacedText(s, upperLeftCorner));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -136,7 +169,7 @@ public class LayoutGridService {
|
|
|
|
|
|
|
|
|
|
List<ColoredLine> coloredLines = layoutGrid.getVisualizationsPerPages().get(middlePage.getNumber() - 1).getColoredLines();
|
|
|
|
|
Rectangle2D r = RectangleTransformations.pad(semanticNode.getBBox().get(middlePage), LINE_WIDTH, LINE_WIDTH);
|
|
|
|
|
var midPageLines = createLinesFromRectangle(r);
|
|
|
|
|
var midPageLines = createLinesFromRectangle(r, middlePage.getRotation());
|
|
|
|
|
// remove top line
|
|
|
|
|
midPageLines.remove(0);
|
|
|
|
|
// remove top line
|
|
|
|
@@ -154,7 +187,7 @@ public class LayoutGridService {
|
|
|
|
|
|
|
|
|
|
List<ColoredLine> coloredLines = layoutGrid.getVisualizationsPerPages().get(lastPage.getNumber() - 1).getColoredLines();
|
|
|
|
|
Rectangle2D r = RectangleTransformations.pad(semanticNode.getBBox().get(lastPage), LINE_WIDTH, LINE_WIDTH);
|
|
|
|
|
var lastPageLines = createLinesFromRectangle(r);
|
|
|
|
|
var lastPageLines = createLinesFromRectangle(r, lastPage.getRotation());
|
|
|
|
|
// remove top line
|
|
|
|
|
lastPageLines.remove(0);
|
|
|
|
|
// add string to left line
|
|
|
|
@@ -170,7 +203,7 @@ public class LayoutGridService {
|
|
|
|
|
|
|
|
|
|
List<ColoredLine> coloredLines = layoutGrid.getVisualizationsPerPages().get(firstPage.getNumber() - 1).getColoredLines();
|
|
|
|
|
Rectangle2D r = RectangleTransformations.pad(semanticNode.getBBox().get(firstPage), LINE_WIDTH, LINE_WIDTH);
|
|
|
|
|
var firstPageLines = createLinesFromRectangle(r);
|
|
|
|
|
var firstPageLines = createLinesFromRectangle(r, firstPage.getRotation());
|
|
|
|
|
// remove bottom line
|
|
|
|
|
firstPageLines.remove(2);
|
|
|
|
|
// add string to top line
|
|
|
|
@@ -196,8 +229,9 @@ public class LayoutGridService {
|
|
|
|
|
| |
|
|
|
|
|
D|__________________| C
|
|
|
|
|
The returned List are the lines [AB, BC, DC, AD]
|
|
|
|
|
The List is reordered, such that the order of the returned lines are always as viewed on the page.
|
|
|
|
|
*/
|
|
|
|
|
private List<Line2D> createLinesFromRectangle(Rectangle2D r) {
|
|
|
|
|
private List<Line2D> createLinesFromRectangle(Rectangle2D r, int pageRotation) {
|
|
|
|
|
// +0.5 to join the lines
|
|
|
|
|
List<Line2D> lines = new ArrayList<>(4);
|
|
|
|
|
float lineWidthCorrection = LINE_WIDTH * 0.5f;
|
|
|
|
@@ -213,7 +247,23 @@ public class LayoutGridService {
|
|
|
|
|
lines.add(new Line2D.Float(b, c));
|
|
|
|
|
lines.add(new Line2D.Float(d1, c1));
|
|
|
|
|
lines.add(new Line2D.Float(a, d));
|
|
|
|
|
return lines;
|
|
|
|
|
|
|
|
|
|
return switch (pageRotation) {
|
|
|
|
|
case 90 -> {
|
|
|
|
|
Collections.rotate(lines, 1);
|
|
|
|
|
yield lines;
|
|
|
|
|
}
|
|
|
|
|
case 180 -> {
|
|
|
|
|
Collections.rotate(lines, 2);
|
|
|
|
|
yield lines;
|
|
|
|
|
}
|
|
|
|
|
case 270 -> {
|
|
|
|
|
Collections.rotate(lines, 3);
|
|
|
|
|
yield lines;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default -> lines;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|