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();
}
}
}