/// <summary> /// Calculate the list of rects that need to be updated when moving a clip level from one source area to another. /// </summary> /// <param name="oldData">The area the clip level is moving from.</param> /// <param name="newData">The area the clip level is moving to.</param> /// <returns>A list of rectangles that need to be updated.</returns> protected List<RectangleI> _CalculateModuloDeltaBounds(RectangleI oldData, RectangleI newData) { // sanity checking Assert.Fatal(oldData.Point.X >= 0 && oldData.Point.Y >= 0 && oldData.IsValid, "ClipMap.CalculateModuloDeltaBounds - Negative oldData origin or bad rect."); Assert.Fatal(newData.Point.X >= 0 && newData.Point.Y >= 0 && newData.IsValid, "ClipMap.CalculateModuloDeltaBounds - Negative newData origin or bad rect."); Assert.Fatal(newData.Extent == oldData.Extent, "ClipMap.CalculateModuloDeltaBounts - Mismatching extents, can only work with matching extents."); _updateRectList.Clear(); // easiest case - if they're the same then do nothing if (oldData.Point == newData.Point) return _updateRectList; // easy case - if there's no overlap then it's all new if (!oldData.Overlaps(newData)) { // clip out to return buffer, and we're done _ClipAgainstGrid(_clipMapSize, newData, ref _updateRectList); return _updateRectList; } // calculate some useful values for both X and Y. delta is used a lot // in determining bounds, and the boundary values are important for // determining where to start copying new data in. int xDelta = newData.Point.X - oldData.Point.X; int yDelta = newData.Point.Y - oldData.Point.Y; int xBoundary = (oldData.Point.X + oldData.Extent.X) % _clipMapSize; int yBoundary = (oldData.Point.Y + oldData.Extent.Y) % _clipMapSize; Assert.Fatal(xBoundary % _clipMapSize == oldData.Point.X % _clipMapSize, "ClipMap.CalculateModuleDeltaBounds - We assume that left and right of the dataset are identical (ie, it's periodical on size of clipmap!) (x)"); Assert.Fatal(yBoundary % _clipMapSize == oldData.Point.Y % _clipMapSize, "ClipMap.CalculateModuleDeltaBounds - We assume that left and right of the dataset are identical (ie, it's periodical on size of clipmap!) (y)"); // now, let's build up our rects. we have one rect if we are moving // on the X or Y axis, two if both. we dealt with the no-move case // previously. if (xDelta == 0) { // moving on Y! so generate and store clipped results. RectangleI yRect = new RectangleI(); if (yDelta < 0) { // we need to generate the box from right of old to right of new yRect.Point = newData.Point; yRect.Extent = new Point(_clipMapSize, -yDelta); } else { // we need to generate the box from left of old to left of new yRect.Point = new Point(newData.Point.X, (oldData.Point.Y + oldData.Extent.Y)); yRect.Extent = new Point(_clipMapSize, yDelta); } // clip out to return buffer, and we're done _ClipAgainstGrid(_clipMapSize, yRect, ref _updateRectList); return _updateRectList; } else if (yDelta == 0) { // moving on X! So generate and store clipped results. RectangleI xRect = new RectangleI(); if (xDelta < 0) { // We need to generate the box from right of old to right of new. xRect.Point = newData.Point; xRect.Extent = new Point(-xDelta, _clipMapSize); } else { // we need to generate the box from left of old to left of new. xRect.Point = new Point((oldData.Point.X + oldData.Extent.X), newData.Point.Y); xRect.Extent = new Point(xDelta, _clipMapSize); } // clip out to return buffer, and we're done _ClipAgainstGrid(_clipMapSize, xRect, ref _updateRectList); return _updateRectList; } else { // Both! We have an L shape. So let's do the bulk of it in one rect, // and the remainder in the other. We'll choose X as the dominant axis. // // a-----b---------c going from e to a. // | | | // | | | // d-----e---------f So the dominant rect is abgh and the passive // | | | rect is bcef. Obviously depending on delta we // | | | have to switch things around a bit. // | | | y+ ^ // | | | | // g-----h---------i x+-> | RectangleI xRect = new RectangleI(); RectangleI yRect = new RectangleI(); if (xDelta < 0) { // case in the diagram xRect.Point = newData.Point; xRect.Extent = new Point(-xDelta, _clipMapSize); // set up what of yRect we know too yRect.Point = new Point(xRect.Point.X + xRect.Extent.X, 0); yRect.Extent = new Point(_clipMapSize + xDelta, 0); } else { // opposite of case in diagram xRect.Point = new Point(oldData.Point.X + oldData.Extent.X, newData.Point.Y); xRect.Extent = new Point(xDelta, _clipMapSize); // set up what of yRect we know too yRect.Point = new Point((xRect.Point.X + xRect.Extent.X) - _clipMapSize, 0); yRect.Extent = new Point(_clipMapSize - xRect.Extent.X, 0); } if (yDelta < 0) { // case in the diagram. yRect.Point = new Point(yRect.Point.X, newData.Point.Y); yRect.Extent = new Point(yRect.Extent.X, -yDelta); } else { // case in the diagram. yRect.Point = new Point(yRect.Point.X, oldData.Point.Y + oldData.Extent.Y); yRect.Extent = new Point(yRect.Extent.X, yDelta); } // make sure we don't overlap. Assert.Fatal(!yRect.Overlaps(xRect), "ClipMap.CalculateModuloDeltaBounds() - overlap in result rects - should not happen!"); // now run them through the clipper and we're done _ClipAgainstGrid(_clipMapSize, xRect, ref _updateRectList); _ClipAgainstGrid(_clipMapSize, yRect, ref _updateRectList); return _updateRectList; } }