/// <summary> /// Area of covered rectangle for two sepcified rectangles /// </summary> public static double JoinArea(RectangleR2 a, RectangleR2 b) { double _left = (a._left < b._left) ? a._left : b._left; double _right = (a._right > b._right) ? a._right : b._right; double _top = (a._top < b._top) ? a._top : b._top; double _bottom = (a._bottom > b._bottom) ? a._bottom : b._bottom; return (_bottom-_top)*(_right-_left); }
internal RtreeR2Page(Storage storage, object obj, RectangleR2 r) { branch = storage.CreateLink(card); branch.Length = card; b = new RectangleR2[card]; setBranch(0, new RectangleR2(r), obj); n = 1; for (int i = 1; i < card; i++) { b[i] = new RectangleR2(); } }
internal RtreeR2Page(Storage storage, RtreeR2Page root, RtreeR2Page p) { branch = storage.CreateLink(card); branch.Length = card; b = new RectangleR2[card]; n = 2; setBranch(0, root.cover(), root); setBranch(1, p.cover(), p); for (int i = 2; i < card; i++) { b[i] = new RectangleR2(); } }
public static void Main(String[] args) { Storage db = StorageFactory.Instance.CreateStorage(); db.Open("testleak.dbs"); #if USE_GENERICS SpatialIndexR2<SpatialObject> root = db.CreateSpatialIndexR2<SpatialObject>(); #else SpatialIndexR2 root = db.CreateSpatialIndexR2(); #endif RectangleR2[] rectangles = new RectangleR2[nObjects]; Random rnd = new Random(2014); db.Root = root; for (int i = 0; i < nObjects; i++) { SpatialObject so = new SpatialObject(); double lat = rnd.NextDouble()*180; double lng = rnd.NextDouble()*180; so.rect = rectangles[i] = new RectangleR2(lat, lng, lat+10, lng+10); so.body = new byte[minObjectSize + rnd.Next(maxObjectSize - minObjectSize)]; root.Put(so.rect, so); } db.Commit(); for (int i = 0; i < nIterations; i++) { if (i % 1000 == 0) { Console.WriteLine("Iteration " + i); } for (int j = 0; j < batchSize; j++) { int k = rnd.Next(nObjects); bool found = false; foreach (SpatialObject oldObj in root.Overlaps(rectangles[k])) { if (oldObj.rect.Equals(rectangles[k])) { root.Remove(oldObj.rect, oldObj); SpatialObject newObj = new SpatialObject(); newObj.rect = oldObj.rect; newObj.body = new byte[minObjectSize + rnd.Next(maxObjectSize - minObjectSize)]; root.Put(newObj.rect, newObj); oldObj.Deallocate(); found = true; break; } } Debug.Assert(found); } db.Commit(); } db.Close(); }
internal RtreeR2Page insert(Storage storage, RectangleR2 r, object obj, int level) { Modify(); if (--level != 0) { // not leaf page int i, mini = 0; double minIncr = Double.MaxValue; double minArea = Double.MaxValue; for (i = 0; i < n; i++) { double area = b[i].Area(); double incr = RectangleR2.JoinArea(b[i], r) - area; if (incr < minIncr) { minIncr = incr; minArea = area; mini = i; } else if (incr == minIncr && area < minArea) { minArea = area; mini = i; } } RtreeR2Page p = (RtreeR2Page)branch[mini]; RtreeR2Page q = p.insert(storage, r, obj, level); if (q == null) { // child was not split b[mini].Join(r); return null; } else { // child was split setBranch(mini, p.cover(), p); return addBranch(storage, q.cover(), q); } } else { return addBranch(storage, new RectangleR2(r), obj); } }
/// <summary> /// Join two rectangles. This rectangle is updates to contain cover of this and specified rectangle. /// </summary> /// <param name="r">rectangle to be joined with this rectangle /// </param> public void Join(RectangleR2 r) { if (_left > r._left) { _left = r._left; } if (_right < r._right) { _right = r._right; } if (_top > r._top) { _top = r._top; } if (_bottom < r._bottom) { _bottom = r._bottom; } }
/// <summary> /// Create copy of the rectangle /// </summary> public RectangleR2(RectangleR2 r) { this._top = r._top; this._left = r._left; this._bottom = r._bottom; this._right = r._right; }
internal int remove(RectangleR2 r, object obj, int level, ArrayList reinsertList) { if (--level != 0) { for (int i = 0; i < n; i++) { if (r.Intersects(b[i])) { RtreeR2Page pg = (RtreeR2Page)branch[i]; int reinsertLevel = pg.remove(r, obj, level, reinsertList); if (reinsertLevel >= 0) { if (pg.n >= minFill) { setBranch(i, pg.cover(), pg); Modify(); } else { // not enough entries in child reinsertList.Add(pg); reinsertLevel = level - 1; removeBranch(i); } return reinsertLevel; } } } } else { for (int i = 0; i < n; i++) { if (branch.ContainsElement(i, obj)) { removeBranch(i); return 0; } } } return -1; }
internal RectangleR2 cover() { RectangleR2 r = new RectangleR2(b[0]); for (int i = 1; i < n; i++) { r.Join(b[i]); } return r; }
private bool MatchProperty(NameVal prop, Thing thing) { switch (prop.name) { case Symbols.Point: if (prop.val is NameVal[]) { NameVal[] coord = (NameVal[])prop.val; if (coord.Length == 2) { double x = (double)coord[0].val; double y = (double)coord[1].val; RectangleR2 r = new RectangleR2(x, y, x, y); foreach (Thing t in root.spatialIndex.Overlaps(r)) { if (t == thing) { return true; } } return false; } } break; case Symbols.Rectangle: if (prop.val is NameVal[]) { NameVal[] coord = (NameVal[])prop.val; if (coord.Length == 4) { RectangleR2 r = new RectangleR2((double)coord[0].val, (double)coord[1].val, (double)coord[2].val, (double)coord[3].val); foreach (Thing t in root.spatialIndex.Overlaps(r)) { if (t == thing) { return true; } } return false; } } break; case Symbols.Keyword: if (prop.val is string) { Hashtable keywords = new Hashtable(); foreach (PropVal pv in thing.props) { object val = pv.val; if (val is string) { foreach (string keyword in ((string)val).ToLower().Split(keywordSeparators)) { if (keyword.Length > 0 && !keywordStopList.ContainsKey(keyword)) { keywords[keyword] = this; } } } } foreach (string keyword in ((string)prop.val).ToLower().Split(keywordSeparators)) { if (keyword.Length > 0 && !keywordStopList.ContainsKey(keyword) && !keywords.ContainsKey(keyword)) { return false; } } return true; } break; } NextItem: foreach (object val in thing[prop.name]) { object pattern = prop.val; if (val is string && pattern is string) { if (MatchString((string)val, (string)pattern)) { return true; } } else if (pattern is NameVal) { if (FollowReference((NameVal)pattern, val as VersionHistory)) { return true; } } else if (pattern is NameVal[]) { foreach (NameVal p in (NameVal[])prop.val) { if (!FollowReference(p, val as VersionHistory)) { goto NextItem; } } return true; } else if (pattern is Range && val is IComparable) { try { Range range = (Range)pattern; IComparable cmp = (IComparable)val; return cmp.CompareTo(range.from) >= (range.fromInclusive ? 0 : 1) && cmp.CompareTo(range.till) <= (range.tillInclusive ? 0 : -1); } catch (ArgumentException) {} } else if (pattern != null && pattern.Equals(val)) { return true; } } return false; }
/// <summary> /// Checks if this rectangle contains the specified rectangle /// </summary> public bool Contains(RectangleR2 r) { return _left <= r._left && _top <= r._top && _right >= r._right && _bottom >= r._bottom; }
RtreeR2Page addBranch(Storage storage, RectangleR2 r, object obj) { if (n < card) { setBranch(n++, r, obj); return null; } else { return splitPage(storage, r, obj); } }
void setBranch(int i, RectangleR2 r, object obj) { b[i] = r; branch[i] = obj; }
internal void find(RectangleR2 r, ArrayList result, int level) { if (--level != 0) { /* this is an internal node in the tree */ for (int i = 0; i < n; i++) { if (r.Intersects(b[i])) { ((RtreeR2Page)branch[i]).find(r, result, level); } } } else { /* this is a leaf node */ for (int i = 0; i < n; i++) { if (r.Intersects(b[i])) { result.Add(branch[i]); } } } }
public void Unpack(ObjectReader reader) { rect = new RectangleR2(reader.ReadDouble(), reader.ReadDouble(), reader.ReadDouble(), reader.ReadDouble()); body = reader.ReadBytes(reader.ReadInt32()); }
/// <summary> /// Non destructive join of two rectangles. /// </summary> /// <param name="a">first joined rectangle /// </param> /// <param name="b">second joined rectangle /// </param> /// <returns>rectangle containing cover of these two rectangles /// </returns> public static RectangleR2 Join(RectangleR2 a, RectangleR2 b) { RectangleR2 r = new RectangleR2(a); r.Join(b); return r; }
/// <summary>Get iterator through object matching specified search parameters</summary> /// <param name="type">String representing type of the object (direct or indirect - IsInstanceOf /// method will be used to check if object belongs to the specified type). It may be null, /// in this case type criteria is skipped.</param> /// <param name="uri">Object URI pattern. It may be null, in this case URI is not inspected.</param> /// <param name="patterns">array of name:value pairs specifying search condition for object properties</param> /// <param name="kind">search kind used to select inspected versions</param> /// <param name="timestamp">timestamp used to select versions, if kind is SearchKind.LatestVersion /// or SearchKind.AllVersions this parameter is ignored</param> /// <returns>Enumerator through object meet search criteria.</returns> public IEnumerable Search(string type, string uri, NameVal[] patterns, SearchKind kind, DateTime timestamp) { VersionHistory typeVh = null; root.SharedLock(); try { if (type != null) { typeVh = GetObject(type); if (typeVh == null) { return new object[0]; // empty selection } } if (uri != null) { int wc = uri.IndexOf('*'); if (wc < 0) { return new SearchResult(root, typeVh, null, patterns, kind, timestamp, root.prefixUriIndex.GetEnumerator(uri, uri)); } else if (wc > 0) { String prefix = uri.Substring(0, wc); return new SearchResult(root, typeVh, uri, patterns, kind, timestamp, root.prefixUriIndex.GetEnumerator(prefix)); } else if ((wc = uri.LastIndexOf('*')) < uri.Length-1) { String suffix = ReverseString(uri.Substring(wc+1, uri.Length-wc-1)); return new SearchResult(root, typeVh, uri, patterns, kind, timestamp, root.suffixUriIndex.GetEnumerator(suffix)); } } if (patterns.Length > 0) { NameVal prop = patterns[0]; object val = prop.val; NameVal[] restOfPatterns = SubArray(patterns); switch (prop.name) { case Symbols.Timestamp: if (val is Range) { Range range = (Range)val; if (range.from is DateTime) { Key fromKey = new Key((DateTime)range.from, range.fromInclusive); Key tillKey = new Key((DateTime)range.till, range.tillInclusive); return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp, root.timeIndex.GetEnumerator(fromKey, tillKey)); } } else if (val is DateTime) { Key key = new Key((DateTime)val); return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp, root.timeIndex.GetEnumerator(key, key)); } return new object[0]; // empty selection case Symbols.Rectangle: if (val is NameVal[]) { NameVal[] coord = (NameVal[])val; if (coord.Length == 4) { RectangleR2 r = new RectangleR2((double)coord[0].val, (double)coord[1].val, (double)coord[2].val, (double)coord[3].val); return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp, root.spatialIndex.Overlaps(r).GetEnumerator()); } } break; case Symbols.Point: if (val is NameVal[]) { NameVal[] coord = (NameVal[])val; if (coord.Length == 2) { double x = (double)coord[0].val; double y = (double)coord[1].val; RectangleR2 r = new RectangleR2(x, y, x, y); return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp, root.spatialIndex.Overlaps(r).GetEnumerator()); } } break; case Symbols.Keyword: if (val is string) { ArrayList keywords = new ArrayList(); foreach (string keyword in ((string)val).ToLower().Split(keywordSeparators)) { if (keyword.Length > 0 && !keywordStopList.ContainsKey(keyword)) { keywords.Add(keyword); } } IEnumerator[] occurences = new IEnumerator[keywords.Count]; for (int i = 0; i < occurences.Length; i++) { Key key = new Key((string)keywords[i]); occurences[i] = root.inverseIndex.GetEnumerator(key, key); } return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp, db.Merge(occurences)); } break; } PropDef def = (PropDef)root.propDefIndex[prop.name]; if (def == null) { return new object[0]; // empty selection } if (val is Range) { Range range = (Range)val; if (range.from is double) { Key fromKey = new Key(new object[]{def, range.from}, range.fromInclusive); Key tillKey = new Key(new object[]{def, range.till}, range.tillInclusive); return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp, root.numPropIndex.GetEnumerator(fromKey, tillKey)); } else if (range.from is DateTime) { Key fromKey = new Key(new object[]{def, range.from}, range.fromInclusive); Key tillKey = new Key(new object[]{def, range.till}, range.tillInclusive); return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp, root.timePropIndex.GetEnumerator(fromKey, tillKey)); } else { Key fromKey = new Key(new object[]{def, range.from}, range.fromInclusive); Key tillKey = new Key(new object[]{def, range.till}, range.tillInclusive); return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp, root.strPropIndex.GetEnumerator(fromKey, tillKey)); } } else if (val is string) { string str = (string)val; int wc = str.IndexOf('*'); if (wc < 0) { Key key = new Key(new object[]{def, str}); return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp, root.strPropIndex.GetEnumerator(key, key)); } else if (wc > 0) { string prefix = str.Substring(0, wc); Key fromKey = new Key(new object[]{def, prefix}); Key tillKey = new Key(new object[]{def, prefix + Char.MaxValue}, false); return new SearchResult(root, typeVh, uri, wc == str.Length-1 ? restOfPatterns : patterns, kind, timestamp, root.strPropIndex.GetEnumerator(fromKey, tillKey)); } } else if (val is double) { Key key = new Key(new object[]{def, val}); return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp, root.numPropIndex.GetEnumerator(key, key)); } else if (val is DateTime) { Key key = new Key(new object[]{def, val}); return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp, root.timePropIndex.GetEnumerator(key, key)); } else if (val is NameVal) { IEnumerable iterator = SearchReferenceProperty(typeVh, uri, patterns, kind, timestamp, (NameVal)val, false, def, new ArrayList()); if (iterator != null) { return iterator; } } else if (val is NameVal[]) { NameVal[] props = (NameVal[])val; if (props.Length > 0) { IEnumerable iterator = SearchReferenceProperty(typeVh, uri, patterns, kind, timestamp, props[0], props.Length > 1, def, new ArrayList()); if (iterator != null) { return iterator; } } } } if (kind == SearchKind.LatestVersion) { return new SearchResult(root, typeVh, uri, patterns, kind, timestamp, root.latest.GetEnumerator()); } return new SearchResult(root, typeVh, uri, patterns, kind, timestamp, root.timeIndex.GetEnumerator()); } finally { root.Unlock(); } }
/// <summary> /// Checks if this rectangle intersects with specified rectangle /// </summary> public bool Intersects(RectangleR2 r) { return _left <= r._right && _top <= r._bottom && _right >= r._left && _bottom >= r._top; }
private IEnumerable SearchReferenceProperty(VersionHistory type, string uri, NameVal[] patterns, SearchKind kind, DateTime timestamp, NameVal prop, bool compound, PropDef def, ArrayList refs) { refs.Add(def); NameVal[] restOfPatterns = compound ? patterns : SubArray(patterns); object val = prop.val; switch (prop.name) { case Symbols.Timestamp: if (val is Range) { Range range = (Range)val; if (range.from is DateTime) { Key fromKey = new Key((DateTime)range.from, range.fromInclusive); Key tillKey = new Key((DateTime)range.till, range.tillInclusive); return new SearchResult(root, type, uri, restOfPatterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), root.timeIndex.GetEnumerator(fromKey, tillKey), kind, timestamp)); } } else if (val is DateTime) { Key key = new Key((DateTime)val); return new SearchResult(root, type, uri, restOfPatterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), root.timeIndex.GetEnumerator(key, key), kind, timestamp)); } return new object[0]; // empty selection case Symbols.Rectangle: if (val is NameVal[]) { NameVal[] coord = (NameVal[])val; if (coord.Length == 4) { RectangleR2 r = new RectangleR2((double)coord[0].val, (double)coord[1].val, (double)coord[2].val, (double)coord[3].val); return new SearchResult(root, type, uri, restOfPatterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), root.spatialIndex.Overlaps(r).GetEnumerator(), kind, timestamp)); } } break; case Symbols.Point: if (val is NameVal[]) { NameVal[] coord = (NameVal[])val; if (coord.Length == 2) { double x = (double)coord[0].val; double y = (double)coord[1].val; RectangleR2 r = new RectangleR2(x, y, x, y); return new SearchResult(root, type, uri, restOfPatterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), root.spatialIndex.Overlaps(r).GetEnumerator(), kind, timestamp)); } } break; case Symbols.Keyword: if (val is string) { ArrayList keywords = new ArrayList(); foreach (string keyword in ((string)val).ToLower().Split(keywordSeparators)) { if (keyword.Length > 0 && !keywordStopList.ContainsKey(keyword)) { keywords.Add(keyword); } } IEnumerator[] occurences = new IEnumerator[keywords.Count]; for (int i = 0; i < occurences.Length; i++) { Key key = new Key((string)keywords[i]); occurences[i] = root.inverseIndex.GetEnumerator(key, key); } return new SearchResult(root, type, uri, restOfPatterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), db.Merge(occurences), kind, timestamp)); } break; } def = (PropDef)root.propDefIndex[prop.name]; if (def == null) { return new object[0]; // empty selection } if (val is Range) { Range range = (Range)val; if (range.from is double) { Key fromKey = new Key(new object[]{def, range.from}, range.fromInclusive); Key tillKey = new Key(new object[]{def, range.till}, range.tillInclusive); return new SearchResult(root, type, uri, restOfPatterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), root.numPropIndex.GetEnumerator(fromKey, tillKey), kind, timestamp)); } else if (range.from is DateTime) { Key fromKey = new Key(new object[]{def, range.from}, range.fromInclusive); Key tillKey = new Key(new object[]{def, range.till}, range.tillInclusive); return new SearchResult(root, type, uri, restOfPatterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), root.timePropIndex.GetEnumerator(fromKey, tillKey), kind, timestamp)); } else { Key fromKey = new Key(new object[]{def, range.from}, range.fromInclusive); Key tillKey = new Key(new object[]{def, range.till}, range.tillInclusive); return new SearchResult(root, type, uri, restOfPatterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), root.strPropIndex.GetEnumerator(fromKey, tillKey), kind, timestamp)); } } if (val is string) { string str = (string)prop.val; int wc = str.IndexOf('*'); if (wc < 0) { Key key = new Key(new object[]{def, str}); return new SearchResult(root, type, uri, restOfPatterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), root.strPropIndex.GetEnumerator(key, key), kind, timestamp)); } else if (wc > 0) { string prefix = str.Substring(0, wc); Key fromKey = new Key(new object[]{def, prefix}); Key tillKey = new Key(new object[]{def, prefix + Char.MaxValue}, false); return new SearchResult(root, type, uri, wc == str.Length-1 ? restOfPatterns : patterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), root.strPropIndex.GetEnumerator(fromKey, tillKey), kind, timestamp)); } } else if (val is double) { Key key = new Key(new object[]{def, val}); return new SearchResult(root, type, uri, restOfPatterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), root.numPropIndex.GetEnumerator(key, key), kind, timestamp)); } else if (val is DateTime) { Key key = new Key(new object[]{def, (DateTime)val}); return new SearchResult(root, type, uri, restOfPatterns, kind, timestamp, new ReferenceIterator(root, (PropDef[])refs.ToArray(typeof(PropDef)), root.timePropIndex.GetEnumerator(key, key), kind, timestamp)); } else if (val is NameVal) { return SearchReferenceProperty(type, uri, patterns, kind, timestamp, (NameVal)val, compound, def, refs); } else if (val is NameVal[]) { NameVal[] props = (NameVal[])val; if (props.Length > 0) { return SearchReferenceProperty(type, uri, patterns, kind, timestamp, props[0], true, def, refs); } } return null; }
RtreeR2Page splitPage(Storage storage, RectangleR2 r, object obj) { int i, j, seed0 = 0, seed1 = 0; double[] rectArea = new double[card+1]; double waste; double worstWaste = Double.MinValue; // // As the seeds for the two groups, find two rectangles which waste // the most area if covered by a single rectangle. // rectArea[0] = r.Area(); for (i = 0; i < card; i++) { rectArea[i+1] = b[i].Area(); } RectangleR2 bp = r; for (i = 0; i < card; i++) { for (j = i+1; j <= card; j++) { waste = RectangleR2.JoinArea(bp, b[j-1]) - rectArea[i] - rectArea[j]; if (waste > worstWaste) { worstWaste = waste; seed0 = i; seed1 = j; } } bp = b[i]; } byte[] taken = new byte[card]; RectangleR2 group0, group1; double groupArea0, groupArea1; int groupCard0, groupCard1; RtreeR2Page pg; taken[seed1-1] = 2; group1 = new RectangleR2(b[seed1-1]); if (seed0 == 0) { group0 = new RectangleR2(r); pg = new RtreeR2Page(storage, obj, r); } else { group0 = new RectangleR2(b[seed0-1]); pg = new RtreeR2Page(storage, branch.GetRaw(seed0-1), group0); setBranch(seed0-1, r, obj); } groupCard0 = groupCard1 = 1; groupArea0 = rectArea[seed0]; groupArea1 = rectArea[seed1]; // // Split remaining rectangles between two groups. // The one chosen is the one with the greatest difference in area // expansion depending on which group - the rect most strongly // attracted to one group and repelled from the other. // while (groupCard0 + groupCard1 < card + 1 && groupCard0 < card + 1 - minFill && groupCard1 < card + 1 - minFill) { int betterGroup = -1, chosen = -1; double biggestDiff = -1; for (i = 0; i < card; i++) { if (taken[i] == 0) { double diff = (RectangleR2.JoinArea(group0, b[i]) - groupArea0) - (RectangleR2.JoinArea(group1, b[i]) - groupArea1); if (diff > biggestDiff || -diff > biggestDiff) { chosen = i; if (diff < 0) { betterGroup = 0; biggestDiff = -diff; } else { betterGroup = 1; biggestDiff = diff; } } } } Debug.Assert(chosen >= 0); if (betterGroup == 0) { group0.Join(b[chosen]); groupArea0 = group0.Area(); taken[chosen] = 1; pg.setBranch(groupCard0++, b[chosen], branch.GetRaw(chosen)); } else { groupCard1 += 1; group1.Join(b[chosen]); groupArea1 = group1.Area(); taken[chosen] = 2; } } // // If one group gets too full, then remaining rectangle are // split between two groups in such way to balance cards of two groups. // if (groupCard0 + groupCard1 < card + 1) { for (i = 0; i < card; i++) { if (taken[i] == 0) { if (groupCard0 >= groupCard1) { taken[i] = 2; groupCard1 += 1; } else { taken[i] = 1; pg.setBranch(groupCard0++, b[i], branch.GetRaw(i)); } } } } pg.n = groupCard0; n = groupCard1; for (i = 0, j = 0; i < groupCard1; j++) { if (taken[j] == 2) { setBranch(i++, b[j], branch.GetRaw(j)); } } // truncate rest of link branch.Length = groupCard1; branch.Length = card; return pg; }
private Thing CreateObject(Thing type, VersionHistory vh, NameVal[] props) { Thing thing = new Thing(); thing.vh = vh; thing.type = type; thing.timestamp = DateTime.Now; thing.props = new PropVal[props.Length]; for (int i = 0; i < props.Length; i++) { NameVal prop = props[i]; PropDef def = (PropDef)root.propDefIndex[prop.name]; if (def == null) { def = new PropDef(); def.name = prop.name; root.propDefIndex.Put(def); } object val = prop.val; PropVal pv = new PropVal(def, val); Key key = new Key(new object[]{def, val}); if (val is string) { root.strPropIndex.Put(key, thing); foreach (string keyword in ((string)val).ToLower().Split(keywordSeparators)) { if (keyword.Length > 0 && !keywordStopList.ContainsKey(keyword)) { root.inverseIndex.Put(keyword, thing); } } } else if (val is double) { root.numPropIndex.Put(key, thing); } else if (val is DateTime) { root.timePropIndex.Put(key, thing); } else if (val is VersionHistory || val == null) { root.refPropIndex.Put(key, thing); if (prop.name == Symbols.Rectangle) { PropVal[] coord = ((VersionHistory)val).Latest.props; RectangleR2 r = new RectangleR2((double)coord[0].val, (double)coord[1].val, (double)coord[2].val, (double)coord[3].val); root.spatialIndex.Put(r, thing); } else if (prop.name == Symbols.Point) { PropVal[] coord = ((VersionHistory)val).Latest.props; double x = (double)coord[0].val; double y = (double)coord[1].val; RectangleR2 r = new RectangleR2(x, y, x, y); root.spatialIndex.Put(r, thing); } } else { throw new InvalidOperationException("Invalid propery value type " + prop.val.GetType()); } thing.props[i] = pv; } thing.Modify(); vh.versions.Add(thing); root.timeIndex.Put(thing); root.latest.Add(thing); return thing; }