X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.utils.datastructures%2Fsrc%2Forg%2Fsimantics%2Futils%2Fdatastructures%2FSegmentSet.java;fp=bundles%2Forg.simantics.utils.datastructures%2Fsrc%2Forg%2Fsimantics%2Futils%2Fdatastructures%2FSegmentSet.java;h=e722d4a462c5e1162973121cbe712e6646827965;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/SegmentSet.java b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/SegmentSet.java new file mode 100644 index 000000000..e722d4a46 --- /dev/null +++ b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/SegmentSet.java @@ -0,0 +1,358 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.utils.datastructures; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * SegmentSet is a set of value segments. + * + * @author Toni Kalajainen + */ +public class SegmentSet implements Iterable { + + public static final SegmentSet NONE = new SegmentSet(); + + /** incrementally sorted and non-intersecting, non-parallel array of segments */ + List list = new ArrayList(); + + /** + * Create new segment set from double value pairs + * + * @param times even length array + * @return + */ + public static SegmentSet of(double...times) + { + if (times==null || ((times.length & 1)==1)) + throw new IllegalArgumentException(); + SegmentSet result = new SegmentSet(); + for (int i=0; i list) { + for (Segment r : list) + add(r); + } + + /** + * Create new set of segments. + * + * @param segments initial segments + */ + public SegmentSet(Segment...segments) { + for (Segment r : Segment.union(segments)) + list.add(r); + } + + public boolean add(Segment...segments) { + boolean result = false; + for (Segment r : segments) + result |= add(r); + return result; + } + + /** + * Add a segment set to this segment set + * + * @param set + * @return true if the content changed + */ + public boolean add(SegmentSet set) { + boolean result = false; + for (Segment r : set.list) + result |= add(r); + return result; + } + + /** + * Get index of the segment that contains the given value. + * If value is not included in the set, return as negative value the index + * of the range the value is prior to. + * e.g. + * -1 before 0 + * -2 before 1 + * + * @return range index + */ + int indexOf(double value) { + for (int i=0; i=value) return -i -1; + } + return -list.size()-1; + } + + /** + * Get the segment the value is in. + * + * @param value + * @return segment or null + */ + public Segment getSegmentOf(double value) + { + int index = indexOf(value); + if (index<0) return null; + return list.get(index); + } + + /** + * Add segment range + * + * @param range + * @return true if the content changed + */ + public boolean add(Segment range) { + int startIndex = indexOf(range.getStart()); + int endIndex = indexOf(range.getEnd()); + + // The whole segment is already included in the set + if (startIndex>=0 && startIndex==endIndex) return false; + + // Doesn't intersect, add as is + if (startIndex<0 && startIndex==endIndex) { + list.add(-startIndex-1, range); + return true; + } + + // Intersects partially + double start = range.getStart(); + double end = range.getEnd(); + + // Extend the segment following the start position + if (startIndex<0) { + startIndex = -startIndex-1; + } else { + start = list.get(startIndex).getStart(); + } + + // Extends the segment preceding the end position + if (endIndex<0) { + endIndex = -endIndex-2; + } else { + end = list.get(endIndex).getEnd(); + } + + int segmentsToRemove = endIndex - startIndex; + for (int j=0; jlist.get(startIndex).getStart()) { + Segment s = list.get(startIndex); + Segment newS = new Segment(s.getStart(), range.getStart()); + list.set(startIndex, newS); + startIndex++; + + if (s.getEnd()>range.getEnd()) { + newS = new Segment(range.getEnd(), s.getEnd()); + list.add(startIndex, newS); + startIndex++; + } + } + + // End position is within segment, Cut it and move to prev one + if (range.getEnd()=0; + } + + /** + * Get the min and max value + * + * @return boundaries or null + */ + public Segment getBoundaries() + { + if (list.isEmpty()) return null; + double start = list.get(0).getStart(); + double end = list.get(list.size()-1).getEnd(); + return new Segment(start, end); + } + + /** + * + * @return lower bound or null + */ + public Double getLowerBound() { + if (list.isEmpty()) return null; + return list.get(0).getStart(); + } + + /** + * + * @return upper bound or null + */ + public Double getUpperBound() { + if (list.isEmpty()) return null; + return list.get(list.size()-1).getEnd(); + } + + /** + * Return incrementally sorted and non-intersecting array of segments. + * + * Note this method returns an internal state, it most not be modified. + * + * @return array + */ + public Segment[] toArray() { + return list.toArray( new Segment[list.size()] ); + } + + /** + * Returns an iterator over the elements in this list in proper sequence. + * + * @return an iterator over the elements in this list in proper sequence. + */ + public Iterator iterator() { + return list.iterator(); + } + + @Override + public String toString() { + return Arrays.toString( toArray() ); + } + + public SegmentSet clone() { + return new SegmentSet(this); + } + +} +