Package com.vividsolutions.jcs.conflate.polygonmatch

Source Code of com.vividsolutions.jcs.conflate.polygonmatch.TargetUnioningFCMatchFinder$Edge

/*
* The JCS Conflation Suite (JCS) is a library of Java classes that
* can be used to build automated or semi-automated conflation solutions.
*
* Copyright (C) 2003 Vivid Solutions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC  V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.vividsolutions.jcs.conflate.polygonmatch;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.util.Assert;
import com.vividsolutions.jump.feature.*;
import com.vividsolutions.jump.task.TaskMonitor;
import com.vividsolutions.jump.util.CollectionUtil;
import com.vividsolutions.jump.util.CoordinateArrays;
import java.util.*;
/**
*  An FCMatchFinder wrapper that also treats unions of adjacent target features
*  as themselves target features. Such unions are formed into composite target
*  features. These composites are temporary -- before the results are returned,
*  each composite is split into its constituent features. <P>
*
*  The result returned is a one-to-one mapping of target feature to matched
*  candidate feature; the one-to-one mapping is achieved by discarding all
*  matches except for those with the highest scores, for each feature (target
*  and matched candidate). <P>
*
*  Note on composites: if a composite's top score is higher than the top score
*  of each of its constituents, the composite match is retained and constituent
*  matches are discarded; otherwise, the composite match is discarded and
*  constituent matches are retained.
*/
public class TargetUnioningFCMatchFinder implements FCMatchFinder {
    private FCMatchFinder matchFinder;
    private int maxCompositeSize;
    /**
     *@param  maxCompositeSize  the maximum number of adjacent target features to
     *      try combining
     *@param  matchFinder       the FCMatchFinder to wrap
     */
    public TargetUnioningFCMatchFinder(int maxCompositeSize, FCMatchFinder matchFinder) {
        this.maxCompositeSize = maxCompositeSize;
        this.matchFinder = matchFinder;
    }
    @Override
    public Map match(
        FeatureCollection targetFC,
        FeatureCollection candidateFC,
        TaskMonitor monitor) {
        monitor.allowCancellationRequests();
        FeatureCollection compositeTargetFC = createCompositeFC(targetFC, monitor);
        Map compositeTargetFeatureToMatchesMap =
            matchFinder.match(compositeTargetFC, candidateFC, monitor);
        compositeTargetFeatureToMatchesMap =
            disambiguateCompositeTargetConstituents(
                compositeTargetFeatureToMatchesMap,
                candidateFC.getFeatureSchema(),
                monitor);
        createUnionIDs(compositeTargetFeatureToMatchesMap, monitor);               
        Map filteredTargetToMatchesMap =
            splitCompositeTargets(compositeTargetFeatureToMatchesMap, monitor);
        //Zero-score targets will have been filtered out. Put them back. [Jon Aquino]
        Map targetToMatchesMap =
            AreaFilterFCMatchFinder.blankTargetToMatchesMap(
                targetFC.getFeatures(),
                candidateFC.getFeatureSchema());
        targetToMatchesMap.putAll(filteredTargetToMatchesMap);
        return targetToMatchesMap;
    }
    private List lastTargetConstituents;
    private List lastUnionIDs;
    private void createUnionIDs(final Map compositeTargetFeatureToMatchesMap, TaskMonitor monitor) {
        monitor.report("Creating union IDs");
        ArrayList compositeTargets = new ArrayList(compositeTargetFeatureToMatchesMap.keySet());
        Collections.sort(compositeTargets, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                double s1 = ((Matches)compositeTargetFeatureToMatchesMap.get(o1)).getTopScore();
                double s2 = ((Matches)compositeTargetFeatureToMatchesMap.get(o2)).getTopScore();
                return s1 < s2 ? -1 : s1 > s2 ? 1 : 0;
            }
        });
        lastTargetConstituents = new ArrayList();
        lastUnionIDs = new ArrayList();
        int unionID = 0;
        for (int i = 0; i < compositeTargets.size(); i++) {
            monitor.report(i+1, compositeTargets.size(), "unions");
            CompositeFeature compositeTarget = (CompositeFeature) compositeTargets.get(i);
            if (compositeTarget.getFeatures().size() == 1) {
                continue;
            }
            unionID++;
            for (Iterator j = compositeTarget.getFeatures().iterator(); j.hasNext(); ) {
                Feature targetConstituent = (Feature) j.next();
                lastTargetConstituents.add(targetConstituent);
                lastUnionIDs.add(new Integer(unionID));
            }
        }
    }
    protected FeatureCollection createCompositeFC(
        FeatureCollection fc,
        TaskMonitor monitor) {
        FeatureCollection compositeFC = new FeatureDataset(fc.getFeatureSchema());
        Set composites = createCompositeSet(fc, monitor);
        add(composites, compositeFC, monitor);
        return new IndexedFeatureCollection(compositeFC);
    }
    /**
     * Returns a composite-target-to-Matches map in which each target constituent will be
     * found in at most one composite target. Does not disambiguate composite targets
     * or matches (use DisambiguatingFCMatchFinder to do that), just composite target
     * constituents.
     */
    protected Map disambiguateCompositeTargetConstituents(
        Map compositeTargetToMatchesMap,
        FeatureSchema candidateSchema,
        TaskMonitor monitor) {
        ArrayList targetConstituentsEncountered = new ArrayList();
        ArrayList compositeTargets = new ArrayList();
        ArrayList candidates = new ArrayList();
        ArrayList scores = new ArrayList();
        SortedSet matchSet =
            DisambiguationMatch.createDisambiguationMatches(compositeTargetToMatchesMap, monitor);
        monitor.report("Discarding inferior composite matches");
        int j = 0;
        outer : for (Iterator i = matchSet.iterator(); i.hasNext();) {
            DisambiguationMatch match = (DisambiguationMatch) i.next();
            monitor.report(++j, matchSet.size(), "matches");
            for (Iterator k =
                ((CompositeFeature) match.getTarget()).getFeatures().iterator();
                k.hasNext();
                ) {
                Feature targetConstituent = (Feature) k.next();
                if (targetConstituentsEncountered.contains(targetConstituent)) {
                    continue outer;
                }
            }
            compositeTargets.add(match.getTarget());
            candidates.add(match.getCandidate());
            scores.add(new Double(match.getScore()));
            targetConstituentsEncountered.addAll(((CompositeFeature) match.getTarget()).getFeatures());
        }
        Map newMap = new HashMap();
        for (int i = 0; i < compositeTargets.size(); i++) {
            Matches matches = new Matches(candidateSchema);
            matches.add(
                (Feature) candidates.get(i),
                ((Double) scores.get(i)).doubleValue());
            newMap.put(compositeTargets.get(i), matches);
        }
        return newMap;
    }
    private List featuresWithCommonEdge(Feature feature, FeatureCollection fc) {
        ArrayList featuresWithCommonEdge = new ArrayList();
        List candidates = fc.query(feature.getGeometry().getEnvelopeInternal());
        for (Iterator i = candidates.iterator(); i.hasNext();) {
            Feature candidate = (Feature) i.next();
            if (feature == candidate
                || shareEdge(feature.getGeometry(), candidate.getGeometry())) {
                featuresWithCommonEdge.add(candidate);
            }
        }
        return featuresWithCommonEdge;
    }
    protected boolean shareEdge(Geometry a, Geometry b) {
        Set aEdges = edges(a);
        Set bEdges = edges(b);
        for (Iterator i = bEdges.iterator(); i.hasNext();) {
            Edge bEdge = (Edge) i.next();
            if (aEdges.contains(bEdge)) {
                return true;
            }
        }
        return false;
    }
    private static class Edge implements Comparable {
        private Coordinate p0, p1;
        public Edge(Coordinate a, Coordinate b) {
            if (a.compareTo(b) < 1) {
                p0 = a;
                p1 = b;
            } else {
                p0 = b;
                p1 = a;
            }
        }
        @Override
        public int compareTo(Object o) {
            Edge other = (Edge) o;
            int result = p0.compareTo(other.p0);
            if (result != 0)
                return result;
            return p1.compareTo(other.p1);
        }
    }
    private Set edges(Geometry g) {
        TreeSet edges = new TreeSet();
        for (Iterator i = CoordinateArrays.toCoordinateArrays(g, false).iterator();
            i.hasNext();
            ) {
            Coordinate[] coordinates = (Coordinate[]) i.next();
            for (int j = 1; j < coordinates.length; j++) { //1
                edges.add(new Edge(coordinates[j], coordinates[j - 1]));
            }
        }
        return edges;
    }
    /**
     *  Splits each composite target into its constituent features.
     */
    protected Map splitCompositeTargets(Map compositeToMatchesMap, TaskMonitor monitor) {
        monitor.report("Splitting composites");
        int compositesProcessed = 0;
        int totalComposites = compositeToMatchesMap.size();
        Map newMap = new HashMap();
        for (Iterator i = compositeToMatchesMap.keySet().iterator();
            i.hasNext() && !monitor.isCancelRequested();
            ) {
            CompositeFeature composite = (CompositeFeature) i.next();
            compositesProcessed++;
            monitor.report(compositesProcessed, totalComposites, "composites");
            Matches matches = (Matches) compositeToMatchesMap.get(composite);
            for (Iterator j = composite.getFeatures().iterator(); j.hasNext();) {
                Feature targetConstituent = (Feature) j.next();
                Assert.isTrue(!newMap.containsKey(targetConstituent));
                newMap.put(targetConstituent, matches.clone());
            }
        }
        return newMap;
    }
    private Set createCompositeSet(FeatureCollection fc, TaskMonitor monitor) {
        monitor.report("Creating composites of adjacent features");
        int featuresProcessed = 0;
        int totalFeatures = fc.getFeatures().size();
        //Use a Set to prevent duplicate composites [Jon Aquino]
        HashSet composites = new HashSet();
        for (Iterator i = fc.getFeatures().iterator();
            i.hasNext() && !monitor.isCancelRequested();
            ) {
            Feature feature = (Feature) i.next();
            featuresProcessed++;
            monitor.report(featuresProcessed, totalFeatures, "features");
            List featuresWithCommonEdge = featuresWithCommonEdge(feature, fc);
            for (Iterator j =
                CollectionUtil
                    .combinations(featuresWithCommonEdge, maxCompositeSize, feature)
                    .iterator();
                j.hasNext() && !monitor.isCancelRequested();
                ) {
                List combination = (List) j.next();
                composites.add(new CompositeFeature(fc.getFeatureSchema(), combination));
            }
        }
        return composites;
    }

    public static class CompositeFeature extends BasicFeature {
        private List features;
        private int hashCode;
        public CompositeFeature(FeatureSchema schema, List features) {
            super(schema);
            this.features = features;
            Geometry union = ((Feature) features.get(0)).getGeometry();
            hashCode = ((Feature) features.get(0)).hashCode();
            for (int i = 1; i < features.size(); i++) {
                Feature feature = (Feature) features.get(i);
                union = union.union(feature.getGeometry());
                hashCode = Math.min(hashCode, feature.hashCode());
            }
            setGeometry(union);
        }
        public List getFeatures() {
            return features;
        }
        @Override
        public boolean equals(Object obj) {
            Assert.isTrue(obj instanceof CompositeFeature, obj.getClass().toString());
            CompositeFeature other = (CompositeFeature) obj;
            if (features.size() != other.features.size()) {
                return false;
            }
            for (Iterator i = features.iterator(); i.hasNext();) {
                Feature myFeature = (Feature) i.next();
                if (!other.features.contains(myFeature)) {
                    return false;
                }
            }
            return true;
        }
        @Override
        public int hashCode() {
            return hashCode;
        }
    }
    private void add(Collection features, FeatureCollection fc, TaskMonitor monitor) {
        monitor.report("Building feature-collection");
        fc.addAll(features);
    }
    public Integer getUnionID(Feature target) {
        int i = lastTargetConstituents.indexOf(target);
        if (i == -1) { return null; }
        return (Integer)lastUnionIDs.get(i);
    }
}
TOP

Related Classes of com.vividsolutions.jcs.conflate.polygonmatch.TargetUnioningFCMatchFinder$Edge

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.