Blob Blame Raw
using System;

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