Blame mono/EllipseTruncate/ConcentricGrid.cs

a79478
using System;
a79478
a79478
namespace EllipseTruncate {
a79478
	public class ConcentricGrid {
a79478
		Ellipse ellipse;
a79478
		double step;
a79478
		Point b0, b1, b2;
a79478
	
a79478
		public ConcentricGrid(Ellipse ellipse, double step, Point b0, Point b1, Point b2) {
a79478
			this.ellipse = ellipse;
a79478
			this.step = step;
a79478
			this.b0 = b0; this.b1 = b1; this.b2 = b2;
a79478
		}
a79478
	
a79478
		public void calcBounds(out double min, out double max) {
a79478
			Point o = ellipse.matrixInv*b0;
a79478
			Point dx = ellipse.matrixInv.turn(b1 - b0);
a79478
			Point dy = ellipse.matrixInv.turn(b2 - b0);
a79478
			max = 0.0;
a79478
			min = double.PositiveInfinity;
a79478
			
a79478
			// distance to points
a79478
			Point[] corners = new Point[] { o, o+dx, o+dx+dy, o+dy };
a79478
			foreach(Point p in corners) {
a79478
				double k = p.len();
a79478
				if (k < min) min = k;
a79478
				if (k > max) max = k;
a79478
			}
a79478
			
a79478
			// distance to sides
a79478
			Point[] lines = new Point[] { dx, dy, -1.0*dx, -1.0*dy };
a79478
			int positive = 0, negative = 0;
a79478
			for(int i = 0; i < 4; ++i) {
a79478
				double len2 = lines[i].lenSqr();
a79478
				if (len2 <= Geometry.precisionSqr) continue;
a79478
				double k = corners[i]*lines[i].rotate90()/Math.Sqrt(len2);
a79478
				if (k > Geometry.precision) ++positive;
a79478
				if (k < Geometry.precision) ++negative;
a79478
				double l = -(corners[i]*lines[i]);
a79478
				if (l <= Geometry.precision || l >= len2 - Geometry.precision) continue;
a79478
				k = Math.Abs(k);
a79478
				if (k < min) min = k;
a79478
				if (k > max) max = k;
a79478
			}
a79478
			
a79478
			// if center is inside bounds
a79478
			if (min < 0.0 || positive == 0 || negative == 0) min = 0.0;
a79478
		}
a79478
		
a79478
		public void draw(Cairo.Context context) {
a79478
			double r2 = Math.Min(
a79478
				ellipse.matrix.row0().lenSqr(),
a79478
				ellipse.matrix.row1().lenSqr() );
a79478
			if (r2 <= Geometry.precisionSqr) return;
a79478
			double actualStep = step/Math.Sqrt(r2);
a79478
		
a79478
			double min, max;
a79478
			calcBounds(out min, out max);
a79478
			if (max <= min) return;
a79478
			if (max - min > 1e5) return;
a79478
			int minI = (int)Math.Ceiling((min - 1.0)/actualStep + Geometry.precision);
a79478
			int maxI = (int)Math.Ceiling((max - 1.0)/actualStep - Geometry.precision);
a79478
			for(int i = minI; i < maxI; ++i) {
a79478
				double scale = i*actualStep + 1.0;
a79478
				Ellipse e = new Ellipse( ellipse.matrix.scale(scale) );
a79478
				e.drawFull(context, true);
a79478
				e.drawTruncated(context, b0, b1, b2, true);
a79478
			}
a79478
		}
a79478
	}
a79478
}
a79478