com.zilbo.flamingSailor.TE.model.Component.java Source code

Java tutorial

Introduction

Here is the source code for com.zilbo.flamingSailor.TE.model.Component.java

Source

package com.zilbo.flamingSailor.TE.model;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import java.awt.geom.Rectangle2D;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/*
 * Copyright 2012 Zilbo.com
 *
 * 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.
 */
public abstract class Component implements Comparable<Component> {
    private static final Logger logger = Logger.getLogger(Component.class);
    Rectangle2D geom;
    Long id;
    List<Component> pieces;
    public static final int HIST_SPACE = 0;
    public static final int HIST_DIGIT = 1;
    public static final int HIST_UPPER = 2;
    public static final int HIST_LOWER = 3;
    public static final int HIST_PUNCT = 4;
    public static final int HIST_OTHER = 5;

    public String getText() {
        int end = this.getChildren().size();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < end; i++) {
            if (i != 0) {
                sb.append('\n');
            }
            sb.append(this.getChildren().get(i).getText());

        }
        return sb.toString();
    }

    public boolean isEmpty() {
        for (Component c : pieces) {
            if (!c.isEmpty()) {
                return false;
            }
        }
        return true;
    }

    public boolean hasChildren() {
        return this.pieces.size() > 0;
    }

    // TODO make this shallow!
    public List<Component> getChildren() {
        List<Component> c = new ArrayList<>();
        c.addAll(pieces);
        return c;
    }

    /**
     * remove a child component.
     * this makes no effort to fix up geographic boundaries, and will fail silently if it doesn't exist.
     * this also doesn't do a depth-wide search for the component.
     *
     * @param c the child to remove
     */
    public void removeChild(Component c) {
        this.pieces.remove(c);
        adjustGeom();
    }

    /**
     * recalculate the geometery of the piece, based on the children of it.
     */
    protected void adjustGeom() {
        geom = new Rectangle2D.Double();
        if (pieces.size() > 0) {
            geom = pieces.get(0).getGeom().getBounds2D();
            for (int i = 1; i < pieces.size(); i++) {
                geom = geom.createUnion(pieces.get(i).getGeom());
            }
        }
    }

    public int size() {
        return this.getChildren().size();
    }

    public Long getID() {
        return this.id;
    }

    protected Component(Long id) {
        this.id = id;
        this.geom = new Rectangle2D.Double();
        pieces = new ArrayList<>();
    }

    public void addChild(Component child) {

        if (pieces.size() == 0) {
            Rectangle2D childRect = child.getGeom();
            geom = new Rectangle2D.Double();
            geom.setRect(childRect);
            //  geom = new Rectangle2D.Double(childRect.getMinX(), childRect.getMinY(), childRect.getMaxX(), childRect.getMaxY());
        } else {
            expandBoundry(child.getGeom());
        }
        pieces.add(child);

    }

    public void addChildAtTop(Component child) {
        if (pieces.size() == 0) {
            Rectangle2D childRect = child.getGeom();
            geom = new Rectangle2D.Double();
            geom.setRect(childRect);
            // geom = new Rectangle2D.Double(childRect.getMinX(), childRect.getMinY(), childRect.getMaxX(), childRect.getMaxY());
        } else {
            expandBoundry(child.getGeom());
        }
        pieces.add(0, child);

    }

    public void merge(Component mergeThis) {
        expandBoundry(mergeThis.getGeom());

        for (Component tl : mergeThis.getChildren()) {
            this.addChild(tl);
        }
    }

    public Rectangle2D getGeom() {
        return this.geom;
    }

    /**
     * @return distance between 2 X points (the width)
     */
    public double width() {
        return getGeom().getWidth();
    }

    /**
     * @return height of the component
     */

    public double height() {
        return getGeom().getHeight();

    }

    @Override
    /**
     * j
     * Sorts text pieces by position by comparing the location of this text piece
     *  with a given text piece t
     * @param t
     *       the text piece to compare with
     * @return
     *       the comparison result
     *            -1: this text piece is located in the left-side or the top of another text piece t
     *             1: this text piece is located in the right-side or the below of another text piece t
     *             0: this text piece is located in the same location as another text piece t
     */
    public int compareTo(Component t) {
        //   Line2D g1 = this.getGeom();
        //  Line2D g2 = t.getGeom();
        // int ret;
        /*
        if (g1.getP1() == g2.getP1() && g1.getP2() == g2.getP2()) {
        ret = 0;
        //   logger.info(ret + "\t" + GeomUtil.getRectangleDebug(g1) + "\t" + GeomUtil.getRectangleDebug(g2));
        return ret;
        }
        */

        if (onSameLine(t)) {
            //ret = new Long(Math.round(y1 / 10)).compareTo(Math.round(y2 / 10));
            //if (ret == 0) {
            //if ( Math.abs(y1-y2) <2) {
            Double x1 = getGeom().getMinX();
            return x1.compareTo(t.getGeom().getMinX());

        } else {
            Double y1 = getGeom().getMinY();
            // double y2 = g2.getY1();

            return y1.compareTo(t.getGeom().getMinY());
        }
    }

    public static class left_comparator implements Comparator<Component> {

        public int compare(Component t1, Component t2) {

            double result = t1.getGeom().getMinX() - t2.getGeom().getMaxX();

            if (result > 0) {
                return 1;
            }
            if (result < 0) {
                return -1;
            }
            return 0;
        }
    }

    public static class top_comparator implements Comparator<Component> {

        public int compare(Component t1, Component t2) {
            if (t1.onSameLine(t2)) {
                return 0;
            }
            double result = t1.getGeom().getMinY() - t2.getGeom().getMaxY();

            if (result > 0) {
                return 1;
            }
            if (result < 0) {
                return -1;
            }
            return 0;
        }
    }

    public static class topleft_comparator implements Comparator<Component> {

        public int compare(Component t1, Component t2) {
            return t1.compareTo(t2);
        }
    }

    public String getRectangleDebug() {
        return GeomUtil.getRectangleDebug(geom);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(this.getClass().getSimpleName() + "{" + getRectangleDebug() + "\n");
        for (Component p : getChildren()) {
            sb.append("\t\t").append(p.toString()).append("\n");
        }
        sb.append("}");
        return sb.toString();
    }

    public double density() {
        double density = 0.0;
        for (Component c : getChildren()) {

            density += c.density();
        }
        return density / (1.0 * getChildren().size());
    }

    public void expandBoundry(Rectangle2D geom2) {

        geom = geom.createUnion(geom2);
        /*
        Point2D point1;
        Point2D point2;
        double x;
        double y;
            
        if (geom.getX1() > geom2.getX1()) {
        x = geom2.getX1();
        } else {
        x = geom.getX1();
        }
        if (geom.getY1() > geom2.getY1()) {
        y = geom2.getY1();
        } else {
        y = geom.getY1();
        }
        point1 = new Point2D.Double(x, y);
            
        if (geom.getX2() < geom2.getX2()) {
        x = geom2.getX2();
        } else {
        x = geom.getX2();
        }
        if (geom.getY2() < geom2.getY2()) {
        y = geom2.getY2();
        } else {
        y = geom.getY2();
        }
        point2 = new Point2D.Double(x, y);
        return new Rectangle2D.Double(point1, point2);
        */
    }

    /**
     * Is 'l2' inside of 'l1'
     *
     * @param l1 box1
     * @return true if this component is inside the box
     */
    public boolean isContainedBy(Rectangle2D l1) {

        return l1.contains(geom);
        /*
        if (l1.getX1() <= geom.getX1() && l1.getX2() >= geom.getX2()) {
        if (l1.getY1() <= geom.getY1() && l1.getY2() >= geom.getY2()) {
            return true;
        }
        }
        return false;
        */

    }

    public List<Component> findByGeom(Rectangle2D box) {
        List<Component> ret = new ArrayList<>();
        if (isContainedBy(box)) {
            ret.add(this);
            return ret;
        }
        for (Component c : getChildren()) {
            ret.addAll(c.findByGeom(box));
        }
        return ret;
    }

    /**
     * if the bottom of the lines rectangle is lower than the textpiece's top, then it belongs here
     *
     * @param c the piece to compare against
     * @return true if they are
     */

    public boolean onSameLine(Component c) {

        return onSameLine(c.getGeom());
    }

    public boolean onSameLine(Rectangle2D otherGeom) {

        Double y1 = this.geom.getMinY();
        Double y3 = this.geom.getMaxY();
        Double y2 = otherGeom.getMinY();
        Double y4 = otherGeom.getMaxY();

        // we have some kind of crossover.
        if (y1 <= y4 && y1 >= y2) {
            // AND the boxes are touching
            if (Math.abs(this.geom.getMinX() - otherGeom.getMaxX()) < 0.5
                    || (this.geom.getMaxX() - otherGeom.getMinX()) < 0.5) {
                // assume it's a super/subscript letter and call it the same line.
                return true;
            }

        }
        // we have some kind of crossover.
        if (y2 <= y3 && y2 >= y1) {
            // AND the boxes are touching
            //   logger.info(this.geom.getMinX() - otherGeom.getMaxX());
            if (Math.abs(this.geom.getMinX() - otherGeom.getMaxX()) < 0.5
                    || (this.geom.getMaxX() - otherGeom.getMinX()) < 0.5) {
                // assume it's a super/subscript letter and call it the same line.
                return true;
            }

        }
        double yAveT = (y2 + y4) / 2;
        //   double diff = (y4-y2)/4;
        if ((y1 <= (yAveT)) && ((yAveT) < y3)) {
            return true;
        }
        yAveT = (y1 + y3) / 2;
        return (y2 <= yAveT) && (yAveT < y4);

    }

    public void dumpChildren(PrintStream out, int level) {

        StringBuilder sb = new StringBuilder();

        sb.append(StringUtils.repeat("..", level));
        sb.append(getClass().getSimpleName());
        if (sb.length() < 20) {
            sb.append(StringUtils.repeat(' ', 20 - sb.length()));
        }
        sb.append('\t');
        sb.append(getRectangleDebug()).append(" \t");
        //  sb.append(getText().replace("\n", "\n" + StringUtils.repeat(' ', 43)));
        String text;
        if (sb.length() > 256) {
            text = sb.substring(0, 256 - 4) + " ...";
        } else {
            text = sb.toString();
        }
        out.println(text);
        for (Component component : getChildren()) {
            component.dumpChildren(out, level + 1);
        }
    }

    boolean isHeading = false;

    public boolean isHeading() {
        return this.isHeading;
    }

    public void setIsHeading(boolean flag) {
        isHeading = flag;
    }

    public boolean isMultiLine() {
        return false;
    }

    public long[] getHistogram() {
        long[] histogram = new long[HIST_OTHER + 1];
        for (int i = 0; i < histogram.length; i++) {
            histogram[i] = 0L;
        }
        for (Component c : this.getChildren()) {
            long[] histC = c.getHistogram();
            for (int i = 0; i < histogram.length; i++) {
                histogram[i] += histC[i];
            }
        }
        return histogram;
    }

    public Double[] getNormalizedHistogram() {
        return getNormalizedHistogram(this.getHistogram());
    }

    public static Double[] getNormalizedHistogram(long[] histogram) {
        double total = 0.0;
        for (long aHistogram : histogram) {
            total += aHistogram;
        }
        Double[] normalized = new Double[histogram.length];
        for (int i = 0; i < histogram.length; i++) {
            normalized[i] = (1.0) * histogram[i] / total;
        }
        return normalized;
    }

    public long[] mergeHistogram(long[] hist) {
        if (hist == null) {
            return getHistogram();
        }
        return mergeHistogram(getHistogram(), hist);
    }

    public static long[] mergeHistogram(long[] hist1, long[] hist2) {
        if (hist2 == null) {
            return hist1;
        }
        if (hist1 == null) {
            return hist2;
        }
        long result[] = new long[hist1.length];
        for (int i = 0; i < hist1.length; i++) {
            result[i] = hist1[i] + hist2[i];
        }
        return result;
    }

    public String normHistoGramToString() {
        return normHistoGramToString(getNormalizedHistogram());
    }

    public static String normHistoGramToString(Double[] nHist) {

        return (String.format("Hist: UC:%4.2f LC:%4.2f DI:%4.2f SP:%4.2f PU:%4.2f O:%4.2f", nHist[HIST_UPPER],
                nHist[HIST_LOWER], nHist[HIST_DIGIT], nHist[HIST_SPACE], nHist[HIST_PUNCT], nHist[HIST_OTHER]));
    }
}