RED-6369: Rules Refactor
*fixed DocumentData Mapping
This commit is contained in:
parent
1fd483a6d4
commit
d9c27d70d1
@ -11,11 +11,14 @@ import lombok.experimental.FieldDefaults;
|
||||
@AllArgsConstructor
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class AtomicTextBlockData {
|
||||
|
||||
Long id;
|
||||
Long page;
|
||||
String searchText;
|
||||
int start;
|
||||
int end;
|
||||
int[] lineBreaks;
|
||||
int[] stringIdxToPositionIdx;
|
||||
float[][] positions;
|
||||
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@ import static java.lang.String.format;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.management.openmbean.InvalidKeyException;
|
||||
|
||||
@ -26,7 +28,6 @@ public class TableOfContentsData {
|
||||
|
||||
public EntryData get(List<Integer> tocId) {
|
||||
|
||||
|
||||
if (tocId.size() < 1) {
|
||||
throw new InvalidKeyException(format("Section Identifier: \"%s\" is not valid.", tocId));
|
||||
}
|
||||
@ -38,14 +39,51 @@ public class TableOfContentsData {
|
||||
}
|
||||
|
||||
|
||||
public Stream<EntryData> streamAllEntries() {
|
||||
|
||||
return entries.stream().flatMap(TableOfContentsData::flatten);
|
||||
}
|
||||
|
||||
|
||||
private static List<Integer> getIds(String idsAsString) {
|
||||
|
||||
return Arrays.stream(idsAsString.split("\\.")).map(Integer::valueOf).toList();
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
|
||||
return String.join("\n", streamAllEntries().map(EntryData::toString).toList());
|
||||
}
|
||||
|
||||
|
||||
private static Stream<EntryData> flatten(EntryData entry) {
|
||||
|
||||
return Stream.concat(Stream.of(entry), entry.subEntries().stream().flatMap(TableOfContentsData::flatten));
|
||||
}
|
||||
|
||||
|
||||
@Builder
|
||||
public record EntryData(int[] tocId, List<EntryData> subEntries, NodeType type, Long[] atomicTextBlocks, Long[] pages, int numberOnPage) {
|
||||
public record EntryData(int[] tocId, List<EntryData> subEntries, NodeType type, Long[] atomicTextBlocks, Long[] pages, int numberOnPage, Map<String, String> properties) {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[");
|
||||
for (int i : tocId) {
|
||||
sb.append(i);
|
||||
sb.append(",");
|
||||
}
|
||||
sb.delete(sb.length() - 1, sb.length());
|
||||
sb.append("]: ");
|
||||
|
||||
sb.append(type);
|
||||
sb.append(" atbs = ");
|
||||
sb.append(atomicTextBlocks.length);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
package com.iqser.red.service.redaction.v1.server.document.data.mapper;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -11,7 +13,11 @@ import com.iqser.red.service.redaction.v1.server.document.data.PageData;
|
||||
import com.iqser.red.service.redaction.v1.server.document.data.TableOfContentsData;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.DocumentGraph;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.TableOfContents;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.entity.ImageNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.factory.RectangleTransformations;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.PageNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.TableCellNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.TableNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.textblock.AtomicTextBlock;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.textblock.TextBlock;
|
||||
|
||||
@ -40,23 +46,68 @@ public class DocumentDataMapper {
|
||||
private TableOfContentsData.EntryData toEntryData(TableOfContents.Entry entry) {
|
||||
|
||||
Long[] atomicTextBlocks;
|
||||
|
||||
if (entry.node().isTerminal()) {
|
||||
atomicTextBlocks = toAtomicTextBlockIds(entry.node().getTerminalTextBlock());
|
||||
} else {
|
||||
atomicTextBlocks = new Long[]{-1L};
|
||||
atomicTextBlocks = new Long[]{};
|
||||
}
|
||||
|
||||
Map<String, String> properties = switch (entry.type()) {
|
||||
case TABLE -> buildTableProperties((TableNode) entry.node());
|
||||
case TABLE_CELL -> buildTableCellProperties((TableCellNode) entry.node());
|
||||
case IMAGE -> buildImageProperties((ImageNode) entry.node());
|
||||
default -> new HashMap<>();
|
||||
};
|
||||
|
||||
return TableOfContentsData.EntryData.builder()
|
||||
.tocId(toPrimitiveIntArray(entry.tocId()))
|
||||
.subEntries(entry.children().stream().map(this::toEntryData).toList())
|
||||
.type(entry.type())
|
||||
.atomicTextBlocks(atomicTextBlocks)
|
||||
.pages(entry.node().getPages().stream().map(PageNode::getNumber).toArray(Long[]::new))
|
||||
.pages(entry.node().getPages().stream().map(PageNode::getNumber).map(Integer::longValue).toArray(Long[]::new))
|
||||
.numberOnPage(entry.node().getNumberOnPage())
|
||||
.properties(properties)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private Map<String, String> buildImageProperties(ImageNode image) {
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("imageType", image.getImageType().toString());
|
||||
properties.put("transparency", String.valueOf(image.isTransparency()));
|
||||
properties.put("position", RectangleTransformations.toString(image.getPosition()));
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
private Map<String, String> buildTableCellProperties(TableCellNode tableCell) {
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("row", String.valueOf(tableCell.getRow()));
|
||||
properties.put("col", String.valueOf(tableCell.getCol()));
|
||||
properties.put("header", String.valueOf(tableCell.isHeader()));
|
||||
|
||||
if (tableCell.getPages().size() > 1 || tableCell.getBBox().keySet().size() > 1) {
|
||||
throw new IllegalArgumentException("TableCell can only occur on a single page!");
|
||||
}
|
||||
String bBoxString = RectangleTransformations.toString(tableCell.getBBox().get(tableCell.getPages().stream().findFirst().get()));
|
||||
properties.put("bBox", bBoxString);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
private Map<String, String> buildTableProperties(TableNode table) {
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("numberOfRows", String.valueOf(table.getNumberOfRows()));
|
||||
properties.put("numberOfCols", String.valueOf(table.getNumberOfCols()));
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
private Long[] toAtomicTextBlockIds(TextBlock textBlock) {
|
||||
|
||||
return textBlock.getAtomicTextBlocks().stream().map(AtomicTextBlock::getId).toArray(Long[]::new);
|
||||
@ -65,11 +116,7 @@ public class DocumentDataMapper {
|
||||
|
||||
private PageData toPageData(PageNode pageNode) {
|
||||
|
||||
return PageData.builder()
|
||||
.height(pageNode.getHeight())
|
||||
.width(pageNode.getWidth())
|
||||
.number(pageNode.getNumber())
|
||||
.build();
|
||||
return PageData.builder().height(pageNode.getHeight()).width(pageNode.getWidth()).number(pageNode.getNumber()).build();
|
||||
}
|
||||
|
||||
|
||||
@ -77,6 +124,7 @@ public class DocumentDataMapper {
|
||||
|
||||
return AtomicTextBlockData.builder()
|
||||
.id(atomicTextBlock.getId())
|
||||
.page(atomicTextBlock.getPage().getNumber().longValue())
|
||||
.searchText(atomicTextBlock.getSearchText())
|
||||
.start(atomicTextBlock.getBoundary().start())
|
||||
.end(atomicTextBlock.getBoundary().end())
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
package com.iqser.red.service.redaction.v1.server.document.data.mapper;
|
||||
|
||||
import static com.iqser.red.service.redaction.v1.server.document.graph.factory.RectangleTransformations.parseRectangle2D;
|
||||
import static java.lang.Math.toIntExact;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -23,15 +22,22 @@ import com.iqser.red.service.redaction.v1.server.document.data.TableOfContentsDa
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.Boundary;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.DocumentGraph;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.TableOfContents;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.entity.ImageNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.FooterNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.HeaderNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.HeadlineNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.NodeType;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.PageNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.ParagraphNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.SectionNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.SemanticNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.TableCellNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.nodes.TableNode;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.textblock.AtomicTextBlock;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.textblock.TextBlock;
|
||||
import com.iqser.red.service.redaction.v1.server.document.graph.textblock.TextBlockCollector;
|
||||
import com.iqser.red.service.redaction.v1.server.exception.NotFoundException;
|
||||
import com.iqser.red.service.redaction.v1.server.redaction.model.ImageType;
|
||||
|
||||
@Service
|
||||
public class DocumentGraphMapper {
|
||||
@ -42,7 +48,7 @@ public class DocumentGraphMapper {
|
||||
|
||||
context.pages.addAll(documentData.getPages().stream().map(this::buildPage).toList());
|
||||
|
||||
buildNodesFromTableOfContents(Collections.emptyList(), context);
|
||||
context.tableOfContents.setEntries(buildEntries(documentData.getTableOfContents().getEntries(), context));
|
||||
|
||||
DocumentGraph documentGraph = DocumentGraph.builder()
|
||||
.numberOfPages(documentData.getPages().size())
|
||||
@ -54,67 +60,127 @@ public class DocumentGraphMapper {
|
||||
}
|
||||
|
||||
|
||||
private void buildNodesFromTableOfContents(List<Integer> currentTocId, Context context) {
|
||||
private List<TableOfContents.Entry> buildEntries(List<TableOfContentsData.EntryData> entries, Context context) {
|
||||
|
||||
List<TableOfContentsData.EntryData> entries;
|
||||
if (currentTocId.size() == 0) {
|
||||
entries = context.documentData().getTableOfContents().getEntries();
|
||||
} else {
|
||||
entries = context.documentData().getTableOfContents().get(currentTocId).subEntries();
|
||||
}
|
||||
List<TableOfContents.Entry> newEntries = new LinkedList<>();
|
||||
for (TableOfContentsData.EntryData entryData : entries) {
|
||||
|
||||
switch (entryData.type()) {
|
||||
case SECTION -> buildSection(entryData, currentTocId, context);
|
||||
case PARAGRAPH -> buildParagraph(entryData, currentTocId, context);
|
||||
boolean terminal = isTerminal(entryData);
|
||||
List<PageNode> pages = Arrays.stream(entryData.pages()).map(pageNumber -> getPage(pageNumber, context)).toList();
|
||||
|
||||
SemanticNode node = switch (entryData.type()) {
|
||||
case SECTION -> buildSection(context);
|
||||
case PARAGRAPH -> buildParagraph(context, terminal);
|
||||
case HEADLINE -> buildHeadline(context, terminal);
|
||||
case HEADER -> buildHeader(context, terminal);
|
||||
case FOOTER -> buildFooter(context, terminal);
|
||||
case TABLE -> buildTable(context, entryData.properties());
|
||||
case TABLE_CELL -> buildTableCell(context, entryData.properties(), terminal);
|
||||
case IMAGE -> buildImage(context, entryData.properties());
|
||||
default -> throw new NotImplementedException("Not yet implemented for type " + entryData.type());
|
||||
};
|
||||
|
||||
if (node.isTerminal()) {
|
||||
TextBlock textBlock = toTextBlock(entryData.atomicTextBlocks(), context, node);
|
||||
node.setTerminalTextBlock(textBlock);
|
||||
}
|
||||
List<Integer> tocId = Arrays.stream(entryData.tocId()).boxed().toList();
|
||||
node.setTocId(tocId);
|
||||
|
||||
if (entryData.type() == NodeType.HEADER) {
|
||||
pages.forEach(page -> page.setHeader((HeaderNode) node));
|
||||
} else if (entryData.type() == NodeType.FOOTER) {
|
||||
pages.forEach(page -> page.setFooter((FooterNode) node));
|
||||
} else {
|
||||
pages.forEach(page -> page.getMainBody().add(node));
|
||||
}
|
||||
newEntries.add(TableOfContents.Entry.builder().tocId(tocId).type(entryData.type()).children(buildEntries(entryData.subEntries(), context)).node(node).build());
|
||||
}
|
||||
return newEntries;
|
||||
}
|
||||
|
||||
|
||||
private void buildSection(TableOfContentsData.EntryData entryData, List<Integer> currentTocId, Context context) {
|
||||
private HeadlineNode buildHeadline(Context context, boolean terminal) {
|
||||
|
||||
SectionNode section = SectionNode.builder().entities(new HashSet<>()).tableOfContents(context.tableOfContents()).build();
|
||||
|
||||
context.sections().add(section);
|
||||
|
||||
List<PageNode> pages = Arrays.stream(entryData.pages()).map(pageNumber -> getPage(pageNumber, context)).toList();
|
||||
pages.forEach(page -> page.getMainBody().add(section));
|
||||
section.getPages().addAll(pages);
|
||||
|
||||
List<Integer> sectionId = context.tableOfContents.createNewChildEntryAndReturnId(currentTocId, NodeType.SECTION, section);
|
||||
section.setTocId(sectionId);
|
||||
buildNodesFromTableOfContents(sectionId, context);
|
||||
return HeadlineNode.builder().terminal(terminal).tableOfContents(context.tableOfContents()).build();
|
||||
}
|
||||
|
||||
|
||||
private void buildParagraph(TableOfContentsData.EntryData entryData, List<Integer> currentTocId, Context context) {
|
||||
private static boolean isTerminal(TableOfContentsData.EntryData entryData) {
|
||||
|
||||
Set<PageNode> pages = Arrays.stream(entryData.pages()).map(pageNumber -> getPage(pageNumber, context)).collect(Collectors.toSet());
|
||||
return entryData.atomicTextBlocks().length > 0;
|
||||
}
|
||||
|
||||
SectionNode parentSection = (SectionNode) context.tableOfContents().getEntryById(currentTocId).node();
|
||||
ParagraphNode paragraph = ParagraphNode.builder().build();
|
||||
TextBlock textBlock = toTextBlock(entryData.atomicTextBlocks(), context, paragraph);
|
||||
|
||||
paragraph.setTerminalTextBlock(textBlock);
|
||||
private ImageNode buildImage(Context context, Map<String, String> properties) {
|
||||
|
||||
pages.forEach(page -> page.getMainBody().add(paragraph));
|
||||
for (PageNode page : pages) {
|
||||
if (!parentSection.getPages().contains(page)) {
|
||||
parentSection.getPages().add(page);
|
||||
}
|
||||
}
|
||||
ImageType imageType = parseImageType(properties.get("imageType"));
|
||||
boolean transparency = Boolean.parseBoolean(properties.get("transparency"));
|
||||
Rectangle2D position = parseRectangle2D(properties.get("position"));
|
||||
|
||||
List<Integer> tocId = context.tableOfContents.createNewChildEntryAndReturnId(currentTocId, NodeType.PARAGRAPH, paragraph);
|
||||
paragraph.setTocId(tocId);
|
||||
return ImageNode.builder().tableOfContents(context.tableOfContents()).imageType(imageType).transparency(transparency).position(position).build();
|
||||
}
|
||||
|
||||
|
||||
private TableCellNode buildTableCell(Context context, Map<String, String> properties, boolean terminal) {
|
||||
|
||||
int row = Integer.parseInt(properties.get("row"));
|
||||
int col = Integer.parseInt(properties.get("col"));
|
||||
boolean header = Boolean.parseBoolean(properties.get("header"));
|
||||
Rectangle2D bBox = parseRectangle2D(properties.get("bBox"));
|
||||
return TableCellNode.builder().terminal(terminal).bBox(bBox).header(header).col(col).row(row).tableOfContents(context.tableOfContents()).build();
|
||||
}
|
||||
|
||||
|
||||
private TableNode buildTable(Context context, Map<String, String> properties) {
|
||||
|
||||
int numberOfRows = Integer.parseInt(properties.get("numberOfRows"));
|
||||
int numberOfCols = Integer.parseInt(properties.get("numberOfCols"));
|
||||
return TableNode.builder().tableOfContents(context.tableOfContents()).numberOfRows(numberOfRows).numberOfCols(numberOfCols).build();
|
||||
}
|
||||
|
||||
|
||||
private FooterNode buildFooter(Context context, boolean terminal) {
|
||||
|
||||
return FooterNode.builder().terminal(terminal).tableOfContents(context.tableOfContents()).build();
|
||||
}
|
||||
|
||||
|
||||
private HeaderNode buildHeader(Context context, boolean terminal) {
|
||||
|
||||
return HeaderNode.builder().terminal(terminal).tableOfContents(context.tableOfContents()).build();
|
||||
}
|
||||
|
||||
|
||||
private SectionNode buildSection(Context context) {
|
||||
|
||||
return SectionNode.builder().tableOfContents(context.tableOfContents()).build();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private ParagraphNode buildParagraph(Context context, boolean terminal) {
|
||||
|
||||
return ParagraphNode.builder().terminal(terminal).tableOfContents(context.tableOfContents()).build();
|
||||
}
|
||||
|
||||
|
||||
private static ImageType parseImageType(String imageType) {
|
||||
|
||||
return switch (imageType) {
|
||||
case "LOGO" -> ImageType.LOGO;
|
||||
case "FORMULA" -> ImageType.FORMULA;
|
||||
case "SIGNATURE" -> ImageType.SIGNATURE;
|
||||
case "OCR" -> ImageType.OCR;
|
||||
default -> ImageType.OTHER;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private TextBlock toTextBlock(Long[] atomicTextBlockIds, Context context, SemanticNode parent) {
|
||||
|
||||
return Arrays.stream(atomicTextBlockIds)
|
||||
.map(atomicTextBlockId -> toAtomicTextBlock(context.atomicTextBlockData.get(toIntExact(atomicTextBlockId)), parent))
|
||||
.map(atomicTextBlockId -> toAtomicTextBlock(context.atomicTextBlockData.get(toIntExact(atomicTextBlockId)), parent, context))
|
||||
.collect(new TextBlockCollector());
|
||||
}
|
||||
|
||||
@ -125,10 +191,11 @@ public class DocumentGraphMapper {
|
||||
}
|
||||
|
||||
|
||||
private AtomicTextBlock toAtomicTextBlock(AtomicTextBlockData atomicTextBlockData, SemanticNode parent) {
|
||||
private AtomicTextBlock toAtomicTextBlock(AtomicTextBlockData atomicTextBlockData, SemanticNode parent, Context context) {
|
||||
|
||||
return AtomicTextBlock.builder()
|
||||
.id(atomicTextBlockData.getId())
|
||||
.page(getPage(atomicTextBlockData.getPage(), context))
|
||||
.searchText(atomicTextBlockData.getSearchText())
|
||||
.boundary(new Boundary(atomicTextBlockData.getStart(), atomicTextBlockData.getEnd()))
|
||||
.lineBreaks(Ints.asList(atomicTextBlockData.getLineBreaks()))
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
package com.iqser.red.service.redaction.v1.server.document.data.mapper;public class PropertiesMapper {
|
||||
}
|
||||
@ -1,7 +1,10 @@
|
||||
package com.iqser.red.service.redaction.v1.server.document.graph.factory;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
@ -60,6 +63,19 @@ public class RectangleTransformations {
|
||||
}
|
||||
|
||||
|
||||
public static String toString(Rectangle2D rectangle2D) {
|
||||
|
||||
return format("%f,%f,%f,%f", rectangle2D.getX(), rectangle2D.getY(), rectangle2D.getWidth(), rectangle2D.getHeight());
|
||||
}
|
||||
|
||||
|
||||
public static Rectangle2D parseRectangle2D(String bBox) {
|
||||
|
||||
List<Float> floats = Arrays.stream(bBox.split(",")).map(Float::parseFloat).toList();
|
||||
return new Rectangle2D.Float(floats.get(0), floats.get(1), floats.get(2), floats.get(3));
|
||||
}
|
||||
|
||||
|
||||
private static class Rectangle2DUnion implements Collector<Rectangle2D, Area, Rectangle2D> {
|
||||
|
||||
@Override
|
||||
|
||||
@ -21,7 +21,6 @@ public class TextBlockFactory {
|
||||
|
||||
stringOffset = new AtomicInteger();
|
||||
textBlockIdx = new AtomicLong();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -64,7 +63,7 @@ public class TextBlockFactory {
|
||||
public AtomicTextBlock emptyTextBlock(SemanticNode parent, Integer numberOnPage, PageNode page) {
|
||||
|
||||
return AtomicTextBlock.builder()
|
||||
.id(textBlockIdx.get())
|
||||
.id(textBlockIdx.getAndIncrement())
|
||||
.boundary(new Boundary(stringOffset.get(), stringOffset.get()))
|
||||
.searchText("")
|
||||
.lineBreaks(Collections.emptyList())
|
||||
|
||||
@ -126,6 +126,12 @@ public interface SemanticNode {
|
||||
}
|
||||
|
||||
|
||||
default void setTerminalTextBlock(TextBlock textBlock) {
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Each AtomicTextBlock has an index on its page, this returns the number of the first AtomicTextBlock underneath this node.
|
||||
* If this node does not have any AtomicTexBlocks underneath it, e.g. an empty TableCell. It returns -1.
|
||||
|
||||
@ -48,7 +48,7 @@ public class ConcatenatedTextBlock implements TextBlock {
|
||||
boundary.setStart(textBlock.getBoundary().start());
|
||||
boundary.setEnd(textBlock.getBoundary().end());
|
||||
} else if (boundary.end() != textBlock.getBoundary().start()) {
|
||||
throw new UnsupportedOperationException(format("Can only concat consecutive TextBlocks, trying to concat %s to %s", textBlock.getBoundary(), boundary));
|
||||
throw new UnsupportedOperationException(format("Can only concat consecutive TextBlocks, trying to concat %s and %s", boundary, textBlock.getBoundary()));
|
||||
}
|
||||
this.atomicTextBlocks.addAll(textBlock.getAtomicTextBlocks());
|
||||
boundary.setEnd(textBlock.getBoundary().end());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user