private Sample ComputeTree( ref Rectangle region, Device2D device2D, ref Sample.Location parentTopLeft, ref Sample.Location parentTopRight, ref Sample.Location parentBottomLeft, ref Sample.Location parentBottomRight, double level = 1.0) { Sample sample = new Sample(ref region); // define the points on the rectangle to test Point topLeft = new Point(region.Left, region.Top); Point topRight = new Point(region.Right, region.Top); Point bottomLeft = new Point(region.Left, region.Bottom); Point bottomRight = new Point(region.Right, region.Bottom); // the method was not called recursively, so compute the distances to each point if(level <= 1.0) { mDecomposer.Query( ref topLeft, device2D, out sample.TopLeft.Distance, out sample.TopLeft.Intersection); mDecomposer.Query( ref topRight, device2D, out sample.TopRight.Distance, out sample.TopRight.Intersection); mDecomposer.Query( ref bottomLeft, device2D, out sample.BottomLeft.Distance, out sample.BottomLeft.Intersection); mDecomposer.Query( ref bottomRight, device2D, out sample.BottomRight.Distance, out sample.BottomRight.Intersection); } else { // use distances already computed by the caller sample.TopLeft = parentTopLeft; sample.TopRight = parentTopRight; sample.BottomLeft = parentBottomLeft; sample.BottomRight = parentBottomRight; } // do not subdivide lower than a resolved resolution unit if(level > MaxLevel) { return sample; } int boundaryContains = 0; Thickness thick = new Thickness(MaximumError); Rectangle boundary = region.Expand(thick); boundaryContains += boundary.Contains(sample.TopLeft.Intersection) ? 1 : 0; boundaryContains += boundary.Contains(sample.TopRight.Intersection) ? 1 : 0; boundaryContains += boundary.Contains(sample.BottomLeft.Intersection) ? 1 : 0; boundaryContains += boundary.Contains(sample.BottomRight.Intersection) ? 1 : 0; // compute the intersection of the region with the shape int boundaryIntersection = 0; boundaryIntersection += sample.TopLeft.Distance >= 0.0 ? 1 : -1; boundaryIntersection += sample.TopRight.Distance >= 0.0 ? 1 : -1; boundaryIntersection += sample.BottomLeft.Distance >= 0.0 ? 1 : -1; boundaryIntersection += sample.BottomRight.Distance >= 0.0 ? 1 : -1; double s = Math.Abs(boundaryIntersection) != 4 || boundaryContains > 0 ? 0.0 : 1.0; double error = MinimumError + ((MaximumError - MinimumError) * s); float halfWidth = region.Width / 2.0f; float halfHeight = region.Height / 2.0f; Point leftCenter = new Point(region.Left, region.Top + halfHeight); Point topCenter = new Point(region.Left + halfWidth, region.Top); Point rightCenter = new Point(region.Right, region.Top + halfHeight); Point bottomCenter = new Point(region.Left + halfWidth, region.Bottom); Point center = new Point(region.Left + halfWidth, region.Top + halfHeight); Sample.Location centerLocation = new Sample.Location(); mDecomposer.Query( ref center, device2D, out centerLocation.Distance, out centerLocation.Intersection); boundaryContains += boundary.Contains(centerLocation.Intersection) ? 1 : 0; if(boundaryContains == 0) { return sample; } Sample.Location leftCenterLocation = new Sample.Location(); Sample.Location topCenterLocation = new Sample.Location(); Sample.Location rightCenterLocation = new Sample.Location(); Sample.Location bottomCenterLocation = new Sample.Location(); mDecomposer.Query( ref leftCenter, device2D, out leftCenterLocation.Distance, out leftCenterLocation.Intersection); mDecomposer.Query( ref topCenter, device2D, out topCenterLocation.Distance, out topCenterLocation.Intersection); mDecomposer.Query( ref rightCenter, device2D, out rightCenterLocation.Distance, out rightCenterLocation.Intersection); mDecomposer.Query( ref bottomCenter, device2D, out bottomCenterLocation.Distance, out bottomCenterLocation.Intersection); double reconstructedLeftCenter = (sample.TopLeft.Distance + sample.BottomLeft.Distance) / 2.0; double reconstructedTopCenter = (sample.TopLeft.Distance + sample.TopRight.Distance) / 2.0; double reconstructedRightCenter = (sample.TopRight.Distance + sample.BottomRight.Distance) / 2.0; double reconstructedBottomCenter = (sample.BottomLeft.Distance + sample.BottomRight.Distance) / 2.0; double reconstructedCenter = (reconstructedTopCenter + reconstructedBottomCenter) / 2.0; bool isLeftCenterInvalid = Math.Abs(reconstructedLeftCenter - leftCenterLocation.Distance) > error; bool isTopCenterInvalid = Math.Abs(reconstructedTopCenter - topCenterLocation.Distance) > error; bool isRightCenterInvalid = Math.Abs(reconstructedRightCenter - rightCenterLocation.Distance) > error; bool isBottomCenterInvalid = Math.Abs(reconstructedBottomCenter - bottomCenterLocation.Distance) > error; bool isCenterInvalid = Math.Abs(reconstructedCenter - centerLocation.Distance) > error; if(isLeftCenterInvalid || isTopCenterInvalid || isRightCenterInvalid || isBottomCenterInvalid || isCenterInvalid) { Rectangle topLeftRegion = new Rectangle( topLeft.X, topLeft.Y, center.X - topLeft.X, center.Y - topLeft.Y); sample.Children.Add( ComputeTree( ref topLeftRegion, device2D, ref sample.TopLeft, ref topCenterLocation, ref leftCenterLocation, ref centerLocation, level + 1.0)); Rectangle topRightRegion = new Rectangle( center.X, topRight.Y, topRight.X - center.X, center.Y - topRight.Y); sample.Children.Add( ComputeTree( ref topRightRegion, device2D, ref topCenterLocation, ref sample.TopRight, ref centerLocation, ref rightCenterLocation, level + 1.0)); Rectangle bottomRightRegion = new Rectangle( center.X, center.Y, bottomRight.X - center.X, bottomRight.Y - center.Y); sample.Children.Add( ComputeTree( ref bottomRightRegion, device2D, ref centerLocation, ref rightCenterLocation, ref bottomCenterLocation, ref sample.BottomRight, level + 1.0)); Rectangle bottomLeftRegion = new Rectangle( bottomLeft.X, center.Y, center.X - bottomLeft.X, bottomLeft.Y - center.Y); sample.Children.Add( ComputeTree( ref bottomLeftRegion, device2D, ref leftCenterLocation, ref centerLocation, ref sample.BottomLeft, ref bottomCenterLocation, level + 1.0)); } return sample; }
private Sample ComputeTree(ref Rectangle region, Device2D device2D) { Sample.Location empty = new Sample.Location(); return ComputeTree(ref region, device2D, ref empty, ref empty, ref empty, ref empty); }