]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/Segment.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.utils.datastructures / src / org / simantics / utils / datastructures / Segment.java
diff --git a/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/Segment.java b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/Segment.java
new file mode 100644 (file)
index 0000000..34e8345
--- /dev/null
@@ -0,0 +1,528 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.utils.datastructures;\r
+\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Comparator;\r
+import java.util.List;\r
+\r
+/**\r
+ * Segment consists of a start and a end value. Both start and end are inclusive.  \r
+ * \r
+ * @See {@link SegmentSet}\r
+ * @author Toni Kalajainen\r
+ */\r
+public final class Segment implements Comparable<Segment>, Serializable, Cloneable {\r
+\r
+       public static final Segment ALL = new Segment(-Double.MAX_VALUE, Double.MAX_VALUE);\r
+       public static final Segment[] NO_RANGES = new Segment[0];\r
+       \r
+    /**\r
+     * Define serial version of this class\r
+        */\r
+       private static final long serialVersionUID = 2979572023736175492L;\r
+\r
+       /** start Data */\r
+    private double start;\r
+\r
+    /** end Data */\r
+    private double end;\r
+\r
+    /**\r
+     * Create a new segment at a single value\r
+     *  \r
+     * @param value value\r
+     * @return segment\r
+     */\r
+    public static Segment at(double value)\r
+    {\r
+               return new Segment(value, value);\r
+    }\r
+    \r
+    /**\r
+     * Create the segment between two values\r
+     *  \r
+     * @param d1 value 1\r
+     * @param d2 value 2\r
+     * @return segment\r
+     */\r
+    public static Segment of(double d1, double d2)\r
+    {\r
+       if (d1<d2) \r
+               return new Segment(d1, d2);\r
+       else\r
+               return new Segment(d2, d1);\r
+    }\r
+    \r
+    /**\r
+     * Create a segment. Start and end are included.\r
+     * Start value must be smaller that end value.\r
+     * \r
+     * @param start the start time\r
+     * @param end the end time\r
+     */\r
+    public Segment(double start, double end) {\r
+       if (start>end)\r
+               throw new IllegalArgumentException("Start is after end");\r
+       this.start = start;\r
+       this.end = end;\r
+    }\r
+    \r
+    /**\r
+     * Create single point\r
+     * \r
+     * @param data Data point \r
+     */\r
+    public Segment(double data) {\r
+        start = data;\r
+        end = data;\r
+    }\r
+    \r
+    /**\r
+     * Create as segment.\r
+     * @param data\r
+     */\r
+    public Segment(double[] data) {\r
+       assert(data.length ==2);\r
+       start = data[0];\r
+       end = data[1];\r
+       if (start>end)\r
+               throw new IllegalArgumentException("Start is after end");\r
+       \r
+    }\r
+\r
+    /**\r
+     * Get the end Data\r
+     * \r
+     * @return the end Data\r
+     */\r
+    public double getEnd() {\r
+        return end;\r
+    }\r
+\r
+    /**\r
+     * Get the start Data\r
+     * \r
+     * @return the Data\r
+     */\r
+    public double getStart() {\r
+        return start;\r
+    }\r
+\r
+    /**\r
+     * Get the length of the Data\r
+     * \r
+     * @return the length\r
+     */\r
+    public double getLength() {\r
+        return end - start;\r
+    }\r
+\r
+    public Segment createWithNewStart(double newStartData) {\r
+        return new Segment(newStartData, end);\r
+    }\r
+\r
+    public Segment createWithNewEnd(double newEndData) {\r
+        return new Segment(start, newEndData);\r
+    }\r
+\r
+    /**\r
+     * Creates a one element array\r
+     * \r
+     * @return the 1-element array\r
+     */\r
+    public Segment[] toArray() {\r
+        Segment[] array = new Segment[1];\r
+        array[0] = this;\r
+        return array;\r
+    }\r
+    \r
+    /**\r
+     * Tests wheter this segment contains value\r
+     * \r
+     * @param value the value\r
+     * @return true if the value is within the segment\r
+     */\r
+    public boolean contains(double value) {\r
+        return (value>=start && value<=end);\r
+    }\r
+    \r
+    /**\r
+     * Tests whether this segment fully contains s\r
+     * \r
+     * @param s segment\r
+     * @return Returns true if this segment contains s\r
+     */\r
+    public boolean contains(Segment s) {\r
+        return (start<=s.start && end>=s.end);\r
+    }\r
+    \r
+    /**\r
+     * Tests whether s intersects or is parallel to this segment.\r
+     * \r
+     * @param s segment\r
+     * @return true if the two segments intersect or are parallel\r
+     */\r
+    public boolean parallelWith(Segment s) {\r
+        if (s.start > this.end) return false;\r
+        if (s.end < this.start) return false;\r
+        return true;\r
+    }\r
+\r
+    /**\r
+     * Tests whether s intersects with this segment\r
+     *  \r
+     * @param s segment\r
+     * @return true if they intersect \r
+     */\r
+    public boolean intersects(Segment s) {\r
+        if (s.start >= this.end) return false;\r
+        if (s.end <= this.start) return false;\r
+        return true;\r
+    }\r
+    \r
+    /**\r
+     * Extends the segment with another.\r
+     *  \r
+     * @param s other segment\r
+     * @return new segment containing both segments\r
+     */\r
+    public Segment extendWith(Segment s) {\r
+       if (contains(s)) return this;\r
+       if (s.contains(this)) return s;\r
+        double newStart = this.start;\r
+        if (s.start<newStart) newStart = s.start;\r
+        double newEnd = this.end;\r
+        if (s.end>newEnd) newEnd = s.end;\r
+        return new Segment(newStart, newEnd);\r
+    }\r
+    \r
+    /**\r
+     * Extends this segment so that value is included.\r
+     * \r
+     * @param value a value\r
+     * @return new segment that includes the value\r
+     */\r
+    public Segment extendWith(double value) {\r
+       if (this.contains(value)) return this;\r
+        return new Segment((value<start?value:start),(value>end?value:end));\r
+    }\r
+    \r
+    /**\r
+     * Create an intersection of this and s\r
+     * \r
+     * @param s segment\r
+     * @return the intersection\r
+     */\r
+    public Segment[] intersection(Segment s) {\r
+        Segment list[] = new Segment[2];\r
+        list[0] = this;\r
+        list[1] = s;\r
+        return Segment.intersection(list);\r
+    }\r
+\r
+    /**\r
+     * Create an union of this and s\r
+     * \r
+     * @param s segment\r
+     * @return the union\r
+     */\r
+    public Segment[] union(Segment range) {\r
+        Segment list[] = new Segment[2];\r
+        list[0] = this;\r
+        list[1] = range;\r
+        return Segment.union(list);\r
+    }\r
+\r
+    /**\r
+     * Create intersection\r
+     * \r
+     * @param segments1 group of Data range\r
+     * @param segments2 group of Data range\r
+     * @return the intersection\r
+     */\r
+    public static Segment[] intersection(Segment segments1[],\r
+            Segment segments2[]) {\r
+        return intersection(concat(segments1, segments2));\r
+    }\r
+    \r
+    /**\r
+     * Create union\r
+     * \r
+     * @param segments1 group of segments\r
+     * @param segments2 group of segments\r
+     * @return the union\r
+     */\r
+    public static Segment[] union(Segment segments1[], Segment segments2[]) {\r
+        return union(concat(segments1, segments2));\r
+    }\r
+    \r
+    /**\r
+     * Returns difference of segments \r
+     * \r
+     * @param group\r
+     * @param cutWith\r
+     * @return\r
+     */\r
+    public static Segment[] difference(Segment group[], Segment cutWith) {\r
+       if (group.length==0) return group;\r
+        \r
+        List<Segment> result = new ArrayList<Segment>(group.length+2);\r
+        for (Segment range : group) {\r
+                // Cuts the range completely\r
+             if (cutWith.start<=range.start && cutWith.end>=range.end) continue;\r
+             // Doesn't cut the range at all\r
+             if (cutWith.start>=range.end || cutWith.end<=range.start) {\r
+                 result.add(range);\r
+                 continue;\r
+             }\r
+             // Splits the range in half\r
+             if (cutWith.start>range.start && cutWith.end<range.end) {\r
+                 result.add(new Segment(range.start, cutWith.start));\r
+                 result.add(new Segment(cutWith.end, range.end));\r
+                 continue;\r
+             }\r
+             // cuts the range from one end\r
+             if (cutWith.start<=range.start) {\r
+                 result.add(new Segment(cutWith.end, range.end));\r
+                 continue;\r
+             }\r
+             // cuts the range from one end\r
+             if (cutWith.end>=range.end) {\r
+                 result.add(new Segment(range.start, cutWith.start));\r
+                 continue;\r
+             }    \r
+             \r
+         }\r
+         \r
+        return (Segment[]) result.toArray(NO_RANGES);\r
+    }\r
+    \r
+    /**\r
+     * Returns difference of segments \r
+     * @param segments1\r
+     * @param segments2\r
+     * @return\r
+     */\r
+    public static Segment[] difference(Segment segments1[], Segment segments2[]) {\r
+       // TODO : this could be optimized (both arrays are sorted)\r
+       Segment temp[] = segments1;\r
+       for (Segment s : segments2)\r
+               temp = difference(temp, s);\r
+       return temp;\r
+    }\r
+\r
+    /**\r
+     * Concate arrays \r
+     * \r
+     * @param array1 array\r
+     * @param array2 array\r
+     * @return the concatenation\r
+     */\r
+    public static Segment[] concat(Segment array1[], Segment array2[]) {\r
+        Segment result[] = new Segment[array1.length + array2.length];\r
+        System.arraycopy(array1, 0, result, 0, array1.length);\r
+        System.arraycopy(array2, 0, result, array1.length, array2.length);\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * Create an intersection with another segment\r
+     * \r
+     * @param s segment\r
+     * @return null if no intersection, otherwise the intersection\r
+     */\r
+    Segment intersectWith(Segment s) {\r
+        if (!intersects(s)) return null;\r
+        double newStart = this.start;\r
+        if (s.start>newStart) newStart = s.start;\r
+        double newEnd = this.end;\r
+        if (s.end<newEnd) newEnd = s.end;\r
+        return new Segment(newStart, newEnd);        \r
+    }    \r
+    \r
+    /**\r
+     * Create an difference with another segment\r
+     * \r
+     * @param s segment\r
+     * @return null if no intersection, otherwise the intersection\r
+     */\r
+    Segment differenceWith(Segment s) {\r
+        if (!intersects(s)) return this;\r
+        double newStart = this.start;\r
+        double newEnd = this.end;\r
+        if (s.start<newEnd) newEnd = s.start;\r
+        if (s.end>newStart) newStart = s.end;\r
+        if (newEnd < newStart)\r
+               return null;\r
+        return new Segment(newStart, newEnd);        \r
+    }  \r
+    /**\r
+     * Intersect a group of segments.\r
+     * In the result contains all segments where 2 or more segments intersected\r
+     * in the source group. \r
+     * \r
+     * @param group group of segments\r
+     * @return intersection of segments. sorted array\r
+     */\r
+    public static Segment[] intersection(Segment group[]) {\r
+        group = sort(group);\r
+        int count = 0;\r
+        Segment[] temp = new Segment[group.length];\r
+        \r
+        Segment base = group[0];\r
+        for (int i=1; i<group.length; i++) {\r
+            Segment r = group[i];\r
+            // an intersection\r
+            Segment is = base.intersectWith(r);\r
+            if (is != null) temp[count++] = is;\r
+\r
+            // extend our base\r
+            if (r.parallelWith(base)) {\r
+                base = base.extendWith(r);\r
+            } else\r
+            // Choose a new base\r
+                base = r;\r
+            \r
+        }\r
+        return resizeArray(temp, count);\r
+    }\r
+\r
+    /**\r
+     * Create an union a group of segments\r
+     * \r
+     * @param group group of segments \r
+     * @return incrementally sorted, non-intersecting array of segments\r
+     */\r
+    public static Segment[] union(Segment group[]) {\r
+        if (group.length<=1) return group;\r
+        group = sort(group);\r
+        \r
+        int count = 0;\r
+        Segment[] temp = new Segment[group.length];\r
+        \r
+        Segment base = group[0];\r
+        for (int i=1; i<group.length; i++) {\r
+            Segment r = group[i];\r
+            if (r.parallelWith(base))\r
+                base = base.extendWith(r);\r
+            else {\r
+                temp[count++] = base;\r
+                base = r;\r
+            }               \r
+        }\r
+        temp[count++] = base;\r
+        return resizeArray(temp, count);\r
+    }\r
+\r
+    /**\r
+     * Resize an array\r
+     * \r
+     * @param array the array\r
+     * @param newLength new length of the array\r
+     * @return new resized array\r
+     */\r
+    public static Segment[] resizeArray(Segment array[], int newLength) {\r
+        int oldLength = array.length;\r
+        if (oldLength==newLength) return array;\r
+        \r
+        Segment newArray[] = new Segment[newLength];            \r
+        // Crop the array\r
+        if (newLength<oldLength) \r
+            System.arraycopy(array, 0, newArray, 0, newLength);\r
+        else\r
+            System.arraycopy(array, 0, newArray, 0, oldLength);\r
+        return newArray;\r
+    }\r
+\r
+    /**\r
+     * Sort array by their start Datas\r
+     * \r
+     * @param group group of segments to sort\r
+     * @return incrementally sorted array of segments\r
+     */\r
+    public static Segment[] sort(Segment group[]) {\r
+        Segment[] result = (Segment[]) group.clone();\r
+        Arrays.sort(result, COMPARATOR);\r
+        return result;\r
+    }\r
+    \r
+    private static final Comparator<Segment> COMPARATOR = new Comparator<Segment>() {\r
+        public int compare(Segment o1, Segment o2) {\r
+            if (o1.start < o2.start)\r
+                return -1;\r
+            if (o1.start > o2.start)\r
+                return 1;\r
+            \r
+            if (o1.end < o2.end)\r
+                return -1;\r
+            if (o1.end > o2.end)\r
+                return 1;\r
+            \r
+            return 0;\r
+        }\r
+    }; \r
+    \r
+    @Override\r
+    public int hashCode() {\r
+       long bits = Double.doubleToLongBits(start);\r
+       int hash = (int)(bits ^ (bits >>> 32));\r
+       bits = Double.doubleToLongBits(end);\r
+       hash ^= (int)(bits ^ (bits >>> 32));\r
+       return hash;\r
+    }\r
+\r
+    public boolean equals(Object obj) {\r
+        if (!(obj instanceof Segment)) return false;\r
+        Segment other = (Segment) obj;\r
+        return (other.end == this.end) && (other.start == this.start);\r
+    }\r
+\r
+    /**\r
+     * Segment start are compared. If they are equal, ends are compared.\r
+     * Smallest value first.\r
+     * \r
+     * @param other compare to\r
+     * @return the compare value\r
+     */\r
+    public int compareTo(Segment other) {\r
+        double diffrence = this.start - other.start;\r
+        if (diffrence < 0)\r
+            return -1;\r
+        if (diffrence > 0)\r
+            return 1;\r
+        \r
+        diffrence = this.end - other.end;\r
+        if (diffrence < 0)\r
+            return -1;\r
+        if (diffrence > 0)\r
+            return 1;\r
+        return 0;\r
+    }\r
+    \r
+    @Override\r
+    public Segment clone() {\r
+       return new Segment(start, end);\r
+    }\r
+    \r
+    public String toString() {\r
+        return "["+start+".."+end+"]";\r
+    }\r
+\r
+    public static String toString(Segment array[]) {\r
+       return Arrays.toString(array);\r
+    }\r
+    \r
+}\r
+\r