Blob Blame Raw
using System;

namespace EllipseTruncate {
	public class ActiveAngleRange {
		public double width = 0.1;
	
		public Point point;
		public double radius;
		public AngleRange.Entry current;
		public AngleRange a = new AngleRange();
		public AngleRange b = new AngleRange();
		
		public ActiveAngleRange(Point point, double radius) {
			this.point = point;
			this.radius = radius;
		}

		public void add() {
			a.add(current);
			current = new AngleRange.Entry();
		}

		public void xor() {
			a.xor(current);
			current = new AngleRange.Entry();
		}

		public void subtract() {
			a.subtract(current);
			current = new AngleRange.Entry();
		}
		
		public void scale(Cairo.Context context, double level = 1.0) {
			double k = Math.Pow(1.0 + 1.5*width, level);
			context.Scale(k, k);
		}
		
		public void draw(Cairo.Context context, uint a0, uint a1, double level = 0.0) {
			if (a0 == a1) return;
			
			context.Save();
			scale(context, level);
			context.LineWidth = width;
			double aa0 = AngleRange.toDouble(a0);
			double aa1 = AngleRange.toDouble(a1);
			if (a1 < a0) aa1 += AngleRange.period;
			if (aa1 < aa0) return;
			
			context.Arc(0.0, 0.0, 1.0, aa0, aa1);
			context.Stroke();
			context.Restore();
		}
		
		public void draw(Cairo.Context context, AngleRange r, double level = 0.0) {
			context.Save();
			scale(context, level);
			if (r.isEmpty()) {
				context.LineWidth = 0.25*width;
				context.SetDash(new double[] { 0.1, 0.02 }, 0.0);
				context.Arc(0.0, 0.0, 1.0, 0.0, 2.0*Math.PI);
				context.Stroke();
			} else
			if (r.isFull()) {
				context.LineWidth = width;
				context.Arc(0.0, 0.0, 1.0, 0.0, 2.0*Math.PI);
				context.Stroke();
				context.LineWidth = 0.25*width;
				context.SetDash(new double[] { 0.1, 0.03 }, 0.0);
				context.Arc(0.0, 0.0, 1.0, 0.0, 2.0*Math.PI);
				context.Stroke();
			} else {
				context.LineWidth = 0.25*width;
				context.Arc(0.0, 0.0, 1.0, 0.0, 2.0*Math.PI);
				context.Stroke();
				bool f = r.flip;
				uint prev = r.angles[r.angles.Count - 1];
				foreach(uint a in r.angles) {
					if (f) draw(context, prev, a);
					prev = a; f = !f;
				}
			}

			if (!r.check()) {
				context.LineWidth = width;
				context.SetDash(new double[] { 0.1, 0.02 }, 0.0);
				context.Arc(0.0, 0.0, 1.0, 0.0, 2.0*Math.PI);
				context.Stroke();
			}

			context.Restore();
		}
		
		public void draw(Cairo.Context context) {
			context.Save();
			context.Translate(point.x, point.y);
			context.Scale(radius, radius);
			
			AngleRange x = new AngleRange();

			// back circle
			context.SetSourceRGBA(1.0, 0.0, 0.0, 0.1);
			context.Arc(0.0, 0.0, 1.0, 0.0, 2.0*Math.PI);
			context.Fill();

			// a
			context.SetSourceRGBA(0.0, 0.0, 0.0, 0.5);
			draw(context, a);

			// b
			context.SetSourceRGBA(0.0, 0.0, 1.0, 0.5);
			draw(context, b, 1.0);

			// current
			context.SetSourceRGBA(0.0, 0.0, 1.0, 0.5);
			if (!current.isEmpty())
				draw(context, current.a0, current.a1);

			// !a
			context.SetSourceRGBA(0.5, 0.5, 0.5, 0.5);
			x.set(a); x.invert();	
			draw(context, x, -1.0);
			
			scale(context);
			
			// a xor b
			scale(context);
			context.SetSourceRGBA(0.0, 0.5, 0.0, 0.5);
			x.set(a);
			x.xor(b);
			draw(context, x);

			// a | b
			scale(context);
			context.SetSourceRGBA(0.0, 0.5, 0.0, 0.5);
			x.set(a);
			x.add(b);
			draw(context, x);
			
			// a & ~b
			scale(context);
			context.SetSourceRGBA(0.0, 0.5, 0.0, 0.5);
			x.set(a);
			x.subtract(b);
			draw(context, x);

			// a & b
			scale(context);
			context.SetSourceRGBA(0.0, 0.5, 0.0, 0.5);
			x.set(a);
			x.intersect(b);
			draw(context, x);
			
			context.Restore();
		}
	}
}