/// <summary> /// Resizing the <paramref name="idx"/> layer (0 is top most layer) to have new length of <paramref name="newLength"/> /// </summary> /// <param name="idx">zero-based. 0 is on top, regardless annotation direction</param> /// <param name="newLength">in meteres</param> /// <param name="fromButtomToUp"></param> public void SetLayerLength(int idx, double newLength, AnnotationDirection direction) { double[] newDepthBoundaries = LayerLengthEditWithShift(depthBoundaries, idx, newLength, direction); if (newDepthBoundaries.Length < depthBoundaries.Length) { //layer removals is required (as they are pushed out) int toRemove = depthBoundaries.Length - newDepthBoundaries.Length; switch (direction) { case AnnotationDirection.UpToBottom: for (int i = 0; i < toRemove; i++) { RemoveLayer(depthBoundaries.Length - 2, FreeSpaceAccepter.UpperLayer); } break; case AnnotationDirection.BottomToUp: for (int i = 0; i < toRemove; i++) { RemoveLayer(0, FreeSpaceAccepter.LowerLayer); } break; default: throw new NotSupportedException("unexpected annotation direction"); } } //now appling new depths System.Diagnostics.Debug.Assert(depthBoundaries.Length == newDepthBoundaries.Length); depthBoundaries = newDepthBoundaries; ResetAllcolumns(); }
/// <param name="wpfHeight">The column height in WPF units</param> public LayerBoundaryEditorVM(double wpfHeight, int maxRank, AnnotationDirection annotationDirection) { Boundaries = new LayerBoundary[] { new LayerBoundary(0.0, maxRank), new LayerBoundary(wpfHeight, maxRank) }; AnnotationDirection = annotationDirection; }
/// <summary> /// Fills in Number array of each boundary with respect to the annotation direction /// </summary> /// <param name="boundaries">Including outer boundaries of the first and last layer</param> /// <returns></returns> public static void RecalcBoundaryNumbers(LayerBoundary[] boundaries, AnnotationDirection direction) { if (boundaries.Length == 0) { return; } //asserting conditions int maxRank = boundaries.Select(b => b.Rank).Max(); if (boundaries[0].Rank != maxRank) { new ArgumentException("the first boundary must be outer boundaries having the max rank"); } if (boundaries[boundaries.Length - 1].Rank != maxRank) { new ArgumentException("the last boundary must be outer boundaries having the max rank"); } int N = boundaries.Length; int[] recentNumbers = Enumerable.Repeat(0, maxRank + 1).ToArray(); switch (direction) { case AnnotationDirection.UpToBottom: for (int i = 0; i < N; i++) { LayerBoundary lb = boundaries[i]; int maxIdxToAccount = lb.Rank; //updating recent numbers recentNumbers[maxIdxToAccount]++; //highest rank number increases for (int j = 0; j < maxIdxToAccount; j++) { recentNumbers[j] = 1; //lower numbers reset ot 1 } //now copying the part of the recentNumbers to the lb.Number lb.Numbers = recentNumbers.Take(maxIdxToAccount + 1).ToArray(); } break; case AnnotationDirection.BottomToUp: for (int i = N - 1; i >= 0; i--) { LayerBoundary lb = boundaries[i]; if (i == N - 1) { //lower boundary always contains all zeros, thus skipping it lb.Numbers = recentNumbers.ToArray(); continue; } int maxIdxToAccount = lb.Rank; //updating recent numbers for (int j = 0; j <= maxIdxToAccount; j++) { recentNumbers[j]++; } //coping updated recent to the boundary lb.Numbers = recentNumbers.Take(maxIdxToAccount + 1).ToArray(); //reseting lower rank recent numbers for (int j = 0; j < maxIdxToAccount; j++) { recentNumbers[j] = 0; } } break; default: throw new NotSupportedException(); break; } return; }
/// <summary> /// Forms a table by filling it with supplied data /// </summary> /// <param name="intervals"></param> /// <param name="boundaries">including the "outer boundaries" of bounding layer</param> /// <param name="layers"></param> /// <param name="isDepthIncreases">true if depth increases (other parameter arrays are sorted so the depth increases)</param> /// <param name="samples">All samples in the project</param> /// <returns></returns> public static CSV.ReportTable GenerateCVSTableContents( Intervals.BoreIntervalVM[] intervals, RTF.LayerBoundary[] boundaries, RTF.LayerDescrition[] layers, string[] rankNames, RTF.Sample[] samples, AnnotationDirection annotationDirection, AnnotationPlane.Template.Property[] allProperties, string[] genRankNames ) { List <KeyValuePair <double, int> > intBounds = new List <KeyValuePair <double, int> >(); for (int i = 0; i < intervals.Length; i++) { Intervals.BoreIntervalVM interval = intervals[i]; if (interval.LowerDepth < interval.UpperDepth) { throw new ArgumentException("The upper bound is lower than lower bound"); } intBounds.Add(new KeyValuePair <double, int>(interval.UpperDepth, 1)); intBounds.Add(new KeyValuePair <double, int>(interval.LowerDepth, -1)); } double[] keys = intBounds.Select(kvp => kvp.Key).ToArray(); foreach (int key in keys) { int curKeyValsSum = intBounds.Where(kvp => kvp.Key == key).Sum(kvp => kvp.Value); if (curKeyValsSum == 0) { intBounds = intBounds.Where(kvp => kvp.Key != key).ToList(); } } int[] events = intBounds.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToArray(); int sum = 0; for (int i = 0; i < events.Length; i++) { sum += events[i]; if (Math.Abs(sum) > 1) { throw new InvalidOperationException("You've passed intersecting intervals"); } } List <CSV.ReportRow> rows = new List <CSV.ReportRow>(); if (boundaries.Length - 1 != layers.Length) { throw new ArgumentException("Layers count must be exactly one more than boundary count"); } string directionString = string.Empty; switch (annotationDirection) { case AnnotationDirection.UpToBottom: directionString = "сверху вниз"; break; case AnnotationDirection.BottomToUp: directionString = "снизу вверх"; break; } List <string> allColumnsList = new List <string>(); allColumnsList.Add("№ " + genRankNames[0]); allColumnsList.Add("№ " + genRankNames[1]); allColumnsList.Add("№ " + genRankNames[2]); allColumnsList.Add("Верхняя граница слоя (м)"); allColumnsList.Add("Нижняя граница слоя (м)"); foreach (AnnotationPlane.Template.Property prop in allProperties) { allColumnsList.Add(string.IsNullOrEmpty(prop.Name) ? prop.Name : prop.ID); } CSV.ReportRow header = new CSV.ReportRow(allColumnsList.ToArray()); rows.Add(header); int reportedInIndex; int inIndex; int laIndex; int layerOrderNum; int group_number = 1; int pack_number = 1; switch (annotationDirection) { case AnnotationDirection.UpToBottom: intervals = intervals.OrderBy(i => i.UpperDepth).ToArray(); for (int i = 0; i < boundaries.Length - 1; i++) { if (boundaries[i + 1].Depth < boundaries[i].Depth) { throw new NotSupportedException("Boundary depths must increase"); } } reportedInIndex = -1; inIndex = 0; laIndex = 0; layerOrderNum = 1; while (inIndex < intervals.Length && laIndex < layers.Length) { if (reportedInIndex != inIndex) { reportedInIndex = inIndex; } RTF.LayerBoundary upperLabound = boundaries[laIndex]; double curLaUpper = upperLabound.Depth; double curLaLower = boundaries[laIndex + 1].Depth; double curIntUpper = intervals[inIndex].UpperDepth; double curIntLower = intervals[inIndex].UpperDepth + intervals[inIndex].ExtractedLength; bool doInInc = false; bool doLaInc = false; bool skipReporting = false; if (curIntLower >= curLaLower) { if (curIntUpper > curLaLower) { skipReporting = true; } else { if (curIntUpper > curLaUpper) { curLaUpper = curIntUpper; } } doLaInc = true; } else { curLaLower = curIntLower; if (curIntUpper > curLaUpper) { curLaUpper = curIntUpper; } doInInc = true; } List <int> group_pack = GetGroupPackNumbersForUpperLaBound(upperLabound, laIndex, boundaries, curIntLower, rankNames); switch (upperLabound.Rank) { case 2: group_number = group_pack[0]; pack_number = 1; layerOrderNum = 1; break; case 1: pack_number = group_pack[0]; layerOrderNum = 1; break; default: break; } if (!skipReporting) { var layerSamples = samples.Where(s => (s.Depth > curLaUpper) && (s.Depth < curLaLower)).ToArray(); rows.Add(GetLayerDescrRow(layerOrderNum++, curLaLower, curLaUpper, layers[laIndex], layerSamples, group_number, pack_number, allProperties)); } if (doLaInc) { laIndex++; } if (doInInc) { inIndex++; } } break; case AnnotationDirection.BottomToUp: intervals = intervals.OrderBy(i => i.UpperDepth).ToArray(); for (int i = boundaries.Length - 2; i >= 0; i--) { if (boundaries[i + 1].Depth < boundaries[i].Depth) { throw new NotSupportedException("Boundary depths must increase"); } } reportedInIndex = intervals.Length; inIndex = intervals.Length - 1; laIndex = layers.Length - 1; layerOrderNum = 1; while (inIndex >= 0 && laIndex >= 0) { if (reportedInIndex != inIndex) { reportedInIndex = inIndex; } RTF.LayerBoundary upperLabound = boundaries[laIndex]; RTF.LayerBoundary lowerLaBound = boundaries[laIndex + 1]; double curLaUpper = upperLabound.Depth; double curLaLower = boundaries[laIndex + 1].Depth; double curIntUpper = intervals[inIndex].UpperDepth; double curIntLower = intervals[inIndex].UpperDepth + intervals[inIndex].ExtractedLength; bool doInDec = false; bool doLaDec = false; bool skipReporting = false; if (curIntUpper <= curLaUpper) { if (curIntLower < curLaUpper) { skipReporting = true; } else { if (curIntLower < curLaLower) { curLaLower = curIntLower; } } doLaDec = true; } else { curLaUpper = curIntUpper; if (curIntLower < curLaLower) { curLaLower = curIntLower; } doInDec = true; } if (!skipReporting) { List <int> group_pack = GetGroupPackNumbersForLowerLaBound(lowerLaBound, laIndex, boundaries, curIntUpper, rankNames); switch (lowerLaBound.Rank) { case 2: group_number = group_pack[0]; pack_number = group_pack[1]; layerOrderNum = 1; break; case 1: pack_number = group_pack[0]; layerOrderNum = 1; break; default: break; } var layerSamples = samples.Where(s => (s.Depth > curLaUpper) && (s.Depth < curLaLower)).ToArray(); rows.Add(GetLayerDescrRow(layerOrderNum++, curLaLower, curLaUpper, layers[laIndex], layerSamples, group_number, pack_number, allProperties)); } if (doLaDec) { laIndex--; } if (doInDec) { inIndex--; } } break; default: throw new NotSupportedException(); } return(new CSV.ReportTable(rows.ToArray())); }
/// <summary> /// Forms a table by filling it with supplied data /// </summary> /// <param name="boundaries">including the "outer boundaries" of bounding layer</param> /// <param name="layers"></param> /// <param name="isDepthIncreases">true if depth increases (other parameter arrays are sorted so the depth increases)</param> /// <returns></returns> public static CSV.ReportTable GenerateCVSTableContents( RTF.LayerBoundary[] boundaries, RTF.LayerDescrition[] layers, AnnotationDirection annotationDirection, AnnotationPlane.Template.Property[] allProperties, string[] genRankNames ) { List <CSV.ReportRow> rows = new List <CSV.ReportRow>(); if (boundaries.Length - 1 != layers.Length) { throw new ArgumentException("Layers count must be exactly one more than boundary count"); } List <string> allColumnsList = new List <string>(); for (int i = genRankNames.Length - 1; i >= 0; i--) { allColumnsList.Add(string.Format("№ {0}", genRankNames[i])); } allColumnsList.Add("Верхняя граница слоя (м)"); allColumnsList.Add("Нижняя граница слоя (м)"); foreach (AnnotationPlane.Template.Property prop in allProperties) { allColumnsList.Add(string.IsNullOrEmpty(prop.Name) ? prop.Name : prop.ID); } CSV.ReportRow header = new CSV.ReportRow(allColumnsList.ToArray()); rows.Add(header); int[] ranksNumbers = Enumerable.Repeat(1, genRankNames.Length).ToArray(); switch (annotationDirection) { case AnnotationDirection.UpToBottom: for (int i = 0; i < layers.Length; i++) { for (int j = 0; j < boundaries[i].OrderNumbers.Length; j++) { ranksNumbers[j] = boundaries[i].OrderNumbers[j]; } rows.Add(GetLayerDescrRow(boundaries[i + 1].Depth, boundaries[i].Depth, layers[i], ranksNumbers, allProperties)); } break; case AnnotationDirection.BottomToUp: for (int i = layers.Length - 1; i >= 0; i--) { rows.Add(GetLayerDescrRow(boundaries[i + 1].Depth, boundaries[i].Depth, layers[i], ranksNumbers, allProperties)); ranksNumbers[boundaries[i].OrderNumbers.Length - 1] = boundaries[i].OrderNumbers[boundaries[i].OrderNumbers.Length - 1] + 1; for (int j = 0; j < boundaries[i].OrderNumbers.Length - 1; j++) { ranksNumbers[j] = 1; } } break; default: throw new NotSupportedException(); } return(new CSV.ReportTable(rows.ToArray())); }
/// <summary> /// Forms a table by filling it with supplied data /// </summary> /// <param name="boundaries">including the "outer boundaries" of bounding layer</param> /// <param name="samples">All samples in the project</param> /// <returns></returns> public static ReportTable GenerateTableContents( Intervals.BoreIntervalVM[] intervals, LayerBoundary[] boundaries, LayerDescrition[] layers, string[] rankNames, Sample[] samples, AnnotationDirection annotationDirection) { //asserting intervals //lower - upper bounds order //intersection check List <KeyValuePair <double, int> > intBounds = new List <KeyValuePair <double, int> >(); for (int i = 0; i < intervals.Length; i++) { Intervals.BoreIntervalVM interval = intervals[i]; if (interval.LowerDepth < interval.UpperDepth) { throw new ArgumentException("The upper bound is lower than lower bound"); } intBounds.Add(new KeyValuePair <double, int>(interval.UpperDepth, 1)); // +1 opens the interval intBounds.Add(new KeyValuePair <double, int>(interval.LowerDepth, -1)); // -1 closes the interval } // detecting intervals with touching bounds; removing these bounds double[] keys = intBounds.Select(kvp => kvp.Key).ToArray(); foreach (int key in keys) { int curKeyValsSum = intBounds.Where(kvp => kvp.Key == key).Sum(kvp => kvp.Value); if (curKeyValsSum == 0) { intBounds = intBounds.Where(kvp => kvp.Key != key).ToList(); } } int[] events = intBounds.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToArray(); int sum = 0; for (int i = 0; i < events.Length; i++) { sum += events[i]; if (Math.Abs(sum) > 1) { throw new InvalidOperationException("You've passed intersecting intervals"); } } List <ReportRow> rows = new List <ReportRow>(); if (boundaries.Length - 1 != layers.Length) { throw new ArgumentException("Layers count must be exactly one more than boundary count"); } string directionString = string.Empty; switch (annotationDirection) { case AnnotationDirection.UpToBottom: directionString = "сверху вниз"; break; case AnnotationDirection.BottomToUp: directionString = "снизу вверх"; break; } ReportRow header = new ReportRow( new TextCell[] { new TextCell( string.Format("Описание керна {0}.\nИнтервал / выход керна в м.", directionString), LeftColWidth, horizontalAlignement: TextAlignement.Centered, isBold: true), new TextCell("место отбора от начала керна, м; описание", RightcolWidth, horizontalAlignement: TextAlignement.Centered, isBold: true) }); rows.Add(header); int reportedInIndex; int inIndex; int laIndex; int layerOrderNum; //for now works with increasing depths order switch (annotationDirection) { case AnnotationDirection.UpToBottom: intervals = intervals.OrderBy(i => i.UpperDepth).ToArray(); for (int i = 0; i < boundaries.Length - 1; i++) { if (boundaries[i + 1].Depth < boundaries[i].Depth) { throw new NotSupportedException("Boundary depths must increase"); } } reportedInIndex = -1; inIndex = 0; laIndex = 0; layerOrderNum = 1; while (inIndex < intervals.Length && laIndex < layers.Length) { if (reportedInIndex != inIndex) { //adding row depicting interval start rows.Add(GetIntervalRow(intervals[inIndex].UpperDepth, intervals[inIndex].LowerDepth, intervals[inIndex].ExtractedLength)); reportedInIndex = inIndex; } LayerBoundary upperLabound = boundaries[laIndex]; double curLaUpper = upperLabound.Depth; double curLaLower = boundaries[laIndex + 1].Depth; //boundraies array always contains one more element than layers double curIntUpper = intervals[inIndex].UpperDepth; double curIntLower = intervals[inIndex].UpperDepth + intervals[inIndex].ExtractedLength; bool doInInc = false; bool doLaInc = false; bool skipReporting = false; //analysing the relative position of the interval and the layer if (curIntLower >= curLaLower) { //the interval includes the end of the layer or interval is entirly below the layer if (curIntUpper > curLaLower) { //the entire interal is below the layer skipReporting = true; //the layer is not reported } else { if (curIntUpper > curLaUpper) { //coersing layer upper bound to match interval curLaUpper = curIntUpper; } } doLaInc = true; } else { //the layer includes the end of the interval curLaLower = curIntLower; //coersing layer lower bound to match interval if (curIntUpper > curLaUpper) { //coersing layer upper bound to match interval curLaUpper = curIntUpper; } doInInc = true; } if (!skipReporting) { if (upperLabound.Rank > 0) { //we need to add rank row for (int rank = upperLabound.Rank; rank > 0; rank--) { double length = 0.0; //calculating total length. starting from cur bound till the next bound of the same rank or higher for (int i = laIndex + 1; i < boundaries.Length; i++) { int curRank = boundaries[i].Rank; length += boundaries[i].Depth - boundaries[i - 1].Depth; if (curRank >= rank) { break; } } length = Math.Min(length, curIntLower - upperLabound.Depth); rows.Add(GetRankDescrRow(upperLabound.OrderNumbers[rank], rankNames[rank], length)); } layerOrderNum = 1; //ranks higher than 0 reset the numbering of layers } var layerSamples = samples.Where(s => (s.Depth > curLaUpper) && (s.Depth < curLaLower)).ToArray(); rows.Add(GetLayerDescrRow(layerOrderNum++, curLaLower - curLaUpper, layers[laIndex], layerSamples)); } if (doLaInc) { laIndex++; } if (doInInc) { inIndex++; } } break; case AnnotationDirection.BottomToUp: intervals = intervals.OrderBy(i => i.UpperDepth).ToArray(); for (int i = boundaries.Length - 2; i >= 0; i--) { if (boundaries[i + 1].Depth < boundaries[i].Depth) { throw new NotSupportedException("Boundary depths must increase"); } } reportedInIndex = intervals.Length; inIndex = intervals.Length - 1; laIndex = layers.Length - 1; layerOrderNum = 1; //while (inIndex < intervals.Length && laIndex < layers.Length) while (inIndex >= 0 && laIndex >= 0) { if (reportedInIndex != inIndex) { //adding row depicting interval start rows.Add(GetIntervalRow(intervals[inIndex].UpperDepth, intervals[inIndex].LowerDepth, intervals[inIndex].ExtractedLength)); reportedInIndex = inIndex; } LayerBoundary upperLabound = boundaries[laIndex]; LayerBoundary lowerLaBound = boundaries[laIndex + 1]; double curLaUpper = upperLabound.Depth; double curLaLower = boundaries[laIndex + 1].Depth; //boundraies array always contains one more element than layers double curIntUpper = intervals[inIndex].UpperDepth; double curIntLower = intervals[inIndex].UpperDepth + intervals[inIndex].ExtractedLength; bool doInDec = false; bool doLaDec = false; bool skipReporting = false; //analysing the relative position of the interval and the layer //if (curIntLower >= curLaLower) if (curIntUpper <= curLaUpper) { //the interval includes the end of the layer or interval is entirly alte the layer //if (curIntUpper > curLaLower) if (curIntLower < curLaUpper) { //the entire interal is after the layer skipReporting = true; //the layer is not reported } else { //if (curIntUpper > curLaUpper) if (curIntLower < curLaLower) { //coersing layer lower bound to match interval //curLaUpper = curIntUpper; curLaLower = curIntLower; } } doLaDec = true; } else { //the layer includes the end of the interval //curLaLower = curIntLower; //coersing layer lower bound to match interval curLaUpper = curIntUpper; //coersing layer upper bound to match interval //if (curIntUpper > curLaUpper) if (curIntLower < curLaLower) { //coersing layer lower bound to match interval //curLaUpper = curIntUpper; curLaLower = curIntLower; } doInDec = true; } if (!skipReporting) { //if (upperLabound.Rank > 0) if (lowerLaBound.Rank > 0) { //we need to add rank row for (int rank = lowerLaBound.Rank; rank > 0; rank--) { double length = 0.0; //calculating total length. starting from cur bound till the next bound of the same rank or higher //for (int i = laIndex + 1; i < boundaries.Length; i++) for (int i = laIndex; i >= 0; i--) { int curRank = boundaries[i].Rank; //length += boundaries[i].Depth - boundaries[i - 1].Depth; length += boundaries[i + 1].Depth - boundaries[i].Depth; if (curRank >= rank) { break; } } //length = Math.Min(length, curIntLower - upperLabound.Depth); length = Math.Min(length, lowerLaBound.Depth - curIntUpper); if (rank == lowerLaBound.Rank) { //as the lower boundary contains passed order number, we need to repot the next numbe (incremented by one) rows.Add(GetRankDescrRow(lowerLaBound.OrderNumbers[rank] + 1, rankNames[rank], length)); } else { //passing hight rank bundary means that lower rank numberings reset rows.Add(GetRankDescrRow(1, rankNames[rank], length)); } } layerOrderNum = 1; //ranks higher than 0 reset the numbering of layers } var layerSamples = samples.Where(s => (s.Depth > curLaUpper) && (s.Depth < curLaLower)).ToArray(); rows.Add(GetLayerDescrRow(layerOrderNum++, curLaLower - curLaUpper, layers[laIndex], layerSamples)); } if (doLaDec) { laIndex--; } if (doInDec) { inIndex--; } } break; default: throw new NotSupportedException(); break; } return(new ReportTable(rows.ToArray())); }
/// <param name="idx">layer index. zero based. zero index is always the upper one</param> /// <returns>new depths</returns> public static double[] LayerLengthEditWithShift(double[] depths, int idx, double newLength, AnnotationDirection direction) { double[] results; if (newLength < 0) { throw new ArgumentException("newLength must be non-negative"); } if ((idx < 0) || (idx >= depths.Length - 1)) { throw new IndexOutOfRangeException("layer index"); } if (newLength == 0.0) { newLength = MinLayerLength; } switch (direction) { case AnnotationDirection.UpToBottom: if (idx == depths.Length - 2) { //the last layer length can't be edited results = depths.ToArray(); return(results); } double oldLength = depths[idx + 1] - depths[idx]; int initialBoundaryCount = depths.Length; double lowerDepth = depths[initialBoundaryCount - 1]; double addition = newLength - oldLength; int toRemove = 0; double removedLayersLength = 0.0; while ( (depths.Length - 2 - toRemove > idx) && //do not proceed further corrected layer (affect the layers befor the idx) (depths[depths.Length - 1 - toRemove] - depths[depths.Length - 2 - toRemove] + removedLayersLength <= addition)) { removedLayersLength += depths[depths.Length - 1 - toRemove] - depths[depths.Length - 2 - toRemove]; toRemove++; } System.Diagnostics.Trace.WriteLine("{0} layers to remove"); results = depths.Take(initialBoundaryCount - toRemove).ToArray(); for (int i = idx + 1; i < initialBoundaryCount - toRemove - 1; i++) { results[i] += addition; } results[initialBoundaryCount - toRemove - 1] = lowerDepth; break; case AnnotationDirection.BottomToUp: if (idx == 0) { //the last layer length can't be edited results = depths.ToArray(); return(results); } oldLength = depths[idx + 1] - depths[idx]; initialBoundaryCount = depths.Length; double upperDepth = depths[0]; double substraction = newLength - oldLength; toRemove = 0; removedLayersLength = 0.0; while ((idx - toRemove - 1 >= 0) && (depths[idx - toRemove] - depths[idx - toRemove - 1] + removedLayersLength <= substraction)) { removedLayersLength += depths[idx - toRemove] - depths[idx - toRemove - 1]; toRemove++; } System.Diagnostics.Trace.WriteLine("{0} layers to remove"); results = depths.Skip(toRemove).ToArray(); for (int i = idx - toRemove; i > 0; i--) { results[i] -= substraction; } results[0] = upperDepth; break; default: throw new NotSupportedException("unexpected annotatiuon direction"); } return(results); }