com.joliciel.jochre.boundaries.SplitCandidateFinderImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.joliciel.jochre.boundaries.SplitCandidateFinderImpl.java

Source

///////////////////////////////////////////////////////////////////////////////
//Copyright (C) 2012 Assaf Urieli
//
//This file is part of Jochre.
//
//Jochre is free software: you can redistribute it and/or modify
//it under the terms of the GNU Affero General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//Jochre is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU Affero General Public License for more details.
//
//You should have received a copy of the GNU Affero General Public License
//along with Jochre.  If not, see <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////////////////
package com.joliciel.jochre.boundaries;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import java.util.TreeSet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.joliciel.jochre.graphics.Shape;

class SplitCandidateFinderImpl implements SplitCandidateFinder {
    private static final Log LOG = LogFactory.getLog(SplitCandidateFinderImpl.class);
    private BoundaryServiceInternal boundaryServiceInternal;
    private int minDistanceBetweenSplits = 5;

    @Override
    public List<Split> findSplitCandidates(Shape shape) {
        List<Split> splitCandidates = new ArrayList<Split>();

        // generate a list giving the total distance from the top and bottom to the shape's edge
        // the hypothesis is that splits almost always occur at x-coordinates
        // where there's a summit in the distance to the shape's edge, between two valleys
        int[] edgeDistances = new int[shape.getWidth()];
        int[][] verticalContour = shape.getVerticalContour();
        for (int x = 0; x < shape.getWidth(); x++) {
            int edgeDistance = verticalContour[x][0] + ((shape.getHeight() - 1) - verticalContour[x][1]);
            if (edgeDistance > shape.getHeight() - 1)
                edgeDistance = shape.getHeight() - 1;

            edgeDistances[x] = edgeDistance;
        }

        int[] maximaMinima = new int[shape.getWidth()];
        int lastDistance = -1;
        boolean rising = true;
        int i = 0;
        for (int edgeDistance : edgeDistances) {
            if (lastDistance >= 0) {
                if (edgeDistance < lastDistance && rising) {
                    maximaMinima[i - 1] = 1;
                }
                if (edgeDistance > lastDistance && !rising) {
                    maximaMinima[i - 1] = -1;
                }
            }
            if (edgeDistance > lastDistance) {
                rising = true;
            } else if (edgeDistance < lastDistance) {
                rising = false;
            }

            lastDistance = edgeDistance;
            i++;
        }
        maximaMinima[0] = 1;
        if (rising)
            maximaMinima[shape.getWidth() - 1] = 1;
        else
            maximaMinima[shape.getWidth() - 1] = -1;

        for (int x = 0; x < shape.getWidth(); x++) {
            String maxMin = "";
            if (maximaMinima[x] < 0)
                maxMin = " min";
            if (maximaMinima[x] > 0)
                maxMin = " max";
            LOG.trace("edgeDistance[" + x + "]: " + edgeDistances[x] + maxMin);
        }

        boolean haveMinimum = false;
        int lastMaximum = -1;
        int lastMinValue = 0;
        int lastMaxValue = 0;
        TreeSet<SplitCandidateValue> splitCandidateValues = new TreeSet<SplitCandidateFinderImpl.SplitCandidateValue>();
        for (i = 0; i < shape.getWidth(); i++) {
            if (maximaMinima[i] < 0) {
                haveMinimum = true;
                if (lastMaximum > 0) {
                    double diff = (double) ((lastMaxValue - lastMinValue) + (lastMaxValue - edgeDistances[i]))
                            / 2.0;
                    splitCandidateValues.add(new SplitCandidateValue(lastMaximum, diff));
                }
                lastMinValue = edgeDistances[i];
            }
            if (maximaMinima[i] > 0) {
                if (haveMinimum) {
                    lastMaximum = i;
                    lastMaxValue = edgeDistances[i];
                }
                haveMinimum = false;
            }
        }

        List<SplitCandidateValue> candidatesToRemove = new ArrayList<SplitCandidateFinderImpl.SplitCandidateValue>();
        for (SplitCandidateValue thisValue : splitCandidateValues) {
            if (candidatesToRemove.contains(thisValue))
                continue;
            for (SplitCandidateValue otherValue : splitCandidateValues) {
                if (candidatesToRemove.contains(otherValue))
                    continue;
                if (otherValue.equals(thisValue))
                    break;
                int distance = thisValue.getPosition() - otherValue.getPosition();
                if (distance < 0)
                    distance = 0 - distance;
                if (distance < this.minDistanceBetweenSplits) {
                    LOG.trace("Removing candidate " + otherValue.getPosition() + ", distance=" + distance);
                    candidatesToRemove.add(otherValue);
                }
            }
        }
        splitCandidateValues.removeAll(candidatesToRemove);

        TreeMap<Integer, Split> splitCandidateMap = new TreeMap<Integer, Split>();
        for (SplitCandidateValue candidateValue : splitCandidateValues) {
            Split splitCandidate = boundaryServiceInternal.getEmptySplit(shape);
            splitCandidate.setPosition(candidateValue.getPosition());
            splitCandidateMap.put(candidateValue.getPosition(), splitCandidate);
        }

        for (Split split : splitCandidateMap.values())
            splitCandidates.add(split);
        return splitCandidates;
    }

    private static class SplitCandidateValue implements Comparable<SplitCandidateValue> {
        int position;
        double magnitude;

        private SplitCandidateValue(int position, double magnitude) {
            super();
            this.position = position;
            this.magnitude = magnitude;
        }

        public int getPosition() {
            return position;
        }

        public double getMagnitude() {
            return magnitude;
        }

        @Override
        public int compareTo(SplitCandidateValue o) {
            if (position == o.getPosition())
                return 0;
            else if (this.magnitude >= o.getMagnitude())
                return -1;
            else
                return 1;
        }

    }

    public BoundaryServiceInternal getBoundaryServiceInternal() {
        return boundaryServiceInternal;
    }

    public void setBoundaryServiceInternal(BoundaryServiceInternal boundaryServiceInternal) {
        this.boundaryServiceInternal = boundaryServiceInternal;
    }

    @Override
    public int getMinDistanceBetweenSplits() {
        return minDistanceBetweenSplits;
    }

    @Override
    public void setMinDistanceBetweenSplits(int minDistanceBetweenSplits) {
        this.minDistanceBetweenSplits = minDistanceBetweenSplits;
    }

}