// ****************************************************************** protected override void SetQuadrantLimits() { T firstPoint = this._listOfListOfPoint.First().First(); double rightX = _xGet(firstPoint); double rightY = _yGet(firstPoint); double topX = rightX; double topY = rightY; foreach (var enumOfPoints in _listOfListOfPoint) { foreach (var point in enumOfPoints) { if (_xGet(point).LargerOrEqualWithTol(rightX)) { if (_xGet(point).EqualsWithTol(rightX)) { if (_yGet(point).LargerWithTol(rightY)) { rightY = _yGet(point); } } else { rightX = _xGet(point); rightY = _yGet(point); } } if (_yGet(point).LargerOrEqualWithTol(topY)) { if (_yGet(point).EqualsWithTol(topY)) { if (_xGet(point).LargerWithTol(topX)) { topX = _xGet(point); } } else { topX = _xGet(point); topY = _yGet(point); } } } } FirstPoint = new PointInfo <T>(_pointConstructor(rightX, rightY), _xGet, _yGet, _pointEqual); LastPoint = new PointInfo <T>(_pointConstructor(topX, topY), _xGet, _yGet, _pointEqual); RootPoint = _pointConstructor(topX, rightY); }
// ****************************************************************** protected override void SetQuadrantLimits() { T firstPoint = this._listOfListOfPoint.First().First(); double leftX = _xGet(firstPoint); double leftY = _yGet(firstPoint); double bottomX = leftX; double bottomY = leftY; foreach (var enumOfPoints in _listOfListOfPoint) { foreach (var point in enumOfPoints) { if (_xGet(point).SmallerOrEqualWithTol(leftX)) { if (_xGet(point).EqualsWithTol(leftX)) { if (_yGet(point).SmallerWithTol(leftY)) { leftY = _yGet(point); } } else { leftX = _xGet(point); leftY = _yGet(point); } } if (_yGet(point).SmallerOrEqualWithTol(bottomY)) { if (_yGet(point).EqualsWithTol(bottomY)) { if (_xGet(point).SmallerWithTol(bottomX)) { bottomX = _xGet(point); } } else { bottomX = _xGet(point); bottomY = _yGet(point); } } } } FirstPoint = new PointInfo <T>(_pointConstructor(leftX, leftY), _xGet, _yGet, _pointEqual); LastPoint = new PointInfo <T>(_pointConstructor(bottomX, bottomY), _xGet, _yGet, _pointEqual); RootPoint = _pointConstructor(bottomX, leftY); }
// ****************************************************************** protected override void TryAdd(double x, double y) { int indexLow = 0; int indexMax = HullPoints.Count - 1; int indexHi = indexMax; while (indexLow != indexHi - 1) { int index = ((indexHi - indexLow) >> 1) + indexLow; if (IsValueCannotBeConvexValueToAnotherOne(x, y, HullPoints[index].X, HullPoints[index].Y)) { return; } if (x.LargerWithTol(HullPoints[index].X)) { indexHi = index; continue; } if (x.SmallerWithTol(HullPoints[index].X)) { indexLow = index; continue; } if (x.EqualsWithTol(HullPoints[index].X)) { indexLow = index; indexHi = index + 1; } break; } PointInfo <T> ptiBefore = HullPoints[indexLow]; if (y.SmallerOrEqualWithTol(ptiBefore.Y)) { return; // Eliminated without slope calc } PointInfo <T> ptiAfter = HullPoints[indexHi]; double slopeToNext = Geometry.CalcSlope(x, y, ptiAfter.X, ptiAfter.Y); if (slopeToNext.LargerWithTol(ptiBefore.SlopeToNext)) { // We keep it (insert, or change existing one) int indexLowToRemove = indexHi; int indexHiToRemove = indexLow; // Find proper value of indexHiToRemove to appropriate index (adjustement that do not require calc of slope) if (HullPoints[indexHi].Y.SmallerWithTol(y)) // We can remove 1 or more points without slope calc { indexHiToRemove = indexHi; while (HullPoints[indexHiToRemove + 1].Y.SmallerWithTol(y)) { indexHiToRemove++; } } // Find proper value of indexHiToRemove to appropriate index (adjustement that require calc of slope) while (indexHiToRemove + 1 < indexMax) { double slopeToNewIndexHiToRemovePlus1 = Geometry.CalcSlope(x, y, HullPoints[indexHiToRemove + 1].X, HullPoints[indexHiToRemove + 1].Y); double slopeToNewIndexHiToRemovePlus2 = Geometry.CalcSlope(x, y, HullPoints[indexHiToRemove + 2].X, HullPoints[indexHiToRemove + 2].Y); if (slopeToNewIndexHiToRemovePlus2.LargerWithTol(slopeToNewIndexHiToRemovePlus1)) { break; } indexHiToRemove++; } // Find proper value of indexLowToRemove to appropriate index (adjustement that require calc of slope) while (indexLowToRemove - 1 > 0) { double slopeToNewIndexLowToRemoveMinus1 = Geometry.CalcSlope(x, y, HullPoints[indexLowToRemove - 1].X, HullPoints[indexLowToRemove - 1].Y); double slopeToNewIndexLowToRemoveMinus2 = Geometry.CalcSlope(x, y, HullPoints[indexLowToRemove - 2].X, HullPoints[indexLowToRemove - 2].Y); if (slopeToNewIndexLowToRemoveMinus2.SmallerWithTol(slopeToNewIndexLowToRemoveMinus1)) { break; } indexLowToRemove--; } PointInfo <T> newPointInfo; if (indexHiToRemove == indexLow) // No point to invalidate after, already calculated slope to next is still valid { newPointInfo = new PointInfo <T>(_pointConstructor(x, y), _xGet, _yGet, _pointEqual, slopeToNext); } else { newPointInfo = new PointInfo <T>(_pointConstructor(x, y), _xGet, _yGet, _pointEqual, Geometry.CalcSlope(x, y, HullPoints[indexHiToRemove + 1].X, HullPoints[indexHiToRemove + 1].Y)); } if (indexHiToRemove >= indexLowToRemove) // Any existing hull point become invalide ? { HullPoints[indexLowToRemove] = newPointInfo; if (indexHiToRemove > indexLowToRemove) { HullPoints.RemoveRange(indexLowToRemove + 1, indexHiToRemove - indexLowToRemove); } } else { HullPoints.Insert(indexHi, newPointInfo); } HullPoints[indexLowToRemove - 1].SlopeToNext = Geometry.CalcSlope(x, y, HullPoints[indexLowToRemove - 1].X, HullPoints[indexLowToRemove - 1].Y); } }
// ****************************************************************** public T[] GetResultsAsArrayOfPoint() { if (_listOfListOfPoint == null || !_listOfListOfPoint.Any() || !_listOfListOfPoint.First().Any()) { return(new T[0]); } int indexQ1Start; int indexQ2Start; int indexQ3Start; int indexQ4Start; int indexQ1End; int indexQ2End; int indexQ3End; int indexQ4End; PointInfo <T> lastPoint = _q4.HullPoints[_q4.HullPoints.Count - 1]; if (_q1.HullPoints.Count == 1) { indexQ1Start = 0; indexQ1End = 0; lastPoint = _q1.HullPoints[0]; } else { indexQ1Start = 0; indexQ1End = _q1.HullPoints.Count - 1; lastPoint = _q1.HullPoints[indexQ1End]; } if (_q2.HullPoints.Count == 1) { if (_q2.FirstPoint.Equals(lastPoint)) { indexQ2Start = 1; indexQ2End = 0; } else { indexQ2Start = 0; indexQ2End = 0; lastPoint = _q2.HullPoints[0]; } } else { if (_q2.FirstPoint.Equals(lastPoint)) { indexQ2Start = 1; } else { indexQ2Start = 0; } indexQ2End = _q2.HullPoints.Count - 1; lastPoint = _q2.HullPoints[indexQ2End]; } if (_q3.HullPoints.Count == 1) { if (_q3.FirstPoint.Equals(lastPoint)) { indexQ3Start = 1; indexQ3End = 0; } else { indexQ3Start = 0; indexQ3End = 0; lastPoint = _q3.HullPoints[0]; } } else { if (_q3.FirstPoint.Equals(lastPoint)) { indexQ3Start = 1; } else { indexQ3Start = 0; } indexQ3End = _q3.HullPoints.Count - 1; lastPoint = _q3.HullPoints[indexQ3End]; } if (_q4.HullPoints.Count == 1) { if (_q4.FirstPoint.Equals(lastPoint)) { indexQ4Start = 1; indexQ4End = 0; } else { indexQ4Start = 0; indexQ4End = 0; } } else { if (_q4.FirstPoint.Equals(lastPoint)) { indexQ4Start = 1; } else { indexQ4Start = 0; } indexQ4End = _q4.HullPoints.Count - 1; if (_q4.HullPoints[indexQ4End].Equals(_q1.HullPoints[0])) { indexQ4End--; } } int countOfFinalHullPoint = (indexQ1End - indexQ1Start) + (indexQ2End - indexQ2Start) + (indexQ3End - indexQ3Start) + (indexQ4End - indexQ4Start) + 4; if (countOfFinalHullPoint == 1) // Case where there is only one point or many of only the same point. Auto closed if required. { return(new T[] { _pointConstructor(_q1.HullPoints[0].X, _q1.HullPoints[0].Y) }); } if (_shouldCloseTheGraph) { countOfFinalHullPoint++; } T[] results = new T[countOfFinalHullPoint]; int resIndex = 0; for (int n = indexQ1Start; n <= indexQ1End; n++) { results[resIndex] = _pointConstructor(_q1.HullPoints[n].X, _q1.HullPoints[n].Y); resIndex++; } for (int n = indexQ2Start; n <= indexQ2End; n++) { results[resIndex] = _pointConstructor(_q2.HullPoints[n].X, _q2.HullPoints[n].Y); resIndex++; } for (int n = indexQ3Start; n <= indexQ3End; n++) { results[resIndex] = _pointConstructor(_q3.HullPoints[n].X, _q3.HullPoints[n].Y); resIndex++; } for (int n = indexQ4Start; n <= indexQ4End; n++) { results[resIndex] = _pointConstructor(_q4.HullPoints[n].X, _q4.HullPoints[n].Y); resIndex++; } if (_shouldCloseTheGraph) { results[resIndex] = _pointConstructor(_q1.FirstPoint.X, _q1.FirstPoint.Y); } return(results); }