using System; using System.Collections.Generic; namespace EllipseTruncate { public class ActivePoint { public Point point; public ActivePoint(double x, double y) { point = new Point(x, y); } } public class MainWindow : Gtk.Window { static public void Main() { Gtk.Application.Init(); MainWindow win = new MainWindow(); win.Show(); win.Maximize(); Gtk.Application.Run(); } Point cursor; Point offset; ActivePoint point; ActiveAngleRange rangeAdd; ActiveAngleRange rangeXor; ActiveAngleRange rangeSub; List points = new List(); List ranges = new List(); ActivePoint ellipse0 = new ActivePoint(500.0, 500.0), ellipse1 = new ActivePoint(600.0, 500.0), ellipse2 = new ActivePoint(500.0, 450.0); ActivePoint bounds0 = new ActivePoint(450.0, 500.0), bounds1 = new ActivePoint(500.0, 700.0), bounds2 = new ActivePoint(600.0, 550.0); ActiveAngleRange rangeA = new ActiveAngleRange(new Point(150.0, 150.0), 50.0); ActiveAngleRange rangeB = new ActiveAngleRange(new Point(400.0, 150.0), 50.0); public MainWindow(): base(Gtk.WindowType.Toplevel) { Events = Gdk.EventMask.KeyPressMask | Gdk.EventMask.KeyReleaseMask | Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.ButtonMotionMask | Gdk.EventMask.PointerMotionMask; ExtensionEvents = Gdk.ExtensionMode.All; rangeA.b = rangeB.a; rangeB.b = rangeA.a; points.AddRange(new ActivePoint[] {ellipse0, ellipse1, ellipse2, bounds0, bounds1, bounds2}); ranges.AddRange(new ActiveAngleRange[] {rangeA, rangeB}); } private bool refreshOnIdle() { QueueDraw(); return false; } private void Refresh() { QueueDraw(); //GLib.Idle.Add(refreshOnIdle); } protected override bool OnDeleteEvent(Gdk.Event e) { Gtk.Application.Quit(); return false; } protected override bool OnExposeEvent(Gdk.EventExpose e) { Cairo.Context context = Gdk.CairoHelper.Create(e.Window); context.Save(); context.SetSourceRGBA(1.0, 1.0, 1.0, 1.0); context.Rectangle(0, 0, Allocation.Width, Allocation.Height); context.Fill(); context.Restore(); context.Save(); context.Antialias = Cairo.Antialias.Gray; foreach(ActivePoint p in points) { context.Save(); context.SetSourceRGBA(0.0, point == p ? 1.0 : 0.0, 1.0, 1.0); context.Arc(p.point.x, p.point.y, 5.0, 0, 2.0*Math.PI); context.Fill(); context.Restore(); } { // draw bounds Point p0 = bounds0.point, p1 = bounds1.point, p2 = bounds2.point; context.Save(); context.SetSourceRGBA(0.5, 0.5, 0.5, 0.2); context.LineWidth = 2.0; context.MoveTo(p0.x, p0.y); context.LineTo(p1.x, p1.y); context.LineTo(p1.x + p2.x - p0.x, p1.y + p2.y - p0.y); context.LineTo(p2.x, p2.y); context.ClosePath(); context.Stroke(); context.Restore(); } // draw ellipse Ellipse ellipse = new Ellipse(ellipse0.point, ellipse1.point, ellipse2.point); ellipse.drawFull(context); ellipse.drawTruncated(context, bounds0.point, bounds1.point, bounds2.point); // draw concentric grid ConcentricGrid cg = new ConcentricGrid( ellipse, 20.0, bounds0.point, bounds1.point, bounds2.point ); cg.draw(context); // draw ranges foreach(ActiveAngleRange rl in ranges) { rl.draw(context); if ((cursor - rl.point).len() < 2.0*rl.radius || !rl.current.isEmpty()) { context.Save(); context.SetSourceRGBA(0.0, 0.0, 0.0, 0.5); context.LineWidth = 1.0; context.MoveTo(rl.point.x, rl.point.y); context.LineTo(cursor.x, cursor.y); context.Stroke(); context.Restore(); } } context.Restore(); context.Dispose(); return false; } private void releaseButton() { if (rangeAdd != null) rangeAdd.add(); if (rangeXor != null) rangeXor.xor(); if (rangeSub != null) rangeSub.subtract(); point = null; rangeAdd = null; rangeXor = null; rangeSub = null; } protected override bool OnButtonPressEvent(Gdk.EventButton e) { cursor = new Point(e.X, e.Y); releaseButton(); ActivePoint ap = null; Point o = new Point(); foreach(ActivePoint p in points) if ((p.point - cursor).len() <= 5.0) { o = p.point - cursor; ap = p; } ActiveAngleRange ar = null; uint a0 = 0; foreach(ActiveAngleRange r in ranges) if ((r.point - cursor).len() < 2.0*r.radius) { ar = r; a0 = AngleRange.toUIntDiscrete((cursor - r.point).atan()); } if (e.Button == 1) { if (ap != null) { point = ap; offset = o; } else if (ar != null) { ar.current = new AngleRange.Entry(); ar.current.a0 = a0; rangeAdd = ar; } } else if (e.Button == 2) { if (ar != null) { ar.current = new AngleRange.Entry(); ar.current.a0 = a0; rangeXor = ar; } } else if (e.Button == 3) { if (ar != null) { ar.current = new AngleRange.Entry(); ar.current.a0 = a0; rangeSub = ar; } } Refresh(); return false; } protected override bool OnButtonReleaseEvent(Gdk.EventButton e) { cursor = new Point(e.X, e.Y); releaseButton(); Refresh(); return false; } protected override bool OnMotionNotifyEvent(Gdk.EventMotion e) { cursor = new Point(e.X, e.Y); if (point != null) point.point = cursor + offset; if (rangeAdd != null) rangeAdd.current.a1 = AngleRange.toUIntDiscrete((cursor - rangeAdd.point).atan()); if (rangeXor != null) rangeXor.current.a1 = AngleRange.toUIntDiscrete((cursor - rangeXor.point).atan()); if (rangeSub != null) rangeSub.current.a1 = AngleRange.toUIntDiscrete((cursor - rangeSub.point).atan()); Refresh(); return false; } } }