/// <summary> /// Overload of BuildJoinedBasins that takes an outlets shape path used for Inlets resolution. If no outlets/inlets path given, it will treat all points as outlets /// </summary> // 2/11/09 rewritten by Chris George to dramatically improve speed: // (a) use utils.ClipPolygon instead of SpatialOperations.MergeShapes // (b) create a binary tree modeling the drainage pattern of the subbasins // (b) merge "upstream-first" using the drainage tree so that each merge combines abutting polygons public static bool BuildJoinedBasins(string subBasinShapePath, string outletsShapePath, string joinBasinShapeResultPath, IProgressHandler callback) { var shapeIdxList = new ArrayList(); BinTree drainage; IFeatureSet outlets = null; if (outletsShapePath != string.Empty) { outlets = FeatureSet.Open(outletsShapePath); } var shed = FeatureSet.Open(subBasinShapePath); var dsNodeFieldNum = -1; var dsShedFieldNum = -1; var us1FieldNum = -1; var us2FieldNum = -1; for (var i = 0; i < shed.DataTable.Columns.Count; i++) { switch (shed.DataTable.Columns[i].ColumnName.ToUpper()) { case "DSNODEID": dsNodeFieldNum = i; break; case "DSWSID": dsShedFieldNum = i; break; case "US1WSID": us1FieldNum = i; break; case "US2WSID": us2FieldNum = i; break; } } //DataManagement.DeleteShapefile(joinBasinShapeResultPath); var newShed = new FeatureSet(); newShed.FeatureType = FeatureType.Polygon; newShed.Filename = joinBasinShapeResultPath; var idfieldnum = AddField(newShed, "MWShapeID", typeof(int)); var linkfieldnum = AddField(newShed, "LinkIDs", typeof(string)); var outletfieldnum = AddField(newShed, "OutletID", typeof(int)); var dswsfieldnum = AddField(newShed, "DSWSID", typeof(int)); var uswsfieldnum1 = AddField(newShed, "USWSID1", typeof(int)); var uswsfieldnum2 = AddField(newShed, "USWSID2", typeof(int)); var reservoirfieldnum = AddField(newShed, "Reservoir", typeof(int)); var oldperc = 0; for (var sindx = 0; sindx < shed.NumRows(); sindx++) { if (shed.NumRows() > 1) { var newperc = Convert.ToInt32((Convert.ToDouble(sindx) / Convert.ToDouble(shed.NumRows())) * 100); if (newperc > oldperc) { if (callback != null) { callback.Progress("Status", newperc, "Merging Watersheds to Outlets/Inlets"); } oldperc = newperc; } } DSNode dsNodeType = DSNode.Outlet; var dsNodeVal = int.Parse(shed.get_CellValue(dsNodeFieldNum, sindx).ToString()); if (dsNodeVal > -1) { // an outlet, inlet, reservoir or point source if (outletsShapePath == string.Empty) { // assume this is an outlet drainage = getDrainageFromSubbasin(shed, outlets, false, true, sindx, dsNodeFieldNum, us1FieldNum, us2FieldNum); } else { dsNodeType = getDSNodeType(outlets, dsNodeVal); if ((dsNodeType == DSNode.Outlet) || (dsNodeType == DSNode.Reservoir)) { if (isUpstreamOfInlet(shed, outlets, sindx)) { drainage = null; } else { drainage = getDrainageFromSubbasin(shed, outlets, true, true, sindx, dsNodeFieldNum, us1FieldNum, us2FieldNum); } } else { // ignore inlets and point sources drainage = null; } } shapeIdxList.Clear(); if (drainage != null) { char[] sep = { ',' }; var idxs = drainage.ToString().Split(sep); for (var i = 0; i < idxs.Length; i++) { shapeIdxList.Add(idxs[i]); } } if (shapeIdxList.Count != 0) { IFeature mergeShape; string strLinks; if (shapeIdxList.Count == 1) { mergeShape = shed.get_Shape(int.Parse(shapeIdxList[0].ToString())); strLinks = shed.get_CellValue(0, int.Parse(shapeIdxList[0].ToString())).ToString(); } else { strLinks = shed.get_CellValue(0, int.Parse(shapeIdxList[0].ToString())).ToString(); for (int i = 1; i <= shapeIdxList.Count - 1; i++) { strLinks = strLinks + ", " + shed.get_CellValue(0, int.Parse(shapeIdxList[i].ToString())); } DateTime time = DateTime.Now; mergeShape = mergeBasinsByDrainage(shed, drainage); var elapsed = DateTime.Now.Subtract(time); Trace.WriteLine("Made merged watershed of " + shapeIdxList.Count + " subbasins in " + elapsed.TotalSeconds.ToString("F1") + " seconds"); } // Check merged shape for single part and clockwise if (mergeShape.NumGeometries > 1) { Trace.WriteLine("Merged polygon has " + mergeShape.NumGeometries + " parts"); } else { var area = SignedArea(mergeShape); if (area < 0) { Trace.WriteLine("Needed to reverse merged polygon"); mergeShape = ReverseShape(mergeShape); } } var currshpidx = newShed.NumRows(); newShed.AddFeature(mergeShape); newShed.EditCellValue(idfieldnum, currshpidx, currshpidx); newShed.EditCellValue(linkfieldnum, currshpidx, strLinks); newShed.EditCellValue(outletfieldnum, currshpidx, dsNodeVal); if (int.Parse(shed.get_CellValue(dsShedFieldNum, sindx).ToString()) != -1) { newShed.EditCellValue(dswsfieldnum, currshpidx, shed.get_CellValue(dsShedFieldNum, sindx)); } else { newShed.EditCellValue(dswsfieldnum, currshpidx, -1); } newShed.EditCellValue(uswsfieldnum1, currshpidx, -1); newShed.EditCellValue(uswsfieldnum2, currshpidx, -1); if (dsNodeType == DSNode.Reservoir) { newShed.EditCellValue(reservoirfieldnum, currshpidx, 1); } else { newShed.EditCellValue(reservoirfieldnum, currshpidx, 0); } } } } buildMergeDownstreamUpStream(newShed, idfieldnum, linkfieldnum, dswsfieldnum, uswsfieldnum1, uswsfieldnum2); newShed.Projection = shed.Projection; shed.Close(); newShed.Save(); newShed.Close(); if (outletsShapePath != string.Empty) { outlets.Close(); } if (callback != null) { callback.Progress(string.Empty, 0, string.Empty); } return true; }