diff --git a/mono/Assistance/ActivePoint.cs b/mono/Assistance/ActivePoint.cs new file mode 100644 index 0000000..fbecc1f --- /dev/null +++ b/mono/Assistance/ActivePoint.cs @@ -0,0 +1,80 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.Collections.Generic; + +namespace Assistance { + public class ActivePoint { + public enum Mode { + Common = 0, + Active = 1 + } + + public enum Type { + Circle, + CircleFill, + CircleCross, + }; + + public static readonly double radius = 10.0; + public static readonly double crossSize = 1.2*radius; + public static readonly Pen[] pens = new Pen[] { Pens.Gray, Pens.Blue }; + public static readonly Brush[] brushes = new Brush[] { Brushes.LightGray, Brushes.LightBlue }; + + public readonly Canvas canvas; + public readonly Assistant assistant; + public readonly Type type; + public Point position; + + public ActivePoint(Assistant assistant, Type type, Point position = new Point()) { + this.canvas = assistant.canvas; + this.assistant = assistant; + this.type = type; + this.position = position; + canvas.points.Add(this); + assistant.points.Add(this); + } + + public bool isInside(Point p) { + return (position - p).lenSqr() <= radius*radius; + } + + public void bringToFront() { + assistant.bringToFront(); + assistant.points.Remove(this); + assistant.points.Add(this); + canvas.points.Remove(this); + canvas.points.Add(this); + } + + private void drawCircle(Graphics g, Mode mode) { + g.DrawEllipse(pens[(int)mode], (float)(position.x - radius), (float)(position.y - radius), (float)(2.0*radius), (float)(2.0*radius)); + } + + private void fillCircle(Graphics g, Mode mode) { + g.FillEllipse(brushes[(int)mode], (float)(position.x - radius), (float)(position.y - radius), (float)(2.0*radius), (float)(2.0*radius)); + } + + private void drawCross(Graphics g, Mode mode) { + g.DrawLine(pens[(int)mode], (float)(position.x - crossSize), (float)position.y, (float)(position.x + crossSize), (float)position.y); + g.DrawLine(pens[(int)mode], (float)position.x, (float)(position.y - crossSize), (float)position.x, (float)(position.y + crossSize)); + } + + public void draw(Graphics g, Mode mode) { + switch(type) { + case Type.Circle: + drawCircle(g, mode); + break; + case Type.CircleFill: + fillCircle(g, mode); + drawCircle(g, mode); + break; + case Type.CircleCross: + drawCircle(g, mode); + drawCross(g, mode); + break; + } + } + } +} + diff --git a/mono/Assistance/Assistance.csproj b/mono/Assistance/Assistance.csproj new file mode 100644 index 0000000..f398257 --- /dev/null +++ b/mono/Assistance/Assistance.csproj @@ -0,0 +1,50 @@ + + + + Debug + x86 + 10.0.0 + 2.0 + {77CD6953-34F0-4125-9DF5-957ECF0E23F0} + Exe + Assistance + Assistance + v4.5 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + x86 + false + + + none + true + bin\Release + prompt + 4 + x86 + false + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mono/Assistance/Assistance.sln b/mono/Assistance/Assistance.sln new file mode 100644 index 0000000..43bd5bc --- /dev/null +++ b/mono/Assistance/Assistance.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assistance", "Assistance.csproj", "{77CD6953-34F0-4125-9DF5-957ECF0E23F0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {77CD6953-34F0-4125-9DF5-957ECF0E23F0}.Debug|x86.ActiveCfg = Debug|x86 + {77CD6953-34F0-4125-9DF5-957ECF0E23F0}.Debug|x86.Build.0 = Debug|x86 + {77CD6953-34F0-4125-9DF5-957ECF0E23F0}.Release|x86.ActiveCfg = Release|x86 + {77CD6953-34F0-4125-9DF5-957ECF0E23F0}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = Assistance.csproj + EndGlobalSection +EndGlobal diff --git a/mono/Assistance/Assistant.cs b/mono/Assistance/Assistant.cs new file mode 100644 index 0000000..c6abe90 --- /dev/null +++ b/mono/Assistance/Assistant.cs @@ -0,0 +1,56 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.Collections.Generic; + +namespace Assistance { + public class Assistant { + public static readonly double maxLen = 1000.0; + public static readonly int gridPointsCount = 100; + public static readonly Pen pen = Pens.Gray; + public static readonly Pen guidePen = Pens.LightGray; + + public readonly Canvas canvas; + public readonly List points = new List(); + + public Assistant(Canvas canvas) { + this.canvas = canvas; + canvas.assistants.Add(this); + } + + public void remove() { + foreach(ActivePoint point in points) + canvas.points.Remove(point); + canvas.assistants.Remove(this); + } + + public void bringToFront() { + canvas.assistants.Remove(this); + canvas.assistants.Add(this); + } + + public double getMaxLen() { + double l = 0.0; + foreach(ActivePoint point in points) + l = Math.Max(l, point.position.len()); + return maxLen + l; + } + + public virtual void onMovePoint(ActivePoint point, Point position) { + point.position = position; + } + + public virtual Point[] getGridPoints(Point target, bool truncate) { return new Point[0]; } + + public Point[] getGridPoints(Point target) { return getGridPoints(target, false); } + + public virtual void draw(Graphics g) { } + + public virtual void drawGuidlines(Graphics g, Point target, bool truncate) { } + + public void drawGuidlines(Graphics g, Point target) { + drawGuidlines(g, target, false); + } + } +} + diff --git a/mono/Assistance/Canvas.cs b/mono/Assistance/Canvas.cs new file mode 100644 index 0000000..a211fb1 --- /dev/null +++ b/mono/Assistance/Canvas.cs @@ -0,0 +1,48 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.Collections.Generic; +using System.Linq; + +namespace Assistance { + public class Canvas { + public readonly List assistants = new List(); + public readonly List points = new List(); + + public ActivePoint ActivePoint = null; + + public ActivePoint findPoint(Point position) { + foreach(ActivePoint point in points.Reverse()) + if (point.isInside(position)) + return point; + return null; + } + + public void drawGuidlines(Graphics g, Point point) { + foreach(Assistant assistant in assistants) + assistant.drawGuidlines(g, point); + } + + public void drawAssistants(Graphics g) { + foreach(Assistant assistant in assistants) + assistant.draw(g); + } + + public void drawPoints(Graphics g, ActivePoint activePoint) { + foreach(ActivePoint point in points) + point.draw(g, activePoint == point ? ActivePoint.Mode.Active : ActivePoint.Mode.Common); + } + + public void draw(Graphics g, ActivePoint activePoint, Point guidlinesPoint) { + drawGuidlines(g, guidlinesPoint); + drawAssistants(g); + drawPoints(g, activePoint); + } + + public void draw(Graphics g, ActivePoint activePoint) { + drawAssistants(g); + drawPoints(g, activePoint); + } + } +} + diff --git a/mono/Assistance/Grid.cs b/mono/Assistance/Grid.cs new file mode 100644 index 0000000..6bd02df --- /dev/null +++ b/mono/Assistance/Grid.cs @@ -0,0 +1,20 @@ +using System; + +namespace Assistance { + public class Grid: Assistant { + public ActivePoint center; + + public Grid(Canvas canvas, Point center): base(canvas) { + this.center = new ActivePoint(this, ActivePoint.Type.CircleCross, center); + } + + public override void draw(System.Drawing.Graphics g) { + foreach(Assistant assistant in canvas.assistants) + foreach(Point p in assistant.getGridPoints(center.position, true)) + foreach(Assistant a in canvas.assistants) + if (a != assistant) + a.drawGuidlines(g, p, true); + } + } +} + diff --git a/mono/Assistance/MainWindow.cs b/mono/Assistance/MainWindow.cs new file mode 100644 index 0000000..f1e294f --- /dev/null +++ b/mono/Assistance/MainWindow.cs @@ -0,0 +1,112 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.Windows.Forms; +using System.Collections.Generic; + +namespace Assistance { + public class MainWindow : Form { + static public void Main() { Application.Run(new MainWindow()); } + + Bitmap bitmap = new Bitmap(1, 1); + Canvas canvas = new Canvas(); + bool dragging = false; + ActivePoint activePoint; + Point offset; + Point cursor; + + public MainWindow() { + Paint += onPaint; + MouseMove += onMouseMove; + MouseDown += onMouseDown; + MouseUp += onMouseUp; + KeyDown += onKeyDown; + WindowState = FormWindowState.Maximized; + } + + protected override void OnPaintBackground(PaintEventArgs e) { } + + public void onPaint(Object sender, PaintEventArgs e) { + if (bitmap.Size != ClientSize) + bitmap = new Bitmap(ClientSize.Width, ClientSize.Height); + Graphics g = Graphics.FromImage(bitmap); + g.Clear(Color.White); + draw(g); + g.Flush(); + e.Graphics.DrawImageUnscaled(bitmap, new Rectangle(0, 0, ClientSize.Width, ClientSize.Height)); + } + + public Point windowToCanvas(Point p) { + return new Point(p.x - ClientSize.Width/2.0, p.y - ClientSize.Height/2.0); + } + + public Point canvasToWindow(Point p) { + return new Point(p.x + ClientSize.Width/2.0, p.y + ClientSize.Height/2.0); + } + + private void beginDrag() { + dragging = true; + offset = activePoint.position - cursor; + activePoint.bringToFront(); + } + + private void endDrag() { + dragging = false; + offset = new Point(); + } + + public void onKeyDown(Object sender, KeyEventArgs e) { + switch(e.KeyCode) { + case Keys.D1: + new VanishingPoint(canvas, cursor); + break; + case Keys.D2: + new Grid(canvas, cursor); + break; + case Keys.Delete: + if (activePoint != null) + activePoint.assistant.remove(); + endDrag(); + break; + } + endDrag(); + Invalidate(); + } + + public void onMouseDown(Object sender, MouseEventArgs e) { + cursor = windowToCanvas(new Point(e.Location.X, e.Location.Y)); + if (e.Button == MouseButtons.Left) { + activePoint = canvas.findPoint(cursor); + if (activePoint != null) + beginDrag(); + } + Invalidate(); + } + + public void onMouseUp(Object sender, MouseEventArgs e) { + cursor = windowToCanvas(new Point(e.X, e.Y)); + if (e.Button == MouseButtons.Left) + endDrag(); + if (!dragging) + activePoint = canvas.findPoint(cursor); + Invalidate(); + } + + public void onMouseMove(Object sender, MouseEventArgs e) { + cursor = windowToCanvas(new Point(e.Location.X, e.Location.Y)); + if (dragging) { + activePoint.assistant.onMovePoint(activePoint, cursor + offset); + } else { + activePoint = canvas.findPoint(cursor); + } + Invalidate(); + } + + public void draw(Graphics g) { + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + g.TranslateTransform(0.5f*ClientSize.Width, 0.5f*ClientSize.Height); + canvas.draw(g, activePoint, cursor + offset); + } + } +} + diff --git a/mono/Assistance/Point.cs b/mono/Assistance/Point.cs new file mode 100644 index 0000000..6ab9fe6 --- /dev/null +++ b/mono/Assistance/Point.cs @@ -0,0 +1,65 @@ +using System; + +namespace Assistance { + public struct Point { + public static readonly double precision = 0.01; + + public double x; + public double y; + + public Point(double x, double y) { + this.x = x; + this.y = y; + } + + public static Point operator+ (Point a, Point b) { + return new Point(a.x + b.x, a.y + b.y); + } + + public static Point operator- (Point a, Point b) { + return new Point(a.x - b.x, a.y - b.y); + } + + public static Point operator* (Point a, double b) { + return new Point(a.x*b, a.y*b); + } + + public static Point operator* (double b, Point a) { + return a*b; + } + + public static Point operator/ (Point a, double b) { + return new Point(a.x/b, a.y/b); + } + + public static double dot(Point a, Point b) { + return a.x*b.x + a.y*b.y; + } + + public bool isEqual(Point other) { + return (this - other).lenSqr() <= precision*precision; + } + + public double lenSqr() { + return x*x + y*y; + } + + public double len() { + return Math.Sqrt(lenSqr()); + } + + public Point normalize() { + double l = len(); + return l > precision*precision*precision ? this/l : this; + } + + public System.Drawing.PointF toFloat() { + return new System.Drawing.PointF((float)x, (float)y); + } + + public System.Drawing.Point toInt() { + return new System.Drawing.Point((int)Math.Floor(x), (int)Math.Floor(y)); + } + } +} + diff --git a/mono/Assistance/VanishingPoint.cs b/mono/Assistance/VanishingPoint.cs new file mode 100644 index 0000000..c14d254 --- /dev/null +++ b/mono/Assistance/VanishingPoint.cs @@ -0,0 +1,120 @@ +using System; + +namespace Assistance { + public class VanishingPoint: Assistant { + public ActivePoint center; + public ActivePoint a0; + public ActivePoint a1; + public ActivePoint b0; + public ActivePoint b1; + public ActivePoint step; + + public VanishingPoint(Canvas canvas, Point center): base(canvas) { + this.center = new ActivePoint(this, ActivePoint.Type.CircleCross, center); + a0 = new ActivePoint(this, ActivePoint.Type.CircleFill, center + new Point(-100.0, 0.0)); + a1 = new ActivePoint(this, ActivePoint.Type.Circle, center + new Point(-200.0, 0.0)); + b0 = new ActivePoint(this, ActivePoint.Type.CircleFill, center + new Point(100.0, 0.0)); + b1 = new ActivePoint(this, ActivePoint.Type.Circle, center + new Point(200.0, 0.0)); + step = new ActivePoint(this, ActivePoint.Type.Circle, (a0.position + a1.position)/2); + } + + private void fixCenter() { + if (!a0.position.isEqual(a1.position) && !b0.position.isEqual(b1.position)) { + Point a = a0.position; + Point b = b0.position; + Point da = a1.position - a; + Point db = b1.position - b; + Point ab = b - a; + double k = db.x*da.y - db.y*da.x; + if (Math.Abs(k) > 0.00001) { + double lb = (da.x*ab.y - da.y*ab.x)/k; + center.position.x = lb*db.x + b.x; + center.position.y = lb*db.y + b.y; + } + } + } + + private void fixSidePoint(ActivePoint p0, ActivePoint p1, Point previousP0) { + if (!p0.position.isEqual(center.position)) { + Point dp0 = p0.position - center.position; + Point dp1 = p1.position - previousP0; + p1.position = center.position + dp0*(dp0.len() + dp1.len())/dp0.len(); + } + } + + private void fixSidePoint(ActivePoint p0, ActivePoint p1) { + fixSidePoint(p0, p1, p0.position); + } + + public void fixPoints() { + fixSidePoint(a0, a1); + fixSidePoint(a0, step); + fixSidePoint(b0, b1); + fixCenter(); + } + + public override void onMovePoint(ActivePoint point, Point position) { + Point previous = point.position; + point.position = position; + if (point == center) { + a0.position += point.position - previous; + a1.position += point.position - previous; + step.position += point.position - previous; + b0.position += point.position - previous; + b1.position += point.position - previous; + } else + if (point == a0) { + fixSidePoint(a0, a1, previous); + fixSidePoint(a0, step, previous); + fixSidePoint(b0, b1); + } else + if (point == b0) { + fixSidePoint(a0, a1); + fixSidePoint(a0, step); + fixSidePoint(b0, b1, previous); + } else { + fixCenter(); + fixSidePoint(a0, a1); + fixSidePoint(a0, step); + fixSidePoint(b0, b1); + } + } + + public override Point[] getGridPoints(Point target, bool truncate) { + double k = (a0.position - center.position).len(); + if (k < 0.00001) + return new Point[0]; + k = (step.position - center.position).len()/k; + + Point[] points = new Point[truncate ? gridPointsCount + 1 : gridPointsCount*2 + 1]; + Point a = target - center.position; + Point b = a; + points[gridPointsCount] = a + center.position; + for(int i = 1; i <= gridPointsCount; ++i) { + a /= k; + b *= k; + points[gridPointsCount - i] = a + center.position; + if (!truncate) + points[gridPointsCount + i] = b + center.position; + } + return points; + } + + public override void draw(System.Drawing.Graphics g) { + g.DrawLine(pen, center.position.toFloat(), a0.position.toFloat()); + g.DrawLine(pen, center.position.toFloat(), a1.position.toFloat()); + g.DrawLine(pen, center.position.toFloat(), b0.position.toFloat()); + g.DrawLine(pen, center.position.toFloat(), b1.position.toFloat()); + } + + public override void drawGuidlines(System.Drawing.Graphics g, Point target, bool truncate) { + if (truncate) { + g.DrawLine(guidePen, center.position.toFloat(), target.toFloat()); + } else { + Point p = (target - center.position).normalize()*getMaxLen() + center.position; + g.DrawLine(guidePen, center.position.toFloat(), p.toFloat()); + } + } + } +} +