All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.formkiq.vision.crafter.SimpleDocumentBlockMaker Maven / Gradle / Ivy

/*
 * Copyright (C) 2018 FormKiQ Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.formkiq.vision.crafter;

import static com.formkiq.vision.document.DocumentBlock.isEquals;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.lang3.Range;

import com.formkiq.vision.comparator.DocumentBlockRectangleComparator;
import com.formkiq.vision.document.DocumentBlock;
import com.formkiq.vision.document.DocumentBlockRectangle;
import com.formkiq.vision.predicate.DocumentBlockHorizontalLinePredicate;

/**
 * Basic {@link DocumentBlock} maker. Given Horizontal / Vertical lines, make
 * square boxes.
 *
 */
public class SimpleDocumentBlockMaker
        implements Function> {

    /** {@link Collection} {@link DocumentBlock}. */
    private Collection horizontal;
    /** {@link Collection} {@link DocumentBlock}. */
    private Collection vertical;

    /**
     * constructor.
     * @param horizontalLines {@link Collection} {@link DocumentBlock}
     * @param verticalLines {@link Collection} {@link DocumentBlock}
     */
    public SimpleDocumentBlockMaker(
            final Collection horizontalLines,
            final Collection verticalLines) {
        this.horizontal = horizontalLines;
        this.vertical = verticalLines;
    }

    @Override
    public List apply(final DocumentBlockRectangle block) {

        List o = new ArrayList<>();

        if (new DocumentBlockHorizontalLinePredicate().test(block)) {

            List bottomBlocks = findBottomBlock(
                    block.getLowerLeftX(), block.getLowerLeftY(),
                    block.getUpperRightX(), block.getUpperRightY());

            for (DocumentBlockRectangle bottom : bottomBlocks) {

                Optional left = findLeftBlock(
                        block.getLowerLeftX(), bottom.getLowerLeftY(),
                        block.getUpperRightX(), block.getUpperRightY());

                Optional right = findRightBlock(
                        block.getLowerLeftX(), bottom.getLowerLeftY(),
                        block.getUpperRightX(), block.getUpperRightY());

                if (left.isPresent() && right.isPresent()
                        && !left.get().equals(right.get())) {

                    o.add(new DocumentBlock(left.get().getLowerLeftX(),
                            bottom.getLowerLeftY(),
                            right.get().getUpperRightX(),
                            block.getUpperRightY()));
                }
            }

        } else {

        	DocumentBlockRectangle left = block;

            Optional top = findHorizontalLine(
                    Float.valueOf(left.getLowerLeftX()),
                    Float.valueOf(left.getUpperRightY()));

            Optional bottom = findHorizontalLine(
                    Float.valueOf(left.getLowerLeftX()),
                    Float.valueOf(left.getLowerLeftY()));

            if (top.isPresent() && bottom.isPresent()) {
                Optional right = findVerticalLine(
                        Float.valueOf(top.get().getUpperRightX()),
                        Float.valueOf(top.get().getLowerLeftY()),
                        Float.valueOf(bottom.get().getUpperRightY()));

                if (right.isPresent() && !left.equals(right.get())) {

                    o.add(new DocumentBlock(left.getLowerLeftX(),
                            bottom.get().getLowerLeftY(),
                            right.get().getUpperRightX(),
                            top.get().getUpperRightY()));
                }
            }
        }

        return o;
    }

    /**
     * Find Horizontal Line.
     * @param x {@link Float}
     * @param y {@link Float}
     * @return {@link Optional} {@link DocumentBlock}
     */
    private Optional findHorizontalLine(final Float x,
            final Float y) {
        Optional line = this.horizontal.stream().filter(h -> {
            return h.toRangeX(2).contains(x) && h.toRangeY(2).contains(y);
        }).max(new DocumentBlockRectangleComparator());

        return line;
    }

    /**
     * Find Horizontal Line.
     * @param x {@link Float}
     * @param y0 {@link Float}
     * @param y1 {@link Float}
     * @return {@link Optional} {@link DocumentBlock}
     */
    private Optional findVerticalLine(final Float x,
            final Float y0, final Float y1) {
        Optional line = this.vertical.stream().filter(v -> {
            return v.toRangeX(2).contains(x) && v.toRangeY(2).contains(y0)
                    && v.toRangeY(2).contains(y1);
        }).max(new DocumentBlockRectangleComparator());

        return line;
    }

    /**
     * Find Left Block.
     * @param lowerLeftX float
     * @param lowerLeftY float
     * @param upperRightX float
     * @param upperRightY float
     * @return {@link Optional} {@link DocumentBlockRectangle}
     */
    private Optional findLeftBlock(final float lowerLeftX,
            final float lowerLeftY, final float upperRightX,
            final float upperRightY) {

        Range yr = Range.between(Float.valueOf(lowerLeftY + 2),
                Float.valueOf(upperRightY - 2));

        Optional left = this.vertical.stream().filter(v -> {
            return isEquals(v.getLowerLeftX(), lowerLeftX)
                    && (v.toRangeY().containsRange(yr))
                    && (v.toRangeY().containsRange(yr));
        }).min(new DocumentBlockRectangleComparator());

        return left;
    }

    /**
     * Find Right Block.
     * @param lowerLeftX float
     * @param lowerLeftY float
     * @param upperRightX float
     * @param upperRightY float
     * @return {@link Optional} {@link DocumentBlock}
     */
    private Optional findRightBlock(final float lowerLeftX,
            final float lowerLeftY, final float upperRightX,
            final float upperRightY) {

        Range yr = Range.between(Float.valueOf(lowerLeftY + 2),
                Float.valueOf(upperRightY - 2));

        Optional left = this.vertical.stream().filter(v -> {
            return isEquals(v.getUpperRightX(), upperRightX)
                    && (v.toRangeY().containsRange(yr))
                    && (v.toRangeY().containsRange(yr));
        }).max(new DocumentBlockRectangleComparator());

        return left;
    }

    /**
     * Find Bottom Block.
     * @param lowerLeftX float
     * @param lowerLeftY float
     * @param upperRightX float
     * @param upperRightY float
     * @return {@link List} {@link DocumentBlock}
     */
    private List findBottomBlock(final float lowerLeftX,
            final float lowerLeftY, final float upperRightX,
            final float upperRightY) {

        List bottom = this.horizontal.stream()
                .filter(h -> lowerLeftY > h.getUpperRightY()
                        && isEquals(h.getLowerLeftX(), lowerLeftX)
                        && isEquals(h.getUpperRightX(), upperRightX))
                .collect(Collectors.toList());

        return bottom;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy