├── SimpleCADTest ├── Resources │ ├── axis.png │ ├── disk.png │ ├── grid.png │ ├── snap.png │ ├── zoom.png │ ├── angle.png │ ├── cross.png │ ├── folder.png │ ├── arrow_all.png │ ├── coordinates.png │ ├── page_white.png │ ├── shape_copy.png │ ├── shape_scale.png │ ├── disk_multiple.png │ ├── shape_flip_horizontal.png │ ├── shape_move_backwards.png │ └── shape_rotate_clockwise.png ├── App.config ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ └── AssemblyInfo.cs ├── Program.cs └── SimpleCADTest.csproj ├── README.md ├── SimpleCAD ├── Document │ ├── IPersistable.cs │ ├── Enums.cs │ ├── LayerDictionary.cs │ ├── TextStyleDictionary.cs │ ├── CompositeDictionary.cs │ ├── IDict.cs │ ├── SettingsProperties.tt │ ├── Layer.cs │ ├── TextStyle.cs │ ├── PersistableDictionaryWithDefault.cs │ ├── DocumentWriter.cs │ ├── PersistableDictionary.cs │ ├── DocumentReader.cs │ ├── Model.cs │ ├── SettingsProperties.cs │ ├── Settings.cs │ └── CADDocument.cs ├── Commands │ ├── Command.cs │ ├── Command_Selection.cs │ ├── Command_Edit.cs │ ├── Command_Composite.cs │ ├── Command_Document.cs │ └── Command_View.cs ├── Editor │ ├── InitArgs.cs │ ├── InputArgs.cs │ ├── TextGetter.cs │ ├── EditorEvents.cs │ ├── SnapPoint.cs │ ├── ControlPoint.cs │ ├── PointGetter.cs │ ├── OpenFilenameGetter.cs │ ├── SaveFilenameGetter.cs │ ├── IntGetter.cs │ ├── CornerGetter.cs │ ├── FloatGetter.cs │ ├── AngleGetter.cs │ ├── DistanceGetter.cs │ ├── InputResult.cs │ ├── CPSelectionSet.cs │ ├── SnapPointCollection.cs │ ├── SelectionGetter.cs │ ├── SelectionSet.cs │ └── CPSelectionGetter.cs ├── Drawables │ ├── Polygon.cs │ ├── Hatch.cs │ ├── Drawable.cs │ ├── Point.cs │ ├── DrawableList.cs │ ├── DrawableDictionary.cs │ ├── CompositeReference.cs │ ├── Curve.cs │ ├── Rectangle.cs │ ├── Composite.cs │ ├── Circle.cs │ └── Line.cs ├── View │ ├── Axes.cs │ ├── ViewEvents.cs │ ├── SelectionWindow.cs │ ├── Camera.cs │ ├── Grid.cs │ └── Cursor.cs ├── CADWindow.Designer.cs ├── Properties │ └── AssemblyInfo.cs ├── Geometry │ ├── Point2DConverter.cs │ ├── Vector2DConverter.cs │ ├── Segment2DConverter.cs │ ├── Segment2D.cs │ ├── Point2D.cs │ ├── Extents2D.cs │ ├── Point2DCollection.cs │ ├── Vector2D.cs │ └── Matrix2D.cs ├── Graphics │ ├── Style.cs │ └── ColorConverter.cs ├── CADWindow.cs ├── MathF.cs └── CADWindow.resx ├── SimpleCAD.sln └── .gitignore /SimpleCADTest/Resources/axis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/axis.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/disk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/disk.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/grid.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/snap.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/zoom.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/angle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/angle.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/cross.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/folder.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/arrow_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/arrow_all.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/coordinates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/coordinates.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/page_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/page_white.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/shape_copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/shape_copy.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/shape_scale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/shape_scale.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/disk_multiple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/disk_multiple.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/shape_flip_horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/shape_flip_horizontal.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/shape_move_backwards.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/shape_move_backwards.png -------------------------------------------------------------------------------- /SimpleCADTest/Resources/shape_rotate_clockwise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oozcitak/SimpleCad/HEAD/SimpleCADTest/Resources/shape_rotate_clockwise.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleCad 2 | A basic CAD-like control surface for winforms (WIP). 3 | 4 | ![Screenshot](https://user-images.githubusercontent.com/188041/77572953-f2980480-6ee0-11ea-8213-662a20398639.png) 5 | -------------------------------------------------------------------------------- /SimpleCAD/Document/IPersistable.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleCAD 2 | { 3 | public interface IPersistable 4 | { 5 | void Load(DocumentReader reader); 6 | void Save(DocumentWriter writer); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /SimpleCADTest/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /SimpleCAD/Document/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleCAD 2 | { 3 | public enum AngleMode 4 | { 5 | Radians, 6 | Degrees, 7 | Grads, 8 | DegreesMinutesSeconds, 9 | Surveyor, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SimpleCAD/Document/LayerDictionary.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleCAD 2 | { 3 | public class LayerDictionary : PersistableDictionaryWithDefault 4 | { 5 | public LayerDictionary() : base("0", Layer.Default) 6 | { 7 | ; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SimpleCAD/Document/TextStyleDictionary.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleCAD 2 | { 3 | public class TextStyleDictionary : PersistableDictionaryWithDefault 4 | { 5 | public TextStyleDictionary() : base("0", TextStyle.Default) 6 | { 7 | ; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SimpleCADTest/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SimpleCAD/Document/CompositeDictionary.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Drawables; 2 | 3 | namespace SimpleCAD 4 | { 5 | public class CompositeDictionary : PersistableDictionary 6 | { 7 | public CompositeDictionary() : base() 8 | { 9 | ; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SimpleCAD/Commands/Command.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace SimpleCAD 4 | { 5 | public abstract class Command 6 | { 7 | public abstract string RegisteredName { get; } 8 | public abstract string Name { get; } 9 | 10 | public virtual Task Apply(CADDocument doc, params string[] args) 11 | { 12 | return Task.FromResult(default(object)); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SimpleCAD/Document/IDict.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SimpleCAD 4 | { 5 | public interface IDict : IEnumerable 6 | { 7 | int Count { get; } 8 | TValue this[string key] { get; set; } 9 | 10 | void Add(string key, TValue value); 11 | void Clear(); 12 | bool ContainsKey(string key); 13 | bool Remove(string key); 14 | bool TryGetValue(string key, out TValue value); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/InitArgs.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleCAD 2 | { 3 | internal class InitArgs 4 | { 5 | public TValue Value; 6 | public string ErrorMessage; 7 | public bool InputValid; 8 | public bool ContinueAsync; 9 | 10 | public InitArgs() 11 | { 12 | Value = default(TValue); 13 | InputValid = true; 14 | ContinueAsync = true; 15 | ErrorMessage = "*Invalid input*"; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SimpleCADTest/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace SimpleCADTest 5 | { 6 | static class Program 7 | { 8 | /// 9 | /// The main entry point for the application. 10 | /// 11 | [STAThread] 12 | static void Main() 13 | { 14 | Application.EnableVisualStyles(); 15 | Application.SetCompatibleTextRenderingDefault(false); 16 | Application.Run(new MainForm()); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SimpleCAD/Commands/Command_Selection.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace SimpleCAD.Commands 4 | { 5 | public class SelectionClear : Command 6 | { 7 | public override string RegisteredName => "Selection.Clear"; 8 | public override string Name => "Clear Selection"; 9 | 10 | public override Task Apply(CADDocument doc, params string[] args) 11 | { 12 | doc.Editor.CurrentSelection.Clear(); 13 | return Task.FromResult(default(object)); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SimpleCAD/Drawables/Polygon.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | using System.ComponentModel; 3 | using System.Drawing; 4 | 5 | namespace SimpleCAD.Drawables 6 | { 7 | public class Polygon : Polyline 8 | { 9 | [Browsable(false)] 10 | public override bool Closed => true; 11 | 12 | public Polygon() : base() { } 13 | public Polygon(Point2DCollection pts) : base(pts) { } 14 | public Polygon(params Point2D[] pts) : base(pts) { } 15 | public Polygon(PointF[] pts) : base(pts) { } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/InputArgs.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleCAD 2 | { 3 | internal class InputArgs 4 | { 5 | public readonly TInput Input; 6 | public TValue Value; 7 | public string ErrorMessage; 8 | public bool InputValid; 9 | public bool InputCompleted; 10 | 11 | public InputArgs(TInput input) 12 | { 13 | Input = input; 14 | Value = default(TValue); 15 | InputValid = true; 16 | InputCompleted = true; 17 | ErrorMessage = "*Invalid input*"; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /SimpleCAD/Document/SettingsProperties.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="false" language="C#" #> 2 | <#@ output extension=".cs" #> 3 | <#@ assembly name="$(TargetPath)" #> 4 | <#@ import namespace="SimpleCAD" #> 5 | 6 | namespace SimpleCAD 7 | { 8 | public partial class Settings 9 | { 10 | <# 11 | foreach(var pair in SimpleCAD.Settings.Defaults) 12 | { 13 | string name = pair.Key; 14 | string type = pair.Value.GetType().FullName; 15 | #> 16 | public <#= type #> <#= name #> 17 | { 18 | get => Get<<#= type #>>("<#= name#>"); 19 | set => Set("<#= name #>", value); 20 | } 21 | <# 22 | } 23 | #> 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/TextGetter.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | 3 | namespace SimpleCAD 4 | { 5 | internal class TextGetter : EditorGetter 6 | { 7 | public TextGetter() 8 | { 9 | SpaceAccepts = false; 10 | } 11 | 12 | protected override void TextChanged(string text) 13 | { 14 | SetCursorText(text); 15 | 16 | Options.Jig(text); 17 | } 18 | 19 | protected override void AcceptCoordsInput(InputArgs args) => 20 | args.InputValid = false; 21 | 22 | protected override void AcceptTextInput(InputArgs args) => 23 | args.Value = args.Input; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SimpleCAD/Drawables/Hatch.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | using SimpleCAD.Graphics; 3 | using System.Drawing; 4 | 5 | namespace SimpleCAD.Drawables 6 | { 7 | public class Hatch : Polygon 8 | { 9 | public Hatch() : base() 10 | { 11 | ; 12 | } 13 | 14 | public Hatch(Point2DCollection pts) : base(pts) 15 | { 16 | ; 17 | } 18 | 19 | public Hatch(params Point2D[] pts) : base(pts) 20 | { 21 | ; 22 | } 23 | 24 | public Hatch(PointF[] pts) : base(pts) 25 | { 26 | ; 27 | } 28 | 29 | public override void Draw(Renderer renderer) 30 | { 31 | renderer.FillPolygon(Style.ApplyLayer(Layer), Points); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/EditorEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SimpleCAD 4 | { 5 | public delegate void EditorPromptEventHandler(object sender, EditorPromptEventArgs e); 6 | public delegate void EditorErrorEventHandler(object sender, EditorErrorEventArgs e); 7 | 8 | public class EditorPromptEventArgs : EventArgs 9 | { 10 | public string Status { get; private set; } 11 | 12 | public EditorPromptEventArgs() : this("") 13 | { 14 | ; 15 | } 16 | 17 | public EditorPromptEventArgs(string status) : base() 18 | { 19 | Status = status; 20 | } 21 | } 22 | 23 | public class EditorErrorEventArgs : EventArgs 24 | { 25 | public Exception Error { get; private set; } 26 | 27 | public EditorErrorEventArgs(Exception error) : base() 28 | { 29 | Error = error; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /SimpleCAD/View/Axes.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | using SimpleCAD.Graphics; 3 | 4 | namespace SimpleCAD.View 5 | { 6 | internal class Axes : Drawable 7 | { 8 | public override void Draw(Renderer renderer) 9 | { 10 | var view = renderer.View; 11 | var doc = view.Document; 12 | 13 | Extents2D bounds = view.GetViewport(); 14 | Color axisColor = doc.Settings.AxisColor; 15 | 16 | renderer.DrawLine(new Style(axisColor), new Point2D(0, bounds.Ymin), new Point2D(0, bounds.Ymax)); 17 | renderer.DrawLine(new Style(axisColor), new Point2D(bounds.Xmin, 0), new Point2D(bounds.Xmax, 0)); 18 | } 19 | 20 | public override Extents2D GetExtents() 21 | { 22 | return Extents2D.Empty; 23 | } 24 | 25 | public override void TransformBy(Matrix2D transformation) 26 | { 27 | ; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SimpleCAD/Commands/Command_Edit.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace SimpleCAD.Commands 5 | { 6 | public class EditDelete : Command 7 | { 8 | public override string RegisteredName => "Edit.Delete"; 9 | public override string Name => "Delete"; 10 | 11 | public override async Task Apply(CADDocument doc, params string[] args) 12 | { 13 | Editor ed = doc.Editor; 14 | 15 | var s = await ed.GetSelection("Select objects: "); 16 | if (s.Result != ResultMode.OK || s.Value.Count == 0) return; 17 | List toDelete = new List(); 18 | foreach (Drawable item in s.Value) 19 | { 20 | toDelete.Add(item); 21 | } 22 | foreach(Drawable item in toDelete ) 23 | { 24 | doc.Model.Remove(item); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/SnapPoint.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | using System; 3 | 4 | namespace SimpleCAD 5 | { 6 | [Flags] 7 | public enum SnapPointType 8 | { 9 | None = 0, 10 | End = 1, 11 | Middle = 2, 12 | Center = 4, 13 | Quadrant = 8, 14 | Point = 16, 15 | All = End | Middle | Center | Quadrant | Point 16 | } 17 | 18 | public class SnapPoint 19 | { 20 | public string Name { get; private set; } 21 | public SnapPointType Type { get; private set; } 22 | public Point2D Location { get; private set; } 23 | 24 | public SnapPoint(string name, Point2D location) : this(name, SnapPointType.End, location) 25 | { 26 | ; 27 | } 28 | 29 | public SnapPoint(string name, SnapPointType type, Point2D location) 30 | { 31 | Name = name; 32 | Type = type; 33 | Location = location; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/ControlPoint.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | 3 | namespace SimpleCAD 4 | { 5 | public enum ControlPointType 6 | { 7 | Point, 8 | Angle, 9 | Distance 10 | } 11 | 12 | public class ControlPoint 13 | { 14 | public string Name { get; private set; } 15 | public ControlPointType Type { get; private set; } 16 | public Point2D BasePoint { get; private set; } 17 | public Point2D Location { get; private set; } 18 | internal int Index; 19 | 20 | public ControlPoint(string name, Point2D basePoint) 21 | : this(name, ControlPointType.Point, basePoint, basePoint) 22 | { 23 | ; 24 | } 25 | 26 | public ControlPoint(string name, ControlPointType type, Point2D basePoint, Point2D location) 27 | { 28 | Name = name; 29 | Type = type; 30 | BasePoint = basePoint; 31 | Location = location; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/PointGetter.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Drawables; 2 | using SimpleCAD.Geometry; 3 | 4 | namespace SimpleCAD 5 | { 6 | internal class PointGetter : EditorGetter 7 | { 8 | protected override void Init(InitArgs args) 9 | { 10 | if (Options.HasBasePoint) 11 | Jigged = new Line(Options.BasePoint, Options.BasePoint); 12 | } 13 | 14 | protected override void CoordsChanged(Point2D pt) 15 | { 16 | SetCursorText(pt.ToString(Editor.Document.Settings.NumberFormat)); 17 | 18 | if (Options.HasBasePoint) 19 | (Jigged as Line).EndPoint = pt; 20 | 21 | Options.Jig(pt); 22 | } 23 | 24 | protected override void AcceptCoordsInput(InputArgs args) => 25 | args.Value = args.Input; 26 | 27 | protected override void AcceptTextInput(InputArgs args) => 28 | args.InputValid = Point2D.TryParse(args.Input, out args.Value); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SimpleCAD/View/ViewEvents.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | using System; 3 | using System.Windows.Forms; 4 | 5 | namespace SimpleCAD 6 | { 7 | public delegate void CursorEventHandler(object sender, CursorEventArgs e); 8 | 9 | public class CursorEventArgs : EventArgs 10 | { 11 | public MouseButtons Button { get; private set; } 12 | public Point2D Location { get; private set; } 13 | public int Clicks { get; private set; } 14 | public int Delta { get; private set; } 15 | 16 | public float X { get { return Location.X; } } 17 | public float Y { get { return Location.Y; } } 18 | 19 | public CursorEventArgs(MouseButtons button, int clicks, Point2D location, int delta) 20 | { 21 | Button = button; 22 | Location = location; 23 | Clicks = clicks; 24 | Delta = delta; 25 | } 26 | 27 | public CursorEventArgs(MouseButtons button, int clicks, float x, float y, int delta) 28 | : this(button, clicks, new Point2D(x, y), delta) 29 | { 30 | ; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/OpenFilenameGetter.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Windows.Forms; 3 | 4 | namespace SimpleCAD 5 | { 6 | internal class OpenFilenameGetter : EditorGetter 7 | { 8 | protected override void Init(InitArgs args) 9 | { 10 | OpenFileDialog ofd = new OpenFileDialog(); 11 | ofd.Title = Options.Message; 12 | ofd.Filter = Options.Filter; 13 | ofd.DefaultExt = "scf"; 14 | string filename = ""; 15 | string path = ""; 16 | if (File.Exists(Options.FileName)) 17 | { 18 | filename = Path.GetFileName(Options.FileName); 19 | path = Path.GetDirectoryName(Options.FileName); 20 | } 21 | if (!string.IsNullOrEmpty(filename)) ofd.FileName = filename; 22 | if (!string.IsNullOrEmpty(path)) ofd.InitialDirectory = path; 23 | 24 | if (ofd.ShowDialog() == DialogResult.OK) 25 | args.Value = ofd.FileName; 26 | else 27 | args.InputValid = false; 28 | 29 | args.ContinueAsync = false; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /SimpleCADTest/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SimpleCADTest.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.6.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 18 | 19 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 20 | 21 | public static Settings Default { 22 | get { 23 | return defaultInstance; 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SimpleCAD/Document/Layer.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Graphics; 2 | using System.ComponentModel; 3 | 4 | namespace SimpleCAD 5 | { 6 | [TypeConverter(typeof(ExpandableObjectConverter))] 7 | public class Layer : IPersistable 8 | { 9 | public static Layer Default => new Layer("0", new Style(Color.White)); 10 | 11 | public string Name { get; private set; } 12 | public Style Style { get; set; } = new Style(Color.White, 0, DashStyle.Solid); 13 | public bool Visible { get; set; } = true; 14 | 15 | public Layer() 16 | { 17 | ; 18 | } 19 | 20 | public Layer(string name, Style style) 21 | { 22 | Name = name; 23 | Style = style; 24 | } 25 | 26 | public void Load(DocumentReader reader) 27 | { 28 | Name = reader.ReadString(); 29 | Style = new Style(); 30 | Style.Load(reader); 31 | Visible = reader.ReadBoolean(); 32 | } 33 | 34 | public void Save(DocumentWriter writer) 35 | { 36 | writer.Write(Name); 37 | Style.Save(writer); 38 | writer.Write(Visible); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/SaveFilenameGetter.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Windows.Forms; 3 | 4 | namespace SimpleCAD 5 | { 6 | internal class SaveFilenameGetter : EditorGetter 7 | { 8 | protected override void Init(InitArgs args) 9 | { 10 | SaveFileDialog sfd = new SaveFileDialog(); 11 | sfd.Title = Options.Message; 12 | sfd.Filter = Options.Filter; 13 | sfd.DefaultExt = "scf"; 14 | string filename = ""; 15 | string path = ""; 16 | try 17 | { 18 | filename = Path.GetFileName(Options.FileName); 19 | path = Path.GetDirectoryName(Options.FileName); 20 | } 21 | catch 22 | { 23 | ; 24 | } 25 | if (!string.IsNullOrEmpty(filename)) sfd.FileName = filename; 26 | if (!string.IsNullOrEmpty(path)) sfd.InitialDirectory = path; 27 | 28 | if (sfd.ShowDialog() == DialogResult.OK) 29 | args.Value = sfd.FileName; 30 | else 31 | args.InputValid = false; 32 | 33 | args.ContinueAsync = false; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SimpleCAD/Document/TextStyle.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Graphics; 2 | using System.ComponentModel; 3 | 4 | namespace SimpleCAD 5 | { 6 | [TypeConverter(typeof(ExpandableObjectConverter))] 7 | public class TextStyle : IPersistable 8 | { 9 | public static TextStyle Default => new TextStyle("0", "Calibri Light", FontStyle.Regular); 10 | 11 | public string Name { get; private set; } 12 | public string FontFamily { get; set; } 13 | public FontStyle FontStyle { get; set; } 14 | 15 | public TextStyle() 16 | { 17 | ; 18 | } 19 | 20 | public TextStyle(string name, string fontFamily, FontStyle fontStyle) 21 | { 22 | Name = name; 23 | FontFamily = fontFamily; 24 | FontStyle = fontStyle; 25 | } 26 | 27 | public void Load(DocumentReader reader) 28 | { 29 | Name = reader.ReadString(); 30 | FontFamily = reader.ReadString(); 31 | FontStyle = (FontStyle)reader.ReadInt(); 32 | } 33 | 34 | public void Save(DocumentWriter writer) 35 | { 36 | writer.Write(Name); 37 | writer.Write(FontFamily); 38 | writer.Write((int)FontStyle); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /SimpleCAD/Document/PersistableDictionaryWithDefault.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SimpleCAD 4 | { 5 | public abstract class PersistableDictionaryWithDefault : PersistableDictionary where TValue : IPersistable, new() 6 | { 7 | public string DefaultKey { get; private set; } 8 | public TValue Default { get => dict[DefaultKey]; } 9 | 10 | public PersistableDictionaryWithDefault(string defaultKey, TValue defaultValue) : base() 11 | { 12 | DefaultKey = defaultKey; 13 | dict.Add(defaultKey, defaultValue); 14 | } 15 | 16 | public TValue GetOrDefault(string key) 17 | { 18 | if (dict.TryGetValue(key, out var value)) 19 | return value; 20 | else 21 | return Default; 22 | } 23 | 24 | public override void Clear() 25 | { 26 | TValue defaultValue = dict[DefaultKey]; 27 | dict.Clear(); 28 | dict.Add(DefaultKey, defaultValue); 29 | } 30 | 31 | public override bool Remove(string key) 32 | { 33 | if(dict.Comparer.Equals(key, DefaultKey)) 34 | return false; 35 | else 36 | return dict.Remove(key); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/IntGetter.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | 3 | namespace SimpleCAD 4 | { 5 | internal class IntGetter : EditorGetter 6 | { 7 | protected override void AcceptCoordsInput(InputArgs args) => 8 | args.InputValid = false; 9 | 10 | protected override void AcceptTextInput(InputArgs args) 11 | { 12 | if (int.TryParse(args.Input, out args.Value)) 13 | { 14 | if (!Options.AllowNegative && args.Value < 0) 15 | { 16 | args.ErrorMessage = "*Negative numbers are not allowed*"; 17 | args.InputValid = false; 18 | } 19 | else if (!Options.AllowPositive && args.Value > 0) 20 | { 21 | args.ErrorMessage = "*Positive numbers are not allowed*"; 22 | args.InputValid = false; 23 | } 24 | else if (!Options.AllowZero && args.Value == 0) 25 | { 26 | args.ErrorMessage = "*Zero is not allowed*"; 27 | args.InputValid = false; 28 | } 29 | } 30 | else 31 | { 32 | args.InputValid = false; 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/CornerGetter.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Drawables; 2 | using SimpleCAD.Geometry; 3 | 4 | namespace SimpleCAD 5 | { 6 | internal class CornerGetter : EditorGetter 7 | { 8 | protected override void Init(InitArgs args) 9 | { 10 | Jigged = new Polygon(Options.BasePoint, Options.BasePoint, Options.BasePoint, Options.BasePoint); 11 | } 12 | 13 | protected override void CoordsChanged(Point2D pt) 14 | { 15 | SetCursorText(pt.ToString(Editor.Document.Settings.NumberFormat)); 16 | 17 | Polygon poly = Jigged as Polygon; 18 | Point2D pc1 = poly.Points[0]; 19 | Point2D pc2 = new Point2D(pt.X, pc1.Y); 20 | Point2D pc3 = pt; 21 | Point2D pc4 = new Point2D(pc1.X, pt.Y); 22 | poly.Points[0] = pc1; 23 | poly.Points[1] = pc2; 24 | poly.Points[2] = pc3; 25 | poly.Points[3] = pc4; 26 | 27 | Options.Jig(pt); 28 | } 29 | 30 | protected override void AcceptCoordsInput(InputArgs args) => 31 | args.Value = args.Input; 32 | 33 | protected override void AcceptTextInput(InputArgs args) => 34 | args.InputValid = Point2D.TryParse(args.Input, out args.Value); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/FloatGetter.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | 3 | namespace SimpleCAD 4 | { 5 | internal class FloatGetter : EditorGetter 6 | { 7 | protected override void AcceptCoordsInput(InputArgs args) => 8 | args.InputValid = false; 9 | 10 | protected override void AcceptTextInput(InputArgs args) 11 | { 12 | if (float.TryParse(args.Input, out args.Value)) 13 | { 14 | if (!Options.AllowNegative && args.Value < 0) 15 | { 16 | args.ErrorMessage = "*Negative numbers are not allowed*"; 17 | args.InputValid = false; 18 | } 19 | else if (!Options.AllowPositive && args.Value > 0) 20 | { 21 | args.ErrorMessage = "*Positive numbers are not allowed*"; 22 | args.InputValid = false; 23 | } 24 | else if (!Options.AllowZero && args.Value == 0) 25 | { 26 | args.ErrorMessage = "*Zero is not allowed*"; 27 | args.InputValid = false; 28 | } 29 | } 30 | else 31 | { 32 | args.InputValid = false; 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/AngleGetter.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Drawables; 2 | using SimpleCAD.Geometry; 3 | 4 | namespace SimpleCAD 5 | { 6 | internal class AngleGetter : EditorGetter 7 | { 8 | protected override void Init(InitArgs args) 9 | { 10 | Jigged = new Line(Options.BasePoint, Options.BasePoint); 11 | } 12 | 13 | protected override void CoordsChanged(Point2D pt) 14 | { 15 | float angle = (pt - Options.BasePoint).Angle; 16 | SetCursorText(Editor.AngleToString(angle)); 17 | 18 | (Jigged as Line).EndPoint = pt; 19 | 20 | Options.Jig(angle); 21 | } 22 | 23 | protected override void AcceptCoordsInput(InputArgs args) => 24 | args.Value = (args.Input - Options.BasePoint).Angle; 25 | 26 | protected override void AcceptTextInput(InputArgs args) 27 | { 28 | if (Editor.TryAngleFromString(args.Input, out float angle)) 29 | { 30 | args.Value = angle; 31 | } 32 | else if (Vector2D.TryParse(args.Input, out Vector2D vec)) 33 | { 34 | args.Value = vec.Angle; 35 | } 36 | else 37 | { 38 | args.InputValid = false; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/DistanceGetter.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Drawables; 2 | using SimpleCAD.Geometry; 3 | 4 | namespace SimpleCAD 5 | { 6 | internal class DistanceGetter : EditorGetter 7 | { 8 | protected override void Init(InitArgs args) 9 | { 10 | Jigged = new Line(Options.BasePoint, Options.BasePoint); 11 | } 12 | 13 | protected override void CoordsChanged(Point2D pt) 14 | { 15 | float dist = (pt - Options.BasePoint).Length; 16 | SetCursorText(dist.ToString(Editor.Document.Settings.NumberFormat)); 17 | 18 | (Jigged as Line).EndPoint = pt; 19 | 20 | Options.Jig(dist); 21 | } 22 | 23 | protected override void AcceptCoordsInput(InputArgs args) => 24 | args.Value = (args.Input - Options.BasePoint).Length; 25 | 26 | protected override void AcceptTextInput(InputArgs args) 27 | { 28 | if (Vector2D.TryParse(args.Input, out Vector2D vec)) 29 | { 30 | args.Value = vec.Length; 31 | } 32 | else if (float.TryParse(args.Input, out args.Value)) 33 | { 34 | ; 35 | } 36 | else 37 | { 38 | args.InputValid = false; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /SimpleCAD/View/SelectionWindow.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | using SimpleCAD.Graphics; 3 | 4 | namespace SimpleCAD.View 5 | { 6 | internal class SelectionWindow : Drawable 7 | { 8 | public Point2D P1 { get; set; } 9 | public Point2D P2 { get; set; } 10 | 11 | public bool WindowSelection => P2.X > P1.X; 12 | 13 | public SelectionWindow(Point2D p1, Point2D p2) 14 | { 15 | P1 = p1; 16 | P2 = p2; 17 | } 18 | 19 | public override void Draw(Renderer renderer) 20 | { 21 | var doc = renderer.View.Document; 22 | 23 | Style fillStyle = (WindowSelection ? new Style(doc.Settings.SelectionWindowColor) : new Style(doc.Settings.ReverseSelectionWindowColor)); 24 | Style outlineStyle = (WindowSelection ? new Style(doc.Settings.SelectionWindowBorderColor) : new Style(doc.Settings.SelectionWindowBorderColor, 0, DashStyle.Dash)); 25 | 26 | renderer.FillRectangle(fillStyle, P1, P2); 27 | renderer.DrawRectangle(outlineStyle, P1, P2); 28 | } 29 | 30 | public override Extents2D GetExtents() 31 | { 32 | Extents2D ex = new Extents2D(); 33 | ex.Add(P1); 34 | ex.Add(P2); 35 | return ex; 36 | } 37 | 38 | public override void TransformBy(Matrix2D transformation) 39 | { 40 | ; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SimpleCADTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("SimpleCADTest")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("SimpleCADTest")] 12 | [assembly: AssemblyCopyright("Copyright © 2018")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("7c00350a-2fa9-4eb1-9475-76732dc9eeb6")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /SimpleCAD/CADWindow.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleCAD 2 | { 3 | partial class CADWindow 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.SuspendLayout(); 32 | // 33 | // CADWindow 34 | // 35 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 36 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 37 | this.Name = "CADWindow"; 38 | this.Size = new System.Drawing.Size(683, 424); 39 | this.ResumeLayout(false); 40 | 41 | } 42 | 43 | #endregion 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /SimpleCAD/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("SimpleCAD")] 8 | [assembly: AssemblyDescription("A basic CAD-like control surface for winforms.")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("SimpleCAD")] 12 | [assembly: AssemblyCopyright("")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("09d0c2a2-1aa1-49d6-b3c7-1e7d4da31a18")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.1.0")] 35 | [assembly: AssemblyFileVersion("1.0.1.0")] 36 | -------------------------------------------------------------------------------- /SimpleCAD.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2027 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleCAD", "SimpleCAD\SimpleCAD.csproj", "{473B4BE8-4019-4A0C-8B73-59A2A07ED028}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleCADTest", "SimpleCADTest\SimpleCADTest.csproj", "{7C00350A-2FA9-4EB1-9475-76732DC9EEB6}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {473B4BE8-4019-4A0C-8B73-59A2A07ED028}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {473B4BE8-4019-4A0C-8B73-59A2A07ED028}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {473B4BE8-4019-4A0C-8B73-59A2A07ED028}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {473B4BE8-4019-4A0C-8B73-59A2A07ED028}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {7C00350A-2FA9-4EB1-9475-76732DC9EEB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {7C00350A-2FA9-4EB1-9475-76732DC9EEB6}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {7C00350A-2FA9-4EB1-9475-76732DC9EEB6}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {7C00350A-2FA9-4EB1-9475-76732DC9EEB6}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {D8E32F36-44D8-4531-8406-EF5032B95559} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/InputResult.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleCAD 2 | { 3 | public enum ResultMode 4 | { 5 | OK, 6 | Keyword, 7 | Cancel 8 | } 9 | 10 | internal enum AcceptReason 11 | { 12 | None, 13 | Init, 14 | Coords, 15 | Text, 16 | Keyword 17 | } 18 | 19 | internal enum CancelReason 20 | { 21 | None, 22 | Init, 23 | Escape, 24 | Space, 25 | Enter 26 | } 27 | 28 | public class InputResult 29 | { 30 | public ResultMode Result { get; private set; } 31 | public TInput Value { get; private set; } 32 | public string Keyword { get; private set; } 33 | internal AcceptReason AcceptReason { get; private set; } 34 | internal CancelReason CancelReason { get; private set; } 35 | 36 | internal static InputResult CancelResult(CancelReason cancelReason) => new InputResult(ResultMode.Cancel, default(TInput), "", AcceptReason.None, cancelReason); 37 | internal static InputResult KeywordResult(string keyword) => new InputResult(ResultMode.Keyword, default(TInput), keyword, AcceptReason.Keyword, CancelReason.None); 38 | internal static InputResult AcceptResult(TInput value, AcceptReason acceptReason) => new InputResult(ResultMode.OK, value, "", acceptReason, CancelReason.None); 39 | 40 | private InputResult(ResultMode result, TInput value, string keyword, AcceptReason acceptReason, CancelReason cancelReason) 41 | { 42 | Result = result; 43 | Value = value; 44 | Keyword = keyword; 45 | AcceptReason = acceptReason; 46 | CancelReason = cancelReason; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /SimpleCAD/Commands/Command_Composite.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Drawables; 2 | using SimpleCAD.Geometry; 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | 6 | namespace SimpleCAD.Commands 7 | { 8 | public class CompositeCreate : Command 9 | { 10 | public override string RegisteredName => "Composite.Create"; 11 | public override string Name => "Create Composite"; 12 | 13 | public override async Task Apply(CADDocument doc, params string[] args) 14 | { 15 | Editor ed = doc.Editor; 16 | 17 | var s = await ed.GetSelection("Select objects: "); 18 | if (s.Result != ResultMode.OK || s.Value.Count == 0) return; 19 | var p = await ed.GetPoint("Base point: "); 20 | if (p.Result != ResultMode.OK) return; 21 | var t = await ed.GetText("Name: "); 22 | if (t.Result != ResultMode.OK || string.IsNullOrEmpty(t.Value)) return; 23 | 24 | Composite composite = new Composite(); 25 | composite.Name = t.Value; 26 | 27 | Matrix2D matrix = Matrix2D.Translation(-1 * p.Value.AsVector2D()); 28 | List toDelete = new List(); 29 | foreach (Drawable item in s.Value) 30 | { 31 | item.TransformBy(matrix); 32 | toDelete.Add(item); 33 | composite.Add(item); 34 | } 35 | 36 | doc.Composites.Add(composite.Name, composite); 37 | 38 | foreach (Drawable item in toDelete) 39 | { 40 | doc.Model.Remove(item); 41 | } 42 | 43 | CompositeReference compRef = new CompositeReference(); 44 | compRef.Composite = composite; 45 | compRef.Location = p.Value; 46 | doc.Model.Add(compRef); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /SimpleCAD/Editor/CPSelectionSet.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace SimpleCAD 5 | { 6 | public sealed class CPSelectionSet 7 | { 8 | Dictionary> items = new Dictionary>(); 9 | 10 | public static CPSelectionSet Empty => new CPSelectionSet(); 11 | 12 | public int[] this[Drawable item] => items[item].ToArray(); 13 | 14 | public CPSelectionSet() 15 | { 16 | ; 17 | } 18 | 19 | public bool Add(Drawable item, int index) 20 | { 21 | if (items.TryGetValue(item, out var indices)) 22 | { 23 | return indices.Add(index); 24 | } 25 | else 26 | { 27 | items.Add(item, new HashSet() { index }); 28 | return true; 29 | } 30 | } 31 | 32 | public void Add(Drawable item, IEnumerable indices) 33 | { 34 | foreach (int index in indices) 35 | { 36 | Add(item, index); 37 | } 38 | } 39 | 40 | public void Clear() 41 | { 42 | items.Clear(); 43 | } 44 | 45 | public int Count { get { return items.Count; } } 46 | 47 | public IEnumerator>> GetEnumerator() 48 | { 49 | return items.GetEnumerator(); 50 | } 51 | 52 | public void UnionWith(CPSelectionSet other) 53 | { 54 | foreach (var item in other) 55 | { 56 | foreach (int index in item.Value) 57 | { 58 | Add(item.Key, index); 59 | } 60 | } 61 | } 62 | 63 | public SelectionSet ToSelectionSet() 64 | { 65 | SelectionSet ss = new SelectionSet(); 66 | foreach (var pair in items) 67 | { 68 | ss.Add(pair.Key); 69 | } 70 | return ss; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /SimpleCAD/View/Camera.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | using System.ComponentModel; 3 | 4 | namespace SimpleCAD 5 | { 6 | public class Camera 7 | { 8 | private Point2D position; 9 | private float zoom; 10 | 11 | [Category("Appearance"), DefaultValue(5f / 3f), Description("Determines the zoom factor of the view.")] 12 | public float Zoom 13 | { 14 | get 15 | { 16 | return zoom; 17 | } 18 | set 19 | { 20 | zoom = value; 21 | 22 | if (float.IsNaN(zoom) || float.IsNegativeInfinity(zoom) || float.IsPositiveInfinity(zoom) || 23 | zoom < float.Epsilon * 1000.0f || zoom > float.MaxValue / 1000.0f) 24 | { 25 | zoom = 1; 26 | } 27 | } 28 | } 29 | 30 | [Category("Appearance"), DefaultValue(typeof(System.Drawing.PointF), "0,0"), Description("Determines the location of the camera.")] 31 | public Point2D Position 32 | { 33 | get 34 | { 35 | return position; 36 | } 37 | set 38 | { 39 | position = value; 40 | float x = position.X; 41 | float y = position.Y; 42 | if (float.IsNaN(x) || float.IsNegativeInfinity(x) || float.IsPositiveInfinity(x) || 43 | x < float.MinValue / 1000.0f || x > float.MaxValue / 1000.0f) 44 | { 45 | x = 0; 46 | } 47 | if (float.IsNaN(y) || float.IsNegativeInfinity(y) || float.IsPositiveInfinity(y) || 48 | y < float.MinValue / 1000.0f || y > float.MaxValue / 1000.0f) 49 | { 50 | y = 0; 51 | } 52 | position = new Point2D(x, y); 53 | } 54 | } 55 | 56 | public Camera(Point2D position, float zoom) 57 | { 58 | this.position = position; 59 | this.zoom = zoom; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /SimpleCAD/Document/DocumentWriter.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | using SimpleCAD.Graphics; 3 | using System; 4 | using System.IO; 5 | 6 | namespace SimpleCAD 7 | { 8 | public sealed class DocumentWriter : IDisposable 9 | { 10 | BinaryWriter writer; 11 | 12 | public CADDocument Document { get; private set; } 13 | 14 | public DocumentWriter(CADDocument document, Stream stream) 15 | { 16 | Document = document; 17 | writer = new BinaryWriter(stream); 18 | } 19 | 20 | public void Write(bool value) 21 | { 22 | writer.Write(value); 23 | } 24 | 25 | public void Write(float value) 26 | { 27 | writer.Write(value); 28 | } 29 | 30 | public void Write(int value) 31 | { 32 | writer.Write(value); 33 | } 34 | 35 | public void Write(uint value) 36 | { 37 | writer.Write(value); 38 | } 39 | 40 | public void Write(string value) 41 | { 42 | writer.Write(value); 43 | } 44 | 45 | public void Write(Point2D value) 46 | { 47 | Write(value.X); 48 | Write(value.Y); 49 | } 50 | 51 | public void Write(Point2DCollection value) 52 | { 53 | Write(value.Count); 54 | foreach (Point2D point in value) 55 | Write(point); 56 | } 57 | 58 | public void Write(Vector2D value) 59 | { 60 | Write(value.X); 61 | Write(value.Y); 62 | } 63 | 64 | public void Write(Color value) 65 | { 66 | Write(value.IsByLayer); 67 | Write(value.Argb); 68 | } 69 | 70 | public void Write(Camera value) 71 | { 72 | Write(value.Position); 73 | Write(value.Zoom); 74 | } 75 | 76 | public void Write(IPersistable item) 77 | { 78 | Write(item.GetType().FullName); 79 | item.Save(this); 80 | } 81 | 82 | public void Dispose() 83 | { 84 | writer.Dispose(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | [Ww]in32/ 5 | [Xx]64/ 6 | 7 | # mstest test results 8 | TestResults 9 | 10 | ## Ignore Visual Studio temporary files, build results, and 11 | ## files generated by popular Visual Studio add-ons. 12 | 13 | # User-specific files 14 | *.suo 15 | # *.user 16 | *.sln.docstates 17 | 18 | # Build results 19 | [Dd]ebug/ 20 | [Rr]elease/ 21 | x64/ 22 | *_i.c 23 | *_i.h 24 | *_p.c 25 | *.ilk 26 | *.meta 27 | *.obj 28 | *.pch 29 | *.pdb 30 | *.pgc 31 | *.pgd 32 | *.rsp 33 | *.sbr 34 | *.tlb 35 | *.tli 36 | *.tlh 37 | *.tmp 38 | *.vspscc 39 | *.vssscc 40 | .builds 41 | *.msi 42 | *.msm 43 | 44 | # Visual Studio 2015/2017 cache/options directory 45 | .vs/ 46 | 47 | # Visual C++ cache files 48 | ipch/ 49 | *.aps 50 | *.ncb 51 | *.opensdf 52 | *.sdf 53 | 54 | # Visual Studio profiler 55 | *.psess 56 | *.vsp 57 | 58 | # Guidance Automation Toolkit 59 | *.gpState 60 | 61 | # ReSharper is a .NET coding add-in 62 | _ReSharper* 63 | 64 | # NCrunch 65 | *.ncrunch* 66 | .*crunch*.local.xml 67 | 68 | # Installshield output folder 69 | [Ee]xpress 70 | 71 | # DocProject is a documentation generator add-in 72 | DocProject/buildhelp/ 73 | DocProject/Help/*.HxT 74 | DocProject/Help/*.HxC 75 | DocProject/Help/*.hhc 76 | DocProject/Help/*.hhk 77 | DocProject/Help/*.hhp 78 | DocProject/Help/Html2 79 | DocProject/Help/html 80 | 81 | # Click-Once directory 82 | publish 83 | 84 | # Publish Web Output 85 | *.Publish.xml 86 | 87 | # Others 88 | [Bb]in 89 | [Oo]bj 90 | sql 91 | TestResults 92 | [Tt]est[Rr]esult* 93 | *.Cache 94 | ClientBin 95 | [Ss]tyle[Cc]op.* 96 | ~$* 97 | *.dbmdl 98 | Generated_Code #added for RIA/Silverlight projects 99 | 100 | # Backup & report files from converting an old project file to a newer 101 | # Visual Studio version. Backup files are not needed, because we have git ;-) 102 | _UpgradeReport_Files/ 103 | Backup*/ 104 | UpgradeLog*.XML 105 | 106 | # Compiled Object files 107 | *.slo 108 | *.lo 109 | *.o 110 | 111 | # Compiled Dynamic libraries 112 | *.so 113 | 114 | # Compiled Static libraries 115 | *.lai 116 | *.la 117 | *.a 118 | *.opendb 119 | *.db 120 | -------------------------------------------------------------------------------- /SimpleCAD/Document/PersistableDictionary.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | 4 | namespace SimpleCAD 5 | { 6 | public abstract class PersistableDictionary : IPersistable, IDict where TValue : IPersistable, new() 7 | { 8 | protected Dictionary dict = new Dictionary(); 9 | 10 | public virtual TValue this[string key] { get => dict[key]; set => dict[key] = value; } 11 | 12 | public virtual int Count => dict.Count; 13 | 14 | public virtual void Load(DocumentReader reader) 15 | { 16 | dict = new Dictionary(); 17 | int count = reader.ReadInt(); 18 | for (int i = 0; i < count; i++) 19 | { 20 | string key = reader.ReadString(); 21 | TValue value = reader.ReadPersistable(); 22 | dict.Add(key, value); 23 | } 24 | } 25 | 26 | public virtual void Save(DocumentWriter writer) 27 | { 28 | writer.Write(dict.Count); 29 | foreach (var pair in dict) 30 | { 31 | writer.Write(pair.Key); 32 | writer.Write(pair.Value); 33 | } 34 | } 35 | 36 | public virtual void Add(string key, TValue value) 37 | { 38 | dict.Add(key, value); 39 | } 40 | 41 | public virtual void Clear() 42 | { 43 | dict.Clear(); 44 | } 45 | 46 | public virtual bool ContainsKey(string key) 47 | { 48 | return dict.ContainsKey(key); 49 | } 50 | 51 | public virtual IEnumerator GetEnumerator() 52 | { 53 | foreach (TValue value in dict.Values) 54 | yield return value; 55 | } 56 | 57 | public virtual bool Remove(string key) 58 | { 59 | return dict.Remove(key); 60 | } 61 | 62 | public virtual bool TryGetValue(string key, out TValue value) 63 | { 64 | return dict.TryGetValue(key, out value); 65 | } 66 | 67 | IEnumerator IEnumerable.GetEnumerator() 68 | { 69 | return GetEnumerator(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /SimpleCAD/Geometry/Point2DConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace SimpleCAD.Geometry 5 | { 6 | public class Point2DConverter : ExpandableObjectConverter 7 | { 8 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 9 | { 10 | return sourceType == typeof(string); 11 | } 12 | 13 | public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 14 | { 15 | return destinationType == typeof(string); 16 | } 17 | 18 | public override bool IsValid(ITypeDescriptorContext context, object value) 19 | { 20 | string str = value as string; 21 | 22 | if (str == null) return false; 23 | 24 | string[] parts = str.Replace(" ", "").Split(';', ','); 25 | if (parts.Length != 2) return false; 26 | foreach (string part in parts) 27 | { 28 | if (!float.TryParse(part, out _)) 29 | return false; 30 | } 31 | 32 | return true; 33 | } 34 | 35 | public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 36 | { 37 | string str = value as string; 38 | 39 | if (str != null) 40 | { 41 | string[] parts = str.Replace(" ", "").Split(';', ','); 42 | if (parts.Length == 2) 43 | { 44 | float x = float.Parse(parts[0]); 45 | float y = float.Parse(parts[1]); 46 | return new Point2D(x, y); 47 | } 48 | } 49 | 50 | return base.ConvertFrom(context, culture, value); 51 | } 52 | 53 | public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 54 | { 55 | if (destinationType == typeof(string) && value is Point2D) 56 | { 57 | Point2D pt = (Point2D)value; 58 | return pt.X.ToString("F2") + "; " + pt.Y.ToString("F2"); 59 | } 60 | 61 | return base.ConvertTo(context, culture, value, destinationType); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /SimpleCAD/Geometry/Vector2DConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace SimpleCAD.Geometry 5 | { 6 | public class Vector2DConverter : ExpandableObjectConverter 7 | { 8 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 9 | { 10 | return sourceType == typeof(string); 11 | } 12 | 13 | public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 14 | { 15 | return destinationType == typeof(string); 16 | } 17 | 18 | public override bool IsValid(ITypeDescriptorContext context, object value) 19 | { 20 | string str = value as string; 21 | 22 | if (str == null) return false; 23 | 24 | string[] parts = str.Replace(" ", "").Split(';', ','); 25 | if (parts.Length != 2) return false; 26 | foreach (string part in parts) 27 | { 28 | if (!float.TryParse(part, out _)) 29 | return false; 30 | } 31 | 32 | return true; 33 | } 34 | 35 | public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 36 | { 37 | string str = value as string; 38 | 39 | if (str != null) 40 | { 41 | string[] parts = str.Replace(" ", "").Split(';', ','); 42 | if (parts.Length == 2) 43 | { 44 | float x = float.Parse(parts[0]); 45 | float y = float.Parse(parts[1]); 46 | return new Vector2D(x, y); 47 | } 48 | } 49 | 50 | return base.ConvertFrom(context, culture, value); 51 | } 52 | 53 | public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 54 | { 55 | if (destinationType == typeof(string) && value is Vector2D) 56 | { 57 | Vector2D vec = (Vector2D)value; 58 | return vec.X.ToString("F2") + "; " + vec.Y.ToString("F2"); 59 | } 60 | 61 | return base.ConvertTo(context, culture, value, destinationType); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /SimpleCAD/Graphics/Style.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace SimpleCAD.Graphics 4 | { 5 | public enum DashStyle 6 | { 7 | ByLayer = -1, 8 | Solid = 0, 9 | Dash = 1, 10 | Dot = 2, 11 | DashDot = 3, 12 | DashDotDot = 4, 13 | } 14 | 15 | [TypeConverter(typeof(ExpandableObjectConverter))] 16 | public class Style : IPersistable 17 | { 18 | public static Style Default => new Style(Color.ByLayer, ByLayer, DashStyle.ByLayer); 19 | 20 | public const float ByLayer = -1; 21 | 22 | public Color Color { get; set; } 23 | public float LineWeight { get; set; } 24 | public DashStyle DashStyle { get; set; } 25 | 26 | public Style(Color color, float lineWeight, DashStyle dashStyle) 27 | { 28 | Color = color; 29 | LineWeight = lineWeight; 30 | DashStyle = dashStyle; 31 | } 32 | 33 | public Style(Color color, float lineWeight) 34 | : this(color, lineWeight, DashStyle.Solid) 35 | { 36 | ; 37 | } 38 | 39 | public Style(Color color) 40 | : this(color, 0, DashStyle.Solid) 41 | { 42 | ; 43 | } 44 | 45 | public Style() 46 | : this(Color.ByLayer, ByLayer, DashStyle.ByLayer) 47 | { 48 | ; 49 | } 50 | 51 | public Style ApplyLayer(Layer layer) 52 | { 53 | Style style = new Style(Color, LineWeight, DashStyle); 54 | if (layer != null) 55 | { 56 | if (Color.IsByLayer) style.Color = layer.Style.Color; 57 | if (LineWeight == ByLayer) style.LineWeight = layer.Style.LineWeight; 58 | if (DashStyle == DashStyle.ByLayer) style.DashStyle = layer.Style.DashStyle; 59 | } 60 | return style; 61 | } 62 | 63 | public void Load(DocumentReader reader) 64 | { 65 | Color = reader.ReadColor(); 66 | LineWeight = reader.ReadFloat(); 67 | DashStyle = (DashStyle)reader.ReadInt(); 68 | } 69 | 70 | public void Save(DocumentWriter writer) 71 | { 72 | writer.Write(Color); 73 | writer.Write(LineWeight); 74 | writer.Write((int)DashStyle); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /SimpleCAD/View/Grid.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | using SimpleCAD.Graphics; 3 | 4 | namespace SimpleCAD.View 5 | { 6 | internal class Grid : Drawable 7 | { 8 | public override void Draw(Renderer renderer) 9 | { 10 | var view = renderer.View; 11 | var doc = view.Document; 12 | 13 | float spacing = 1; 14 | // Dynamic grid spacing 15 | while (view.WorldToScreen(new Vector2D(spacing, 0)).X > 12) 16 | spacing /= 10; 17 | 18 | while (view.WorldToScreen(new Vector2D(spacing, 0)).X < 4) 19 | spacing *= 10; 20 | 21 | Extents2D bounds = view.GetViewport(); 22 | Style majorStyle = new Style(doc.Settings.MajorGridColor); 23 | Style minorStyle = new Style(doc.Settings.MinorGridColor); 24 | 25 | int k = 0; 26 | for (float i = 0; i > bounds.Xmin; i -= spacing) 27 | { 28 | Style style = (k == 0 ? majorStyle : minorStyle); 29 | k = (k + 1) % 10; 30 | renderer.DrawLine(style, new Point2D(i, bounds.Ymax), new Point2D(i, bounds.Ymin)); 31 | } 32 | k = 0; 33 | for (float i = 0; i < bounds.Xmax; i += spacing) 34 | { 35 | Style style = (k == 0 ? majorStyle : minorStyle); 36 | k = (k + 1) % 10; 37 | renderer.DrawLine(style, new Point2D(i, bounds.Ymax), new Point2D(i, bounds.Ymin)); 38 | } 39 | k = 0; 40 | for (float i = 0; i < bounds.Ymax; i += spacing) 41 | { 42 | Style style = (k == 0 ? majorStyle : minorStyle); 43 | k = (k + 1) % 10; 44 | renderer.DrawLine(style, new Point2D(bounds.Xmin, i), new Point2D(bounds.Xmax, i)); 45 | } 46 | k = 0; 47 | for (float i = 0; i > bounds.Ymin; i -= spacing) 48 | { 49 | Style style = (k == 0 ? majorStyle : minorStyle); 50 | k = (k + 1) % 10; 51 | renderer.DrawLine(style, new Point2D(bounds.Xmin, i), new Point2D(bounds.Xmax, i)); 52 | } 53 | } 54 | 55 | public override Extents2D GetExtents() 56 | { 57 | return Extents2D.Infinity; 58 | } 59 | 60 | public override void TransformBy(Matrix2D transformation) 61 | { 62 | ; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /SimpleCAD/Commands/Command_Document.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace SimpleCAD.Commands 4 | { 5 | public class DocumentNew : Command 6 | { 7 | public override string RegisteredName => "Document.New"; 8 | public override string Name => "New"; 9 | 10 | public override Task Apply(CADDocument doc, params string[] args) 11 | { 12 | doc.New(); 13 | return Task.FromResult(default(object)); 14 | } 15 | } 16 | 17 | public class DocumentOpen : Command 18 | { 19 | public override string RegisteredName => "Document.Open"; 20 | public override string Name => "Open"; 21 | 22 | public override async Task Apply(CADDocument doc, params string[] args) 23 | { 24 | Editor ed = doc.Editor; 25 | ed.PickedSelection.Clear(); 26 | 27 | var res = await ed.GetOpenFilename("Open file"); 28 | if (res.Result == ResultMode.OK) 29 | { 30 | doc.Open(res.Value); 31 | } 32 | } 33 | } 34 | 35 | public class DocumentSave : Command 36 | { 37 | public override string RegisteredName => "Document.Save"; 38 | public override string Name => "Save"; 39 | 40 | public override async Task Apply(CADDocument doc, params string[] args) 41 | { 42 | Editor ed = doc.Editor; 43 | ed.PickedSelection.Clear(); 44 | 45 | string filename = doc.FileName; 46 | if (string.IsNullOrEmpty(filename)) 47 | { 48 | var res = await ed.GetSaveFilename("Save file"); 49 | if (res.Result == ResultMode.OK) 50 | filename = res.Value; 51 | else 52 | return; 53 | } 54 | doc.Save(filename); 55 | } 56 | } 57 | 58 | public class DocumentSaveAs : Command 59 | { 60 | public override string RegisteredName => "Document.SaveAs"; 61 | public override string Name => "Save As"; 62 | 63 | public override async Task Apply(CADDocument doc, params string[] args) 64 | { 65 | Editor ed = doc.Editor; 66 | ed.PickedSelection.Clear(); 67 | 68 | var res = await ed.GetSaveFilename("Save file"); 69 | if (res.Result == ResultMode.OK) 70 | { 71 | doc.Save(res.Value); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /SimpleCAD/Drawables/Drawable.cs: -------------------------------------------------------------------------------- 1 | using SimpleCAD.Geometry; 2 | using SimpleCAD.Graphics; 3 | using System; 4 | using System.ComponentModel; 5 | using System.Runtime.CompilerServices; 6 | 7 | namespace SimpleCAD 8 | { 9 | public abstract class Drawable : INotifyPropertyChanged, IPersistable 10 | { 11 | public Lazy layerRef = new Lazy(() => Layer.Default); 12 | 13 | public Style Style { get; set; } = Style.Default; 14 | public Layer Layer { get => layerRef.Value; set => layerRef = new Lazy(() => value); } 15 | public bool Visible { get; set; } = true; 16 | internal bool InModel { get; set; } = false; 17 | 18 | public event PropertyChangedEventHandler PropertyChanged; 19 | 20 | public abstract void Draw(Renderer renderer); 21 | public abstract Extents2D GetExtents(); 22 | public virtual bool Contains(Point2D pt, float pickBoxSize) { return GetExtents().Contains(pt); } 23 | public abstract void TransformBy(Matrix2D transformation); 24 | public virtual ControlPoint[] GetControlPoints() { return new ControlPoint[0]; } 25 | public virtual ControlPoint[] GetStretchPoints() { return GetControlPoints(); } 26 | public virtual SnapPoint[] GetSnapPoints() { return new SnapPoint[0]; } 27 | public virtual void TransformControlPoints(int[] indices, Matrix2D transformation) { } 28 | public virtual void TransformStretchPoints(int[] indices, Matrix2D transformation) { TransformControlPoints(indices, transformation); } 29 | 30 | public virtual Drawable Clone() { return (Drawable)MemberwiseClone(); } 31 | 32 | protected Drawable() { } 33 | 34 | protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") 35 | { 36 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 37 | } 38 | 39 | public virtual void Load(DocumentReader reader) 40 | { 41 | var doc = reader.Document; 42 | string layerName = reader.ReadString(); 43 | layerRef = new Lazy(() => doc.Layers[layerName]); 44 | Style = reader.ReadPersistable