├── .gitignore ├── LICENSE ├── MathHelper ├── MathHelper.csproj ├── Properties │ └── AssemblyInfo.cs └── Vector.cs ├── PuzzleGraph ├── Decorator.cs ├── Decorators │ ├── AbstractTetrisDecorator.cs │ ├── ArrowDecorator.cs │ ├── BoxDecorator.cs │ ├── BrokenDecorator.cs │ ├── CircleDecorator.cs │ ├── CombinedDecorator.cs │ ├── EliminatorDecorator.cs │ ├── EndDecorator.cs │ ├── HollowTetrisDecorator.cs │ ├── ParallelPuzzleDecorator.cs │ ├── PointDecorator.cs │ ├── RingDecorator.cs │ ├── SelfIntersectionDecorator.cs │ ├── SquareDecorator.cs │ ├── StarDecorator.cs │ ├── StartDecorator.cs │ ├── SymmetryPuzzleDecorator.cs │ ├── TetrisDecorator.cs │ ├── TextDecorator.cs │ ├── ThreeWayPuzzleDecorator.cs │ └── TriangleDecorator.cs ├── Edge.cs ├── Face.cs ├── Graph.cs ├── GraphElement.cs ├── IEdgeDecorable.cs ├── IFaceDecorable.cs ├── INodeDecorable.cs ├── IUnifiedScaleDecorator.cs ├── LocalizedDisplayNameAttribute.cs ├── MetaData.cs ├── Node.cs ├── ObsolateFormatFixer.cs ├── Properties │ └── AssemblyInfo.cs ├── PuzzleGraph.csproj ├── Resources │ ├── Lang.Designer.cs │ ├── Lang.resx │ └── Lang.zh-CN.resx ├── SaveState.cs ├── SerializableFont.cs ├── TetrisTemplate.cs ├── TransformableDecorator.cs ├── XmlColor.cs └── XmlFont.cs ├── README.md ├── Screenshots ├── 1.png └── 2.jpg ├── TemplateGenerator ├── App.config ├── HexagonTemplateGenerator.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── PyramidHexagonTemplateGenerator.cs ├── RightTriangleTemplateGenerator.cs ├── SquareTemplateGenerator.cs └── TemplateGenerator.csproj ├── WitnessVisualizer.sln └── WitnessVisualizer ├── App.config ├── EditManager.cs ├── EditView.cs ├── FormHelper.cs ├── GraphManipulation.cs ├── Icons ├── ColorPicker.png ├── Cursor.png └── Paint.png ├── InputDialog.cs ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── MainForm.zh-CN.resx ├── PaintingModeControl.cs ├── Program.cs ├── Prompt.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── PuzzleGraphRenderer.cs ├── PuzzleSettings.cs ├── PuzzleToolkit.cs ├── PuzzleToolkitDecoratorItem.cs ├── PuzzleToolkitItem.cs ├── PuzzleToolkitMiscItem.cs ├── Puzzles └── README.txt ├── Resources ├── Lang.Designer.cs ├── Lang.resx └── Lang.zh-CN.resx ├── Templates └── README.txt ├── TetrisTemplateRenderer.cs ├── TetrisTransferHelper.cs ├── Toolkit └── README.txt ├── WitnessVisualizer.csproj ├── designer.ico ├── designer2.ico └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | 254 | # Others 255 | 256 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Junyan Jiang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MathHelper/MathHelper.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730} 8 | Library 9 | Properties 10 | MathHelper 11 | MathHelper 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /MathHelper/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("MathHelper")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MathHelper")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("4ed83a7c-9e43-4e5e-95ef-f724f5664730")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /MathHelper/Vector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace MathHelper 5 | { 6 | public class Vector 7 | { 8 | public double X { get; private set; } 9 | public double Y { get; private set; } 10 | public Vector(double inputX,double inputY) 11 | { 12 | X = inputX; 13 | Y = inputY; 14 | } 15 | public static Vector Zero = new Vector(0.0, 0.0); 16 | public static Vector UnitX = new Vector(1.0, 0.0); 17 | public static Vector UnitY = new Vector(0.0, 1.0); 18 | public PointF ToPoint() 19 | { 20 | return new PointF((float)X, (float)Y); 21 | } 22 | public RectangleF ToCircleBoundingBox(double radius) 23 | { 24 | float diameter = (float)(radius*2); 25 | return new RectangleF((float)(X - radius), (float)(Y - radius), diameter, diameter); 26 | } 27 | public static RectangleF ToRectangleF(Vector a, Vector b) 28 | { 29 | double x1 = Math.Min(a.X, b.X); 30 | double y1 = Math.Min(a.Y, b.Y); 31 | double width = Math.Max(a.X, b.X) - x1; 32 | double height = Math.Max(a.Y, b.Y) - y1; 33 | return new RectangleF((float)x1, (float)y1, (float)width, (float)height); 34 | } 35 | 36 | #region operations 37 | public static Vector operator +(Vector a) => a; 38 | public static Vector operator -(Vector a) => new Vector(-a.X,-a.Y); 39 | public static Vector operator +(Vector a, Vector b) => new Vector(a.X + b.X, a.Y + b.Y); 40 | public static Vector operator -(Vector a, Vector b) => new Vector(a.X - b.X, a.Y - b.Y); 41 | public static Vector operator *(Vector a, double b) => new Vector(a.X * b, a.Y * b); 42 | public static Vector operator *(double b, Vector a) => new Vector(a.X * b, a.Y * b); 43 | public static Vector operator /(Vector a, double b) => new Vector(a.X / b, a.Y / b); 44 | public static Vector operator /(double b, Vector a) => new Vector(a.X / b, a.Y / b); 45 | public static double operator ^(Vector a, Vector b) => a.X * b.X + a.Y * b.Y; 46 | public static double operator *(Vector a, Vector b) => a.X * b.Y - b.X * a.Y; 47 | #endregion 48 | 49 | #region helper functions 50 | public Vector MapToScreen(double scale,Vector origin) => this * scale + origin; 51 | public Vector MapFromScreen(double scale, Vector origin) => (this - origin) / scale; 52 | public double Length() => Math.Sqrt(X * X + Y * Y); 53 | public static double PointDistance(Vector query, Vector point) => (query - point).Length(); 54 | public static double SegmentDistance(Vector query, Vector start, Vector end) 55 | { 56 | // from https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment by Joshua 57 | double x = query.X, y = query.Y; 58 | double x1 = start.X, y1 = start.Y; 59 | double x2 = end.X, y2 = end.Y; 60 | double A = x - x1; 61 | double B = y - y1; 62 | double C = x2 - x1; 63 | double D = y2 - y1; 64 | 65 | double dot = A * C + B * D; 66 | double len_sq = C * C + D * D; 67 | double param = -1; 68 | if (len_sq != 0) //in case of 0 length line 69 | param = dot / len_sq; 70 | 71 | double xx, yy; 72 | 73 | if (param < 0) 74 | { 75 | xx = x1; 76 | yy = y1; 77 | } 78 | else if (param > 1) 79 | { 80 | xx = x2; 81 | yy = y2; 82 | } 83 | else 84 | { 85 | xx = x1 + param * C; 86 | yy = y1 + param * D; 87 | } 88 | 89 | double dx = x - xx; 90 | double dy = y - yy; 91 | return Math.Sqrt(dx * dx + dy * dy); 92 | } 93 | 94 | public static double GetAngle(Vector a, Vector b) 95 | { 96 | double lengthProduct = a.Length() * b.Length(); 97 | if (lengthProduct < 1e-10) 98 | return 0.0f; 99 | double cosValue = (a ^ b) / lengthProduct; 100 | return Math.Acos(cosValue); 101 | } 102 | 103 | public Vector Rotate(double angle) 104 | { 105 | double cosValue = Math.Cos(angle), sinValue = Math.Sin(angle); 106 | return new Vector(cosValue * X - sinValue * Y, sinValue * X + cosValue * Y); 107 | } 108 | #endregion 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using System.Xml.Serialization; 6 | using PuzzleGraph.Decorators; 7 | 8 | namespace PuzzleGraph 9 | { 10 | [ 11 | XmlInclude(typeof(BrokenDecorator)), 12 | XmlInclude(typeof(EliminatorDecorator)), 13 | XmlInclude(typeof(EndDecorator)), 14 | XmlInclude(typeof(HollowTetrisDecorator)), 15 | XmlInclude(typeof(PointDecorator)), 16 | XmlInclude(typeof(SquareDecorator)), 17 | XmlInclude(typeof(StarDecorator)), 18 | XmlInclude(typeof(StartDecorator)), 19 | XmlInclude(typeof(TetrisDecorator)), 20 | XmlInclude(typeof(TriangleDecorator)), 21 | XmlInclude(typeof(CircleDecorator)), 22 | XmlInclude(typeof(RingDecorator)), 23 | XmlInclude(typeof(TextDecorator)), 24 | XmlInclude(typeof(CombinedDecorator)), 25 | XmlInclude(typeof(SymmetryPuzzleDecorator)), 26 | XmlInclude(typeof(ThreeWayPuzzleDecorator)), 27 | XmlInclude(typeof(ParallelPuzzleDecorator)), 28 | XmlInclude(typeof(ArrowDecorator)), 29 | XmlInclude(typeof(SelfIntersectionDecorator)), 30 | XmlInclude(typeof(BoxDecorator)), 31 | ] 32 | public abstract class Decorator : ICloneable 33 | { 34 | public virtual bool IsFaceDecorable() => this is IFaceDecorable; 35 | public virtual bool IsEdgeDecorable() => this is IEdgeDecorable; 36 | public virtual bool IsNodeDecorable() => this is INodeDecorable; 37 | 38 | public bool IsDecorableFor(GraphElement element) 39 | { 40 | return (element is Node && IsNodeDecorable()) || 41 | (element is Edge && IsEdgeDecorable()) || 42 | (element is Face && IsFaceDecorable()); 43 | } 44 | public object Clone() 45 | { 46 | using (MemoryStream ms = new MemoryStream()) 47 | { 48 | XmlSerializer xml = new XmlSerializer(typeof(Decorator)); 49 | xml.Serialize(ms, this); 50 | ms.Position = 0; 51 | return xml.Deserialize(ms); 52 | } 53 | } 54 | public override string ToString() 55 | { 56 | return Resources.Lang.ResourceManager.GetString(this.GetType().Name) ?? this.GetType().Name; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/AbstractTetrisDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PuzzleGraph.Decorators 8 | { 9 | public class AbstractTetrisDecorator : TransformableDecorator 10 | { 11 | [LocalizedDisplayName("Shapes")] 12 | public List> Shapes { get; set; } = new List>(); 13 | [LocalizedDisplayName("Indexes")] 14 | public List Indexes { get; set; } = new List(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/ArrowDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class ArrowDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | [LocalizedDisplayName("Count")] 14 | public int Count { get; set; } = 1; 15 | [LocalizedDisplayName("Color")] 16 | [XmlElement(Type = typeof(XmlColor))] 17 | public Color Color { get; set; } = Color.Purple; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/BoxDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class BoxDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/BrokenDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PuzzleGraph.Decorators 8 | { 9 | public class BrokenDecorator : Decorator, IEdgeDecorable 10 | { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/CircleDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class CircleDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | [LocalizedDisplayName("Color")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color Color { get; set; } = Color.Brown; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/CombinedDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PuzzleGraph.Decorators 9 | { 10 | public class CombinedDecorator : Decorator 11 | { 12 | public override bool IsFaceDecorable() 13 | { 14 | if(First is null || Second is null) return false; 15 | return First.IsFaceDecorable() && Second.IsFaceDecorable(); 16 | } 17 | public override bool IsEdgeDecorable() 18 | { 19 | if (First is null || Second is null) return false; 20 | return First.IsEdgeDecorable() && Second.IsEdgeDecorable(); 21 | } 22 | public override bool IsNodeDecorable() 23 | { 24 | if (First is null || Second is null) return false; 25 | return First.IsNodeDecorable() && Second.IsNodeDecorable(); 26 | } 27 | [LocalizedDisplayName("First")] 28 | [TypeConverter(typeof(ExpandableObjectConverter))] 29 | public Decorator First { get; set; } 30 | [LocalizedDisplayName("Second")] 31 | [TypeConverter(typeof(ExpandableObjectConverter))] 32 | public Decorator Second { get; set; } 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/EliminatorDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class EliminatorDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | [LocalizedDisplayName("Color")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color Color { get; set; } = Color.White; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/EndDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class EndDecorator : Decorator, INodeDecorable, IEdgeDecorable 12 | { 13 | [LocalizedDisplayName("Length")] 14 | public double Length { get; set; } = 0.2; 15 | [LocalizedDisplayName("Angle")] 16 | public double Angle { get; set; } = 135; 17 | [LocalizedDisplayName("Color")] 18 | [XmlElement(Type = typeof(XmlColor))] 19 | public Color Color { get; set; } = Color.Transparent; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/HollowTetrisDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class HollowTetrisDecorator : AbstractTetrisDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | [LocalizedDisplayName("Color")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color Color { get; set; } = Color.Blue; 16 | [LocalizedDisplayName("BorderSize")] 17 | public double BorderSize { get; set; } = 0.19; 18 | [LocalizedDisplayName("MarginSize")] 19 | public double MarginSize { get; set; } = 0.14; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/ParallelPuzzleDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class ParallelPuzzleDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable, IUnifiedScaleDecorator 12 | { 13 | [LocalizedDisplayName("SecondLineColor")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color SecondLineColor { get; set; } = Color.Aqua; 16 | 17 | [LocalizedDisplayName("TranslationX")] 18 | public double TranslationX { get; set; } = 0.0; 19 | [LocalizedDisplayName("TranslationY")] 20 | public double TranslationY { get; set; } = 0.0; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/PointDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class PointDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | [LocalizedDisplayName("Color")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color Color { get; set; } = Color.Black; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/RingDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class RingDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | [LocalizedDisplayName("Color")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color Color { get; set; } = Color.Brown; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/SelfIntersectionDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class SelfIntersectionDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | [LocalizedDisplayName("Color1")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color Color1 { get; set; } = Color.Black; 16 | [LocalizedDisplayName("Color2")] 17 | [XmlElement(Type = typeof(XmlColor))] 18 | public Color Color2 { get; set; } = Color.Black; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/SquareDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class SquareDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | [LocalizedDisplayName("Color")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color Color { get; set; } = Color.Black; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/StarDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class StarDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | [LocalizedDisplayName("Color")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color Color { get; set; } = Color.Black; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/StartDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class StartDecorator : Decorator, INodeDecorable, IEdgeDecorable 12 | { 13 | [LocalizedDisplayName("Color")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color Color { get; set; } = Color.Transparent; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/SymmetryPuzzleDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class SymmetryPuzzleDecorator: TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable, IUnifiedScaleDecorator 12 | { 13 | [LocalizedDisplayName("SecondLineColor")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color SecondLineColor { get; set; } = Color.Aqua; 16 | 17 | [LocalizedDisplayName("IsRotational")] 18 | public bool IsRotational { get; set; } = false; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/TetrisDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class TetrisDecorator : AbstractTetrisDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | [LocalizedDisplayName("Color")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color Color { get; set; } = Color.Yellow; 16 | [LocalizedDisplayName("MarginSize")] 17 | public double MarginSize { get; set; } = 0.14; 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/TextDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.ComponentModel.Design; 5 | using System.Drawing; 6 | using System.Drawing.Design; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Xml.Serialization; 11 | 12 | namespace PuzzleGraph.Decorators 13 | { 14 | public class TextDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 15 | { 16 | // [XmlElement(Type = typeof(XmlFont))] 17 | [LocalizedDisplayName("Font")] 18 | [XmlIgnore()] 19 | public Font Font { get { return SerializableFont?.ToFont(); } 20 | set { SerializableFont = new SerializableFont(value); } 21 | } 22 | [Browsable(false)] 23 | public SerializableFont SerializableFont { get; set; } 24 | [Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))] 25 | [LocalizedDisplayName("Text")] 26 | public string Text { get; set; } 27 | [LocalizedDisplayName("Color")] 28 | [XmlElement(Type = typeof(XmlColor))] 29 | public Color Color { get; set; } = Color.Black; 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/ThreeWayPuzzleDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class ThreeWayPuzzleDecorator: TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable, IUnifiedScaleDecorator 12 | { 13 | [LocalizedDisplayName("SecondLineColor")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color SecondLineColor { get; set; } = Color.Aqua; 16 | [LocalizedDisplayName("ThirdLineColor")] 17 | [XmlElement(Type = typeof(XmlColor))] 18 | public Color ThirdLineColor { get; set; } = Color.LightGreen; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /PuzzleGraph/Decorators/TriangleDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph.Decorators 10 | { 11 | public class TriangleDecorator : TransformableDecorator, IFaceDecorable, IEdgeDecorable, INodeDecorable 12 | { 13 | [LocalizedDisplayName("Count")] 14 | public int Count { get; set; } = 1; 15 | [LocalizedDisplayName("Color")] 16 | [XmlElement(Type = typeof(XmlColor))] 17 | public Color Color { get; set; } = Color.Gold; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /PuzzleGraph/Edge.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Text; 5 | using System.Xml.Serialization; 6 | 7 | namespace PuzzleGraph 8 | { 9 | public class Edge : GraphElement 10 | { 11 | [LocalizedDisplayName("Start")] 12 | public Node Start { get; set; } 13 | [LocalizedDisplayName("End")] 14 | public Node End { get; set; } 15 | [LocalizedDisplayName("GraphElementColor")] 16 | [XmlElement(Type = typeof(XmlColor))] 17 | public Color GraphElementColor { get; set; } = Color.Transparent; 18 | 19 | public Edge(Node inputStart,Node inputEnd) 20 | { 21 | Start = inputStart; 22 | End = inputEnd; 23 | Decorator = null; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /PuzzleGraph/Face.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Text; 5 | using System.Xml.Serialization; 6 | 7 | namespace PuzzleGraph 8 | { 9 | public class Face : GraphElement 10 | { 11 | [LocalizedDisplayName("Nodes")] 12 | public List Nodes { get; set; } 13 | [LocalizedDisplayName("GraphElementColor")] 14 | [XmlElement(Type = typeof(XmlColor))] 15 | public Color GraphElementColor { get; set; } = Color.Transparent; 16 | 17 | public Face(List inputNodes) 18 | { 19 | Nodes = inputNodes; 20 | Decorator = null; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /PuzzleGraph/Graph.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System; 3 | using System.IO; 4 | using System.Text; 5 | using System.Xml.Serialization; 6 | using System.Linq; 7 | using System.ComponentModel; 8 | 9 | namespace PuzzleGraph 10 | { 11 | public class Graph : ICloneable 12 | { 13 | [LocalizedDisplayName("Nodes")] 14 | public List Nodes { get; private set; } 15 | [LocalizedDisplayName("Edges")] 16 | public List Edges { get; private set; } 17 | [LocalizedDisplayName("Faces")] 18 | public List Faces { get; private set; } 19 | [LocalizedDisplayName("MetaData")] 20 | [TypeConverter(typeof(ExpandableObjectConverter))] 21 | public MetaData MetaData { get; private set; } 22 | public Graph() 23 | { 24 | Nodes = new List(); 25 | Edges = new List(); 26 | Faces = new List(); 27 | MetaData = new MetaData(); 28 | } 29 | private Graph(SaveState state) 30 | { 31 | Nodes = state.Nodes; 32 | Edges = state.EdgesID.Select(edgeID => new Edge(Nodes[edgeID.Start], Nodes[edgeID.End]) { Decorator = edgeID.Decorator, GraphElementColor=edgeID.GraphElementColor }).ToList(); 33 | Faces = state.FacesID.Select(faceID => new Face(faceID.Nodes.Select(id => Nodes[id]).ToList()) { Decorator = faceID.Decorator, GraphElementColor = faceID.GraphElementColor }).ToList(); 34 | MetaData = state.MetaData; 35 | } 36 | public override string ToString() 37 | { 38 | XmlSerializer xml = new XmlSerializer(typeof(SaveState)); 39 | using(MemoryStream ms=new MemoryStream()) 40 | { 41 | xml.Serialize(ms, new SaveState(this)); 42 | return Encoding.UTF8.GetString(ms.ToArray()); 43 | } 44 | } 45 | public Graph(string saveState):this(new XmlSerializer(typeof(SaveState)) 46 | .Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(saveState))) as SaveState) 47 | { 48 | 49 | } 50 | public static Graph LoadFromFile(string fileName) 51 | { 52 | XmlSerializer xml = new XmlSerializer(typeof(SaveState)); 53 | using (FileStream fs=new FileStream(fileName,FileMode.Open)) 54 | { 55 | return new Graph(xml.Deserialize(fs) as SaveState); 56 | } 57 | } 58 | public void SaveToFile(string fileName) 59 | { 60 | XmlSerializer xml = new XmlSerializer(typeof(SaveState)); 61 | using (FileStream fs = new FileStream(fileName, FileMode.Create)) 62 | { 63 | xml.Serialize(fs, new SaveState(this)); 64 | } 65 | } 66 | 67 | public void RemoveElement(GraphElement element) 68 | { 69 | if(element is Node node) 70 | { 71 | List elementsToDelete = new List(); 72 | foreach(Edge edge in Edges) 73 | { 74 | if(edge.Start== node || edge.End==node) 75 | { 76 | elementsToDelete.Add(edge); 77 | } 78 | } 79 | foreach (Face face in Faces) 80 | { 81 | if (face.Nodes.Contains(node)) 82 | { 83 | elementsToDelete.Add(face); 84 | } 85 | } 86 | foreach (GraphElement newElement in elementsToDelete) 87 | RemoveElement(newElement); 88 | Nodes.Remove(node); 89 | } 90 | else if(element is Edge edge) 91 | { 92 | List elementsToDelete = new List(); 93 | foreach (Face face in Faces) 94 | { 95 | for (int i = 0; i < face.Nodes.Count; ++i) 96 | { 97 | Node firstNode = face.Nodes[i]; 98 | Node secondNode = face.Nodes[i + 1 < face.Nodes.Count ? i + 1 : 0]; 99 | if ((firstNode == edge.End && secondNode == edge.Start) || 100 | (firstNode == edge.Start && secondNode == edge.End)) 101 | { 102 | elementsToDelete.Add(face); 103 | break; 104 | } 105 | } 106 | } 107 | foreach (GraphElement newElement in elementsToDelete) 108 | RemoveElement(newElement); 109 | Edges.Remove(edge); 110 | } 111 | else if(element is Face face) 112 | { 113 | Faces.Remove(face); 114 | } 115 | } 116 | 117 | public enum FlipType 118 | { 119 | XY=0, 120 | Horizontal=1, 121 | Vertical=2, 122 | Rotate=3 123 | } 124 | private static Node TransformNode(Node node,FlipType flipType,double angle=0) 125 | { 126 | if (flipType == FlipType.XY) 127 | return new Node(node.Y, node.X); 128 | else if (flipType == FlipType.Horizontal) 129 | return new Node(-node.X, node.Y); 130 | else if (flipType == FlipType.Vertical) 131 | return new Node(node.X, -node.Y); 132 | else if (flipType == FlipType.Rotate) 133 | { 134 | double cosValue = Math.Cos(angle), sinValue = Math.Sin(angle); 135 | return new Node(cosValue * node.X - sinValue * node.Y, sinValue * node.X + cosValue * node.Y); 136 | } 137 | else throw new NotSupportedException(); 138 | } 139 | public static Graph FlipGraph(Graph graph, FlipType flipType) 140 | { 141 | Graph graphClone = new Graph(graph.ToString()); 142 | Graph newGraph = new Graph(); 143 | Dictionary mapping = new Dictionary(); 144 | foreach (Node node in graphClone.Nodes) 145 | { 146 | mapping[node] = TransformNode(node, flipType); 147 | mapping[node].Decorator = node.Decorator; 148 | } 149 | foreach (Node node in graphClone.Nodes) 150 | { 151 | newGraph.Nodes.Add(mapping[node]); 152 | } 153 | foreach (Edge edge in graphClone.Edges) 154 | { 155 | Edge newEdge = new Edge(mapping[edge.Start], mapping[edge.End]); 156 | newEdge.Decorator = edge.Decorator; 157 | newEdge.GraphElementColor = edge.GraphElementColor; 158 | newGraph.Edges.Add(newEdge); 159 | } 160 | foreach (Face face in graphClone.Faces) 161 | { 162 | List nodes = new List(); 163 | nodes.AddRange(face.Nodes); 164 | nodes.Reverse(); 165 | Face newFace = new Face(nodes.Select(node => mapping[node]).ToList()); 166 | newFace.Decorator = face.Decorator; 167 | newFace.GraphElementColor = face.GraphElementColor; 168 | newGraph.Faces.Add(newFace); 169 | } 170 | TetrisTemplate oldTetrisTemplate = graphClone.MetaData.TetrisTemplate; 171 | newGraph.MetaData = graphClone.MetaData; 172 | newGraph.MetaData.TetrisTemplate = new TetrisTemplate(); 173 | foreach (List shape in oldTetrisTemplate.Shapes) 174 | { 175 | List newShape = new List(); 176 | newShape.AddRange(shape); 177 | newShape.Reverse(); 178 | newGraph.MetaData.TetrisTemplate.Shapes.Add(newShape.Select(node => TransformNode(node, flipType)).ToList()); 179 | } 180 | return newGraph; 181 | } 182 | public static Graph RotateGraph(Graph graph, double angle) 183 | { 184 | Graph graphClone = new Graph(graph.ToString()); 185 | Graph newGraph = new Graph(); 186 | Dictionary mapping = new Dictionary(); 187 | foreach (Node node in graphClone.Nodes) 188 | { 189 | mapping[node] = TransformNode(node, FlipType.Rotate, angle); 190 | mapping[node].Decorator = node.Decorator; 191 | } 192 | foreach (Node node in graphClone.Nodes) 193 | { 194 | newGraph.Nodes.Add(mapping[node]); 195 | } 196 | foreach (Edge edge in graphClone.Edges) 197 | { 198 | Edge newEdge = new Edge(mapping[edge.Start], mapping[edge.End]); 199 | newEdge.Decorator = edge.Decorator; 200 | newGraph.Edges.Add(newEdge); 201 | } 202 | foreach (Face face in graphClone.Faces) 203 | { 204 | List nodes = new List(); 205 | nodes.AddRange(face.Nodes); 206 | Face newFace = new Face(nodes.Select(node => mapping[node]).ToList()); 207 | newFace.Decorator = face.Decorator; 208 | newGraph.Faces.Add(newFace); 209 | } 210 | TetrisTemplate oldTetrisTemplate = graphClone.MetaData.TetrisTemplate; 211 | newGraph.MetaData = graphClone.MetaData; 212 | newGraph.MetaData.TetrisTemplate = new TetrisTemplate(); 213 | foreach (List shape in oldTetrisTemplate.Shapes) 214 | { 215 | List newShape = new List(); 216 | newShape.AddRange(shape); 217 | newGraph.MetaData.TetrisTemplate.Shapes.Add(newShape.Select(node => TransformNode(node, FlipType.Rotate, angle)).ToList()); 218 | } 219 | return newGraph; 220 | 221 | } 222 | public static Graph ScaleGraph(Graph graph, double scaleX, double scaleY) 223 | { 224 | Graph graphClone = new Graph(graph.ToString()); 225 | Graph newGraph = new Graph(); 226 | Dictionary mapping = new Dictionary(); 227 | foreach (Node node in graphClone.Nodes) 228 | { 229 | mapping[node] = new Node(node.X * scaleX, node.Y * scaleY); 230 | mapping[node].Decorator = node.Decorator; 231 | } 232 | foreach (Node node in graphClone.Nodes) 233 | { 234 | newGraph.Nodes.Add(mapping[node]); 235 | } 236 | foreach (Edge edge in graphClone.Edges) 237 | { 238 | Edge newEdge = new Edge(mapping[edge.Start], mapping[edge.End]); 239 | newEdge.Decorator = edge.Decorator; 240 | newGraph.Edges.Add(newEdge); 241 | } 242 | foreach (Face face in graphClone.Faces) 243 | { 244 | List nodes = new List(); 245 | nodes.AddRange(face.Nodes); 246 | Face newFace = new Face(nodes.Select(node => mapping[node]).ToList()); 247 | newFace.Decorator = face.Decorator; 248 | newGraph.Faces.Add(newFace); 249 | } 250 | TetrisTemplate oldTetrisTemplate = graphClone.MetaData.TetrisTemplate; 251 | newGraph.MetaData = graphClone.MetaData; 252 | newGraph.MetaData.TetrisTemplate = new TetrisTemplate(); 253 | foreach (List shape in oldTetrisTemplate.Shapes) 254 | { 255 | List newShape = new List(); 256 | newShape.AddRange(shape); 257 | newGraph.MetaData.TetrisTemplate.Shapes.Add(newShape.Select(node => new Node(node.X * scaleX, node.Y * scaleY)).ToList()); 258 | } 259 | return newGraph; 260 | 261 | } 262 | 263 | public object Clone() 264 | { 265 | return new Graph(ToString()); 266 | } 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /PuzzleGraph/GraphElement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Xml.Serialization; 9 | 10 | namespace PuzzleGraph 11 | { 12 | public abstract class GraphElement 13 | { 14 | [LocalizedDisplayName("Decorator")] 15 | [TypeConverter(typeof(ExpandableObjectConverter))] 16 | public Decorator Decorator { get; set; } 17 | public override string ToString() 18 | { 19 | return Resources.Lang.ResourceManager.GetString(this.GetType().Name) ?? this.GetType().Name; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /PuzzleGraph/IEdgeDecorable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PuzzleGraph 8 | { 9 | internal interface IEdgeDecorable 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /PuzzleGraph/IFaceDecorable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PuzzleGraph 8 | { 9 | internal interface IFaceDecorable 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /PuzzleGraph/INodeDecorable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PuzzleGraph 8 | { 9 | internal interface INodeDecorable 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /PuzzleGraph/IUnifiedScaleDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PuzzleGraph 8 | { 9 | public interface IUnifiedScaleDecorator 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /PuzzleGraph/LocalizedDisplayNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PuzzleGraph 9 | { 10 | class LocalizedDisplayNameAttribute : DisplayNameAttribute 11 | { 12 | private readonly string resourceName; 13 | public LocalizedDisplayNameAttribute(string resourceName) : base() 14 | { 15 | this.resourceName = resourceName; 16 | } 17 | 18 | public override string DisplayName 19 | { 20 | get 21 | { 22 | return Resources.Lang.ResourceManager.GetString(this.resourceName) ?? ""; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /PuzzleGraph/MetaData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Text; 5 | using System.Xml.Serialization; 6 | 7 | namespace PuzzleGraph 8 | { 9 | [LocalizedDisplayName("MetaData")] 10 | public class MetaData 11 | { 12 | [LocalizedDisplayName("PuzzleTitle")] 13 | public string PuzzleTitle { get; set; } = ""; 14 | [LocalizedDisplayName("BackgroundColor")] 15 | [XmlElement(Type = typeof(XmlColor))] 16 | public Color BackgroundColor { get; set; } = Color.LightGray; 17 | [LocalizedDisplayName("ForegroundColor")] 18 | [XmlElement(Type = typeof(XmlColor))] 19 | public Color ForegroundColor { get; set; } = Color.DarkGray; 20 | [LocalizedDisplayName("EdgeWidth")] 21 | public double EdgeWidth { get; set; } = 0.2; 22 | [LocalizedDisplayName("TetrisTemplate")] 23 | public TetrisTemplate TetrisTemplate { get; set; } = new TetrisTemplate(); 24 | [LocalizedDisplayName("TetrisScale")] 25 | public double TetrisScale { get; set; } = 0.2; 26 | [LocalizedDisplayName("FaceDecorationScale")] 27 | public double FaceDecorationScale { get; set; } = 1.0; 28 | [LocalizedDisplayName("ExportWidth")] 29 | public int ExportWidth { get; set; } = 768; 30 | [LocalizedDisplayName("ExportHeight")] 31 | public int ExportHeight { get; set; } = 768; 32 | [LocalizedDisplayName("LineColor")] 33 | [XmlElement(Type = typeof(XmlColor))] 34 | public Color LineColor { get; set; } = Color.Yellow; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /PuzzleGraph/Node.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace PuzzleGraph 4 | { 5 | public class Node: GraphElement 6 | { 7 | [LocalizedDisplayName("X")] 8 | public double X { get; set; } 9 | [LocalizedDisplayName("Y")] 10 | public double Y { get; set; } 11 | [LocalizedDisplayName("Hidden")] 12 | public bool Hidden { get; set; } 13 | 14 | private Node() { } 15 | public Node(double inputX,double inputY) 16 | { 17 | X = inputX; 18 | Y = inputY; 19 | Decorator = null; 20 | Hidden = false; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /PuzzleGraph/ObsolateFormatFixer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PuzzleGraph 8 | { 9 | public class ObsolateFormatFixer 10 | { 11 | private static List> IndexToShape(Graph graph, List indexes) 12 | { 13 | List> result = new List>(); 14 | TetrisTemplate template = graph.MetaData.TetrisTemplate; 15 | foreach (int index in indexes) 16 | { 17 | if (index < template.Shapes.Count) 18 | { 19 | result.Add(template.Shapes[index].Select(node => new Node(node.X, node.Y)).ToList()); 20 | } 21 | } 22 | return result; 23 | } 24 | 25 | public static bool FixObsoletedTetrisFormat(Graph graph) 26 | { 27 | bool upgraded = false; 28 | foreach (Face face in graph.Faces) 29 | { 30 | if (face.Decorator is Decorators.AbstractTetrisDecorator tetris) 31 | { 32 | if(tetris.Shapes.Count == 0 && tetris.Indexes.Count > 0) 33 | { 34 | upgraded = true; 35 | tetris.Shapes = IndexToShape(graph, tetris.Indexes); 36 | if (tetris.Shapes.Count == 0) 37 | tetris.Indexes.Clear(); 38 | } 39 | } 40 | } 41 | return upgraded; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /PuzzleGraph/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("PuzzleGraph")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PuzzleGraph")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("e6e86344-2472-4da8-8012-70eadba9841c")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PuzzleGraph/PuzzleGraph.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E6E86344-2472-4DA8-8012-70EADBA9841C} 8 | Library 9 | Properties 10 | PuzzleGraph 11 | PuzzleGraph 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | True 83 | True 84 | Lang.resx 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | ResXFileCodeGenerator 96 | Lang.Designer.cs 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /PuzzleGraph/Resources/Lang.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace PuzzleGraph.Resources { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Lang { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Lang() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PuzzleGraph.Resources.Lang", typeof(Lang).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 重写当前线程的 CurrentUICulture 属性 51 | /// 重写当前线程的 CurrentUICulture 属性。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /PuzzleGraph/Resources/Lang.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /PuzzleGraph/Resources/Lang.zh-CN.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 角度 122 | 123 | 124 | 背景色 125 | 126 | 127 | 边框大小 128 | 129 | 130 | 断线装饰 131 | 132 | 133 | 圆圈装饰 134 | 135 | 136 | 颜色 137 | 138 | 139 | 合并装饰 140 | 141 | 142 | 数量 143 | 144 | 145 | 装饰元素 146 | 147 | 148 | ΔX 149 | 150 | 151 | ΔY 152 | 153 | 154 | 线段 155 | 156 | 157 | 路径宽度 158 | 159 | 160 | 抗体装饰 161 | 162 | 163 | 终点 164 | 165 | 166 | 终点装饰 167 | 168 | 169 | 导出高度 170 | 171 | 172 | 导出宽度 173 | 174 | 175 | 额外缩放 176 | 177 | 178 | 179 | 180 | 181 | 面装饰元素缩放 182 | 183 | 184 | 185 | 186 | 187 | 字体 188 | 189 | 190 | 字体名 191 | 192 | 193 | 前景色 194 | 195 | 196 | 网格颜色 197 | 198 | 199 | 图像单位 200 | 201 | 202 | 空心俄罗斯方块装饰 203 | 204 | 205 | 编号 206 | 207 | 208 | 长度 209 | 210 | 211 | 边距大小 212 | 213 | 214 | 元数据 215 | 216 | 217 | 结点 218 | 219 | 220 | 结点 221 | 222 | 223 | 点装饰 224 | 225 | 226 | 谜题标题 227 | 228 | 229 | 圆环装饰 230 | 231 | 232 | 233 | 234 | 235 | 形状 236 | 237 | 238 | 大小 239 | 240 | 241 | 色块装饰 242 | 243 | 244 | 星形装饰 245 | 246 | 247 | 起点 248 | 249 | 250 | 起点装饰 251 | 252 | 253 | 样式 254 | 255 | 256 | 俄罗斯方块装饰 257 | 258 | 259 | 俄罗斯方块缩放 260 | 261 | 262 | 俄罗斯方块模板 263 | 264 | 265 | 文本 266 | 267 | 268 | 文本装饰 269 | 270 | 271 | 三角装饰 272 | 273 | 274 | X坐标 275 | 276 | 277 | Y坐标 278 | 279 | -------------------------------------------------------------------------------- /PuzzleGraph/SaveState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace PuzzleGraph 10 | { 11 | public class SaveState 12 | { 13 | public class SaveEdge 14 | { 15 | public int Start { get; set; } 16 | public int End { get; set; } 17 | public Decorator Decorator { get; set; } 18 | [XmlElement(Type = typeof(XmlColor))] 19 | public Color GraphElementColor { get; set; } = Color.Transparent; 20 | } 21 | public class SaveFace 22 | { 23 | public List Nodes { get; set; } 24 | public Decorator Decorator { get; set; } 25 | [XmlElement(Type = typeof(XmlColor))] 26 | public Color GraphElementColor { get; set; } = Color.Transparent; 27 | } 28 | 29 | public List Nodes { get; set; } 30 | public List EdgesID { get; set; } 31 | public List FacesID { get; set; } 32 | public MetaData MetaData { get; set; } 33 | 34 | private SaveState() { } 35 | public SaveState(Graph graph) 36 | { 37 | Dictionary nodeIDs = new Dictionary(); 38 | Nodes = graph.Nodes; 39 | for(int i=0;i(graph.Edges.Count); 44 | for(int i=0;i(graph.Faces.Count); 51 | for(int i=0;i nodeIDs[node]).ToList(), 55 | Decorator = face.Decorator, GraphElementColor = face.GraphElementColor 56 | }); 57 | } 58 | MetaData = graph.MetaData; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /PuzzleGraph/SerializableFont.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace PuzzleGraph 9 | { 10 | 11 | // from https://stackoverflow.com/questions/1940127/how-to-xmlserialize-system-drawing-font-class 12 | public class SerializableFont 13 | { 14 | public string FontFamily { get; set; } 15 | public GraphicsUnit GraphicsUnit { get; set; } 16 | public float Size { get; set; } 17 | public FontStyle Style { get; set; } 18 | 19 | /// 20 | /// Intended for xml serialization purposes only 21 | /// 22 | private SerializableFont() { } 23 | 24 | public SerializableFont(Font f) 25 | { 26 | FontFamily = f.FontFamily.Name; 27 | GraphicsUnit = f.Unit; 28 | Size = f.Size; 29 | Style = f.Style; 30 | } 31 | 32 | public static SerializableFont FromFont(Font f) 33 | { 34 | return new SerializableFont(f); 35 | } 36 | 37 | public Font ToFont() 38 | { 39 | return new Font(FontFamily, Size, Style, 40 | GraphicsUnit); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /PuzzleGraph/TetrisTemplate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PuzzleGraph 8 | { 9 | public class TetrisTemplate 10 | { 11 | public List> Shapes { get; set; } = new List>(); 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PuzzleGraph/TransformableDecorator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace PuzzleGraph 8 | { 9 | public class TransformableDecorator : Decorator 10 | { 11 | [LocalizedDisplayName("DeltaX")] 12 | public double DeltaX { get; set; } = 0.0; 13 | [LocalizedDisplayName("DeltaY")] 14 | public double DeltaY { get; set; } = 0.0; 15 | [LocalizedDisplayName("Angle")] 16 | public double Angle { get; set; } = 0.0; 17 | [LocalizedDisplayName("ExtraScale")] 18 | public double ExtraScale { get; set; } = 1.0; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /PuzzleGraph/XmlColor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Text; 5 | using System.Xml.Serialization; 6 | 7 | namespace PuzzleGraph 8 | { 9 | // Code from https://stackoverflow.com/a/4322461 10 | public class XmlColor 11 | { 12 | private Color color_ = Color.Black; 13 | 14 | public XmlColor() { } 15 | public XmlColor(Color c) { color_ = c; } 16 | 17 | 18 | public static implicit operator Color(XmlColor x) 19 | { 20 | return x.color_; 21 | } 22 | 23 | public static implicit operator XmlColor(Color c) 24 | { 25 | return new XmlColor(c); 26 | } 27 | 28 | public static string FromColor(Color color) 29 | { 30 | if (color.IsNamedColor) 31 | return color.Name; 32 | 33 | int colorValue = color.ToArgb(); 34 | 35 | if (((uint)colorValue >> 24) == 0xFF) 36 | return String.Format("#{0:X6}", colorValue & 0x00FFFFFF); 37 | else 38 | return String.Format("#{0:X8}", colorValue); 39 | } 40 | 41 | public static Color ToColor(string value) 42 | { 43 | try 44 | { 45 | if (value[0] == '#') 46 | { 47 | return Color.FromArgb((value.Length <= 7 ? unchecked((int)0xFF000000) : 0) + 48 | Int32.Parse(value.Substring(1), System.Globalization.NumberStyles.HexNumber)); 49 | } 50 | else 51 | { 52 | return Color.FromName(value); 53 | } 54 | } 55 | catch (Exception) 56 | { 57 | } 58 | 59 | return Color.Black; 60 | } 61 | 62 | [XmlText] 63 | public string Default 64 | { 65 | get { return FromColor(color_); } 66 | set { color_ = ToColor(value); } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /PuzzleGraph/XmlFont.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Xml.Serialization; 9 | 10 | namespace PuzzleGraph 11 | { 12 | class XmlFont 13 | { 14 | private Font font_ = SystemFonts.DefaultFont; 15 | 16 | public XmlFont() { } 17 | public XmlFont(Font font) { font_ = font; } 18 | 19 | public static implicit operator Font(XmlFont x) 20 | { 21 | return x.font_; 22 | } 23 | 24 | public static implicit operator XmlFont(Font font) 25 | { 26 | return new XmlFont(font); 27 | } 28 | 29 | // Code from https://stackoverflow.com/questions/19263202/how-to-serialize-font 30 | public static string FromFont(Font font) 31 | { 32 | return font.FontFamily.Name 33 | + ":" + font.Size 34 | + ":" + font.Style 35 | + ":" + font.Unit 36 | + ":" + font.GdiCharSet 37 | + ":" + font.GdiVerticalFont 38 | ; 39 | } 40 | public static Font ToFont(string value) 41 | { 42 | var parts = value.Split(':'); 43 | return new Font( 44 | new FontFamily(parts[0]), // FontFamily.Name 45 | float.Parse(parts[1]), // Size 46 | EnumSerializationHelper.FromString(parts[2]), // Style 47 | EnumSerializationHelper.FromString(parts[3]), // Unit 48 | byte.Parse(parts[4]), // GdiCharSet 49 | bool.Parse(parts[5]) // GdiVerticalFont 50 | ); 51 | } 52 | 53 | [XmlText] 54 | public string Default 55 | { 56 | get { return FromFont(font_); } 57 | set { font_ = ToFont(value); } 58 | } 59 | 60 | } 61 | [TypeConverter(typeof(EnumConverter))] 62 | static public class EnumSerializationHelper 63 | { 64 | 65 | static public T FromString(string value) 66 | { 67 | return (T)Enum.Parse(typeof(T), value, true); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Witness Visualizer 2 | Edit and visualize irregular game panels for The Witness. 3 | 4 | ![image](https://github.com/instr3/WitnessVisualizer/raw/master/Screenshots/1.png) 5 | 6 | ![image](https://github.com/instr3/WitnessVisualizer/raw/master/Screenshots/2.jpg) 7 | 8 | ## Build Environment 9 | .NET Framework 4.7.2 10 | 11 | ## How To Run 12 | 1. Build TemplateGenerator and WitnessVisualizer 13 | 2. Run TemplateGenerator.exe to automatically generate some templates. 14 | 3. Run WitnessVisualizer.exe, open the templates and edit them. 15 | 16 | ## How to add new Decorators 17 | Decorators mean some symbols that are shown on the puzzle's faces/edges/corners. If you want to add a new mechanic (thus need a new symbol) to the puzzles, you can create your own decorator. Two examples in this project are ``RingDecorator`` and ``CircleDecorator`` that do not belong to the original game. 18 | 1. Add and implement a new decorator class in ``PuzzleGraph\Decorators``. See other implemented decorators for reference. 19 | 2. Add a ``XmlInclude(typeof(YourDecoratorClass))`` attribute to ``PuzzleGraph\Decorator.cs`` so it can be (de-)serialized when saving/loading the puzzle. 20 | 3. Implement the rendering method of the decorator in ``WitnessVisualizer\PuzzleGraphRenderer.cs``. 21 | 4. Add a new ``PuzzleToolkitDecoratorItem`` item in ``WitnessVisualizer\PuzzleToolkit.cs`` so that you can find one in the list view on the left of the editor. 22 | 23 | ## Project Structure 24 | 1. PuzzleGraph provides a uniform graph structure for storing irregular game panels. It supports Serialization & Deserialization from XML. 25 | 2. MathHelper provides some basic analytical functions. 26 | 3. WitnessVisualizer implements the main editor form and the rendering functions. 27 | 4. TemplateGenerator is an ugly program to generate some common templates for The Witness puzzles. 28 | 29 | ## Issues 30 | 1. WitnessVisualizer currently does not support adding/modifying graph nodes/edges/faces. 31 | 2. Hollow tetris will sometimes add random fragments due to unknown bugs of the WinForm drawing system. 32 | -------------------------------------------------------------------------------- /Screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instr3/WitnessVisualizer/158f7f4535309879dda782d024ad2bd5dd062810/Screenshots/1.png -------------------------------------------------------------------------------- /Screenshots/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instr3/WitnessVisualizer/158f7f4535309879dda782d024ad2bd5dd062810/Screenshots/2.jpg -------------------------------------------------------------------------------- /TemplateGenerator/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /TemplateGenerator/HexagonTemplateGenerator.cs: -------------------------------------------------------------------------------- 1 | using PuzzleGraph; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace TemplateGenerator 9 | { 10 | class HexagonTemplateGenerator 11 | { 12 | public Graph Generate(int X, int Y, int tetrisTemplateSize, bool roundShape, bool roundShapeTetris) 13 | { 14 | double sqrt3 = Math.Sqrt(3.0); 15 | double scale = 0.75; 16 | Graph graph = new Graph(); 17 | List nodes = new List(); 18 | List edges = new List(); 19 | Node[,] dict1 = new Node[X + 1, Y + 1]; 20 | Node[,] dict2 = new Node[X + 1, Y + 1]; 21 | for (int i = 0; i <= X; ++i) 22 | { 23 | for (int j = 0; j <= Y; ++j) 24 | { 25 | if (i != X || j != 0) 26 | { 27 | dict1[i, j] = new Node(((j - i) * 1.5 - 0.5) * scale, ((j + i) * sqrt3 / 2) * scale); 28 | nodes.Add(dict1[i, j]); 29 | } 30 | if (i != 0 || j != Y) 31 | { 32 | dict2[i, j] = new Node(((j - i) * 1.5 + 0.5) * scale, ((j + i) * sqrt3 / 2) * scale); 33 | nodes.Add(dict2[i, j]); 34 | } 35 | if (dict1[i, j] != null && dict2[i, j] != null) 36 | edges.Add(new Edge(dict1[i, j], dict2[i, j])); 37 | } 38 | } 39 | for (int i = 1; i <= X; ++i) 40 | for (int j = 0; j <= Y; ++j) 41 | edges.Add(new Edge(dict1[i - 1, j], dict2[i, j])); 42 | for (int i = 0; i <= X; ++i) 43 | for (int j = 1; j <= Y; ++j) 44 | edges.Add(new Edge(dict2[i, j - 1], dict1[i, j])); 45 | List faces = new List(); 46 | for (int i = 1; i <= X; ++i) 47 | for (int j = 1; j <= Y; ++j) 48 | faces.Add(new Face(new List() { dict1[i - 1, j - 1], dict2[i - 1, j - 1], dict1[i - 1, j], dict2[i, j], dict1[i, j], dict2[i, j - 1] })); 49 | graph.Nodes.AddRange(nodes); 50 | graph.Edges.AddRange(edges); 51 | graph.Faces.AddRange(faces); 52 | if(roundShape) 53 | { 54 | List toDelete = new List(); 55 | double limit = ((int)X / 2 + 1.1) * 1.5 * scale; 56 | foreach(Node node in graph.Nodes) 57 | { 58 | if (node.X < -limit || node.X > limit) 59 | toDelete.Add(node); 60 | } 61 | foreach (Node node in toDelete) 62 | graph.RemoveElement(node); 63 | graph.MetaData.PuzzleTitle = string.Format("HexRound/HexRoundPuzzle_{0}x{1}", X, Y); 64 | } 65 | else 66 | { 67 | graph.MetaData.PuzzleTitle = string.Format("Hex/HexPuzzle_{0}x{1}", X, Y); 68 | } 69 | GenerateTetrisTemplate(graph, tetrisTemplateSize,roundShapeTetris); 70 | return graph; 71 | } 72 | void GenerateTetrisTemplate(Graph graph,int tetrisTemplateSize,bool roundShape) 73 | { 74 | double sqrt3 = Math.Sqrt(3.0); 75 | double scale = 0.75; 76 | Node[,] dict1 = new Node[tetrisTemplateSize + 1, tetrisTemplateSize + 1]; 77 | Node[,] dict2 = new Node[tetrisTemplateSize + 1, tetrisTemplateSize + 1]; 78 | List> result = new List>(); 79 | List> toDelete = new List>(); 80 | for (int i = 0; i <= tetrisTemplateSize; ++i) 81 | { 82 | for (int j = 0; j <= tetrisTemplateSize; ++j) 83 | { 84 | dict1[i, j] = new Node(((j - i) * 1.5 - 0.5) * scale, ((j + i) * sqrt3 / 2) * scale); 85 | dict2[i, j] = new Node(((j - i) * 1.5 + 0.5) * scale, ((j + i) * sqrt3 / 2) * scale); 86 | } 87 | } 88 | for (int i = 1; i <= tetrisTemplateSize; ++i) 89 | { 90 | for (int j = 1; j <= tetrisTemplateSize; ++j) 91 | { 92 | result.Add(new List() { dict1[i - 1, j - 1], dict2[i - 1, j - 1], dict1[i - 1, j], dict2[i, j], dict1[i, j], dict2[i, j - 1] }); 93 | } 94 | } 95 | if (roundShape) 96 | { 97 | double limit = ((int)tetrisTemplateSize / 2 + 1.1) * 1.5 * scale; 98 | foreach (List shape in result) 99 | { 100 | foreach(Node node in shape) 101 | { 102 | if (node.X < -limit || node.X > limit - 1.1) // todo: why 103 | toDelete.Add(shape); 104 | break; 105 | } 106 | } 107 | } 108 | graph.MetaData.TetrisTemplate.Shapes.AddRange(result.Except(toDelete)); 109 | 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /TemplateGenerator/Program.cs: -------------------------------------------------------------------------------- 1 | using PuzzleGraph; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace TemplateGenerator 10 | { 11 | class Program 12 | { 13 | static void Main(string[] args) 14 | { 15 | SquareTemplateGenerator squareTemplateGenerator = new SquareTemplateGenerator(); 16 | HexagonTemplateGenerator hexagonTemplateGenerator = new HexagonTemplateGenerator(); 17 | RightTriangleTemplateGenerator rightTriangleTemplateGenerator = new RightTriangleTemplateGenerator(); 18 | PyramidHexagonTemplateGenerator pyramidHexagonTemplateGenerator = new PyramidHexagonTemplateGenerator(); 19 | for (int i=1;i<=10;++i) 20 | { 21 | for(int j=1;j<=10;++j) 22 | { 23 | SaveGeneratedPuzzle(squareTemplateGenerator.Generate(i, j, 6)); 24 | SaveGeneratedPuzzle(rightTriangleTemplateGenerator.Generate(i, j, 6)); 25 | SaveGeneratedPuzzle(hexagonTemplateGenerator.Generate(i, j, 7, false, true)); 26 | } 27 | } 28 | for(int i=3;i<=7;i+=2) 29 | { 30 | SaveGeneratedPuzzle(hexagonTemplateGenerator.Generate(i, i, 7, true, true)); 31 | } 32 | for (int i = 2; i <= 8; i += 1) 33 | { 34 | SaveGeneratedPuzzle(pyramidHexagonTemplateGenerator.Generate(i, i, 7, true)); 35 | } 36 | } 37 | static void SaveGeneratedPuzzle(Graph graph) 38 | { 39 | string name = graph.MetaData.PuzzleTitle; 40 | if (name.Contains("/")) 41 | { 42 | Directory.CreateDirectory("Templates/" + name.Substring(0, name.IndexOf("/"))); 43 | } 44 | graph.SaveToFile("Templates/" + name + ".wit"); 45 | } 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /TemplateGenerator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("TemplateGenerator")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TemplateGenerator")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("6a6d539a-27cb-4073-a225-9e63dc45867e")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /TemplateGenerator/PyramidHexagonTemplateGenerator.cs: -------------------------------------------------------------------------------- 1 | using PuzzleGraph; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace TemplateGenerator 9 | { 10 | class PyramidHexagonTemplateGenerator 11 | { 12 | public Graph Generate(int X, int Y, int tetrisTemplateSize, bool roundShapeTetris) 13 | { 14 | double sqrt3 = Math.Sqrt(3.0); 15 | double scale = 0.75; 16 | Graph graph = new Graph(); 17 | List nodes = new List(); 18 | List edges = new List(); 19 | Node[,] dict1 = new Node[X + 1, Y + 1]; 20 | Node[,] dict2 = new Node[X + 1, Y + 1]; 21 | for (int i = 0; i <= X; ++i) 22 | { 23 | for (int j = 0; j <= Y; ++j) 24 | { 25 | if (i != X || j != 0) 26 | { 27 | dict1[i, j] = new Node(((j - i) * 1.5 - 0.5) * scale, ((j + i) * sqrt3 / 2) * scale); 28 | nodes.Add(dict1[i, j]); 29 | } 30 | if (i != 0 || j != Y) 31 | { 32 | dict2[i, j] = new Node(((j - i) * 1.5 + 0.5) * scale, ((j + i) * sqrt3 / 2) * scale); 33 | nodes.Add(dict2[i, j]); 34 | } 35 | if (dict1[i, j] != null && dict2[i, j] != null) 36 | edges.Add(new Edge(dict1[i, j], dict2[i, j])); 37 | } 38 | } 39 | for (int i = 1; i <= X; ++i) 40 | for (int j = 0; j <= Y; ++j) 41 | edges.Add(new Edge(dict1[i - 1, j], dict2[i, j])); 42 | for (int i = 0; i <= X; ++i) 43 | for (int j = 1; j <= Y; ++j) 44 | edges.Add(new Edge(dict2[i, j - 1], dict1[i, j])); 45 | List faces = new List(); 46 | for (int i = 1; i <= X; ++i) 47 | for (int j = 1; j <= Y; ++j) 48 | faces.Add(new Face(new List() { dict1[i - 1, j - 1], dict2[i - 1, j - 1], dict1[i - 1, j], dict2[i, j], dict1[i, j], dict2[i, j - 1] })); 49 | graph.Nodes.AddRange(nodes); 50 | graph.Edges.AddRange(edges); 51 | graph.Faces.AddRange(faces); 52 | List toDelete = new List(); 53 | double limit = 1.1 * scale; 54 | foreach (Node node in graph.Nodes) 55 | { 56 | if (node.X > limit) 57 | toDelete.Add(node); 58 | } 59 | foreach (Node node in toDelete) 60 | graph.RemoveElement(node); 61 | graph.MetaData.PuzzleTitle = string.Format("HexPyramid/HexPyramidPuzzle_{0}x{1}", X, Y); 62 | GenerateTetrisTemplate(graph, tetrisTemplateSize, roundShapeTetris); 63 | return Graph.FlipGraph(graph, Graph.FlipType.XY); 64 | } 65 | void GenerateTetrisTemplate(Graph graph, int tetrisTemplateSize, bool roundShape) 66 | { 67 | double sqrt3 = Math.Sqrt(3.0); 68 | double scale = 0.75; 69 | Node[,] dict1 = new Node[tetrisTemplateSize + 1, tetrisTemplateSize + 1]; 70 | Node[,] dict2 = new Node[tetrisTemplateSize + 1, tetrisTemplateSize + 1]; 71 | List> result = new List>(); 72 | List> toDelete = new List>(); 73 | for (int i = 0; i <= tetrisTemplateSize; ++i) 74 | { 75 | for (int j = 0; j <= tetrisTemplateSize; ++j) 76 | { 77 | dict1[i, j] = new Node(((j - i) * 1.5 - 0.5) * scale, ((j + i) * sqrt3 / 2) * scale); 78 | dict2[i, j] = new Node(((j - i) * 1.5 + 0.5) * scale, ((j + i) * sqrt3 / 2) * scale); 79 | } 80 | } 81 | for (int i = 1; i <= tetrisTemplateSize; ++i) 82 | { 83 | for (int j = 1; j <= tetrisTemplateSize; ++j) 84 | { 85 | result.Add(new List() { dict1[i - 1, j - 1], dict2[i - 1, j - 1], dict1[i - 1, j], dict2[i, j], dict1[i, j], dict2[i, j - 1] }); 86 | } 87 | } 88 | if (roundShape) 89 | { 90 | double limit = 0.0 * scale; 91 | foreach (List shape in result) 92 | { 93 | foreach (Node node in shape) 94 | { 95 | if (node.X > limit) 96 | toDelete.Add(shape); 97 | break; 98 | } 99 | } 100 | } 101 | graph.MetaData.TetrisTemplate.Shapes.AddRange(result.Except(toDelete)); 102 | 103 | } 104 | 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /TemplateGenerator/RightTriangleTemplateGenerator.cs: -------------------------------------------------------------------------------- 1 | using PuzzleGraph; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace TemplateGenerator 9 | { 10 | class RightTriangleTemplateGenerator 11 | { 12 | public Graph Generate(int X, int Y, int tetrisTemplateSize) 13 | { 14 | double scale = 1.2; 15 | Graph graph = new Graph(); 16 | List nodes = new List(); 17 | Node[,] dict = new Node[X + 1, Y + 1]; 18 | for (int i = 0; i <= X; ++i) 19 | { 20 | for (int j = 0; j <= Y; ++j) 21 | { 22 | dict[i, j] = new Node((i + 1) * scale, (j + 1) * scale); 23 | nodes.Add(dict[i, j]); 24 | } 25 | } 26 | List edges = new List(); 27 | for (int i = 1; i <= X; ++i) 28 | for (int j = 0; j <= Y; ++j) 29 | edges.Add(new Edge(dict[i - 1, j], dict[i, j])); 30 | for (int i = 0; i <= X; ++i) 31 | for (int j = 1; j <= Y; ++j) 32 | edges.Add(new Edge(dict[i, j - 1], dict[i, j])); 33 | List faces = new List(); 34 | for (int i = 1; i <= X; ++i) 35 | { 36 | for (int j = 1; j <= Y; ++j) 37 | { 38 | edges.Add(new Edge(dict[i - 1, j - 1], dict[i, j])); 39 | faces.Add(new Face(new List() { dict[i - 1, j - 1], dict[i, j], dict[i - 1, j] })); 40 | faces.Add(new Face(new List() { dict[i - 1, j - 1], dict[i, j - 1], dict[i, j] })); 41 | } 42 | } 43 | graph.Nodes.AddRange(nodes); 44 | graph.Edges.AddRange(edges); 45 | graph.Faces.AddRange(faces); 46 | List> result = new List>(); 47 | dict = new Node[tetrisTemplateSize + 1, tetrisTemplateSize + 1]; 48 | for (int i = 0; i <= tetrisTemplateSize; ++i) 49 | { 50 | for (int j = 0; j <= tetrisTemplateSize; ++j) 51 | { 52 | dict[i, j] = new Node((i + 1) * scale, (j + 1) * scale); 53 | } 54 | } 55 | for (int i = 1; i <= tetrisTemplateSize; ++i) 56 | { 57 | for (int j = 1; j <= tetrisTemplateSize; ++j) 58 | { 59 | result.Add(new List() { dict[i - 1, j - 1], dict[i, j], dict[i - 1, j] }); 60 | result.Add(new List() { dict[i - 1, j - 1], dict[i, j - 1], dict[i, j] }); 61 | } 62 | } 63 | graph.MetaData.TetrisTemplate.Shapes.AddRange(result); 64 | graph.MetaData.PuzzleTitle = string.Format("RightTriangle/RightTrianglePuzzle_{0}x{1}", X, Y); 65 | graph.MetaData.FaceDecorationScale = 0.8; 66 | graph.MetaData.TetrisScale = 0.3; 67 | return graph; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /TemplateGenerator/SquareTemplateGenerator.cs: -------------------------------------------------------------------------------- 1 | using PuzzleGraph; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace TemplateGenerator 9 | { 10 | class SquareTemplateGenerator 11 | { 12 | public Graph Generate(int X,int Y, int tetrisTemplateSize) 13 | { 14 | Graph graph = new Graph(); 15 | List nodes = new List(); 16 | Node[,] dict = new Node[X + 1, Y + 1]; 17 | for (int i = 0; i <= X; ++i) 18 | { 19 | for (int j = 0; j <= Y; ++j) 20 | { 21 | dict[i, j] = new Node(i + 1, j + 1); 22 | nodes.Add(dict[i, j]); 23 | } 24 | } 25 | List edges = new List(); 26 | for (int i = 1; i <= X; ++i) 27 | for (int j = 0; j <= Y; ++j) 28 | edges.Add(new Edge(dict[i - 1, j], dict[i, j])); 29 | for (int i = 0; i <= X; ++i) 30 | for (int j = 1; j <= Y; ++j) 31 | edges.Add(new Edge(dict[i, j - 1], dict[i, j])); 32 | List faces = new List(); 33 | for (int i = 1; i <= X; ++i) 34 | for (int j = 1; j <= Y; ++j) 35 | faces.Add(new Face(new List() { dict[i - 1, j - 1], dict[i, j - 1], dict[i, j], dict[i - 1, j] })); 36 | graph.Nodes.AddRange(nodes); 37 | graph.Edges.AddRange(edges); 38 | graph.Faces.AddRange(faces); 39 | List> result = new List>(); 40 | for (int i = 1; i <= tetrisTemplateSize; ++i) 41 | { 42 | for (int j = 1; j <= tetrisTemplateSize; ++j) 43 | { 44 | result.Add(new List() { new Node(i, j), new Node(i + 1, j), new Node(i + 1, j + 1), new Node(i, j + 1) }); 45 | } 46 | } 47 | graph.MetaData.TetrisTemplate.Shapes.AddRange(result); 48 | graph.MetaData.PuzzleTitle = string.Format("Square/SquarePuzzle_{0}x{1}", X, Y); 49 | return graph; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /TemplateGenerator/TemplateGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6A6D539A-27CB-4073-A225-9E63DC45867E} 8 | Exe 9 | TemplateGenerator 10 | TemplateGenerator 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | ..\WitnessVisualizer\bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | ..\WitnessVisualizer\bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | {4ed83a7c-9e43-4e5e-95ef-f724f5664730} 59 | MathHelper 60 | 61 | 62 | {e6e86344-2472-4da8-8012-70eadba9841c} 63 | PuzzleGraph 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /WitnessVisualizer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29025.244 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WitnessVisualizer", "WitnessVisualizer\WitnessVisualizer.csproj", "{1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PuzzleGraph", "PuzzleGraph\PuzzleGraph.csproj", "{E6E86344-2472-4DA8-8012-70EADBA9841C}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MathHelper", "MathHelper\MathHelper.csproj", "{4ED83A7C-9E43-4E5E-95EF-F724F5664730}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemplateGenerator", "TemplateGenerator\TemplateGenerator.csproj", "{6A6D539A-27CB-4073-A225-9E63DC45867E}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|x64 = Debug|x64 18 | Debug|x86 = Debug|x86 19 | Release|Any CPU = Release|Any CPU 20 | Release|x64 = Release|x64 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Debug|x64.ActiveCfg = Debug|Any CPU 27 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Debug|x64.Build.0 = Debug|Any CPU 28 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Debug|x86.ActiveCfg = Debug|Any CPU 29 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Debug|x86.Build.0 = Debug|Any CPU 30 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Release|x64.ActiveCfg = Release|Any CPU 33 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Release|x64.Build.0 = Release|Any CPU 34 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Release|x86.ActiveCfg = Release|Any CPU 35 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49}.Release|x86.Build.0 = Release|Any CPU 36 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Debug|x64.ActiveCfg = Debug|Any CPU 39 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Debug|x64.Build.0 = Debug|Any CPU 40 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Debug|x86.ActiveCfg = Debug|Any CPU 41 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Debug|x86.Build.0 = Debug|Any CPU 42 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Release|x64.ActiveCfg = Release|Any CPU 45 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Release|x64.Build.0 = Release|Any CPU 46 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Release|x86.ActiveCfg = Release|Any CPU 47 | {E6E86344-2472-4DA8-8012-70EADBA9841C}.Release|x86.Build.0 = Release|Any CPU 48 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Debug|x64.ActiveCfg = Debug|Any CPU 51 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Debug|x64.Build.0 = Debug|Any CPU 52 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Debug|x86.ActiveCfg = Debug|Any CPU 53 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Debug|x86.Build.0 = Debug|Any CPU 54 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Release|x64.ActiveCfg = Release|Any CPU 57 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Release|x64.Build.0 = Release|Any CPU 58 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Release|x86.ActiveCfg = Release|Any CPU 59 | {4ED83A7C-9E43-4E5E-95EF-F724F5664730}.Release|x86.Build.0 = Release|Any CPU 60 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Debug|x64.ActiveCfg = Debug|Any CPU 63 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Debug|x64.Build.0 = Debug|Any CPU 64 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Debug|x86.ActiveCfg = Debug|Any CPU 65 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Debug|x86.Build.0 = Debug|Any CPU 66 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Release|Any CPU.ActiveCfg = Release|Any CPU 67 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Release|Any CPU.Build.0 = Release|Any CPU 68 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Release|x64.ActiveCfg = Release|Any CPU 69 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Release|x64.Build.0 = Release|Any CPU 70 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Release|x86.ActiveCfg = Release|Any CPU 71 | {6A6D539A-27CB-4073-A225-9E63DC45867E}.Release|x86.Build.0 = Release|Any CPU 72 | EndGlobalSection 73 | GlobalSection(SolutionProperties) = preSolution 74 | HideSolutionNode = FALSE 75 | EndGlobalSection 76 | GlobalSection(ExtensibilityGlobals) = postSolution 77 | SolutionGuid = {50DEADD1-478E-481E-BCF2-FFA5AE72A3C4} 78 | EndGlobalSection 79 | EndGlobal 80 | -------------------------------------------------------------------------------- /WitnessVisualizer/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /WitnessVisualizer/EditManager.cs: -------------------------------------------------------------------------------- 1 | using PuzzleGraph; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace WitnessVisualizer 9 | { 10 | class EditManager where T : ICloneable 11 | { 12 | const int UNDO_STACK_SIZE = 50; 13 | T newestRecord; 14 | LinkedList> undoStack; 15 | LinkedListNode> undoPtr, redoPtr; 16 | public bool CanUndo 17 | { 18 | get { return undoPtr != null; } 19 | } 20 | public string LastUndoInfo 21 | { 22 | get { return CanUndo ? undoPtr.Value.Key : ""; } 23 | } 24 | public bool CanRedo 25 | { 26 | get { return undoPtr != redoPtr; } 27 | } 28 | public string LastRedoInfo 29 | { 30 | get { return CanRedo ? (undoPtr == null ? undoStack.First : undoPtr.Next).Value.Key : ""; } 31 | } 32 | public EditManager() 33 | { 34 | Reset(); 35 | } 36 | public void Reset() 37 | { 38 | undoStack = new LinkedList>(); 39 | undoPtr = redoPtr = null; 40 | } 41 | public void BeforePreformEdit(T state, string commandName) 42 | { 43 | while (undoPtr != redoPtr) 44 | { 45 | var preNode = redoPtr.Previous; 46 | undoStack.Remove(redoPtr); 47 | redoPtr = preNode; 48 | } 49 | string localizedCommandName = Resources.Lang.ResourceManager.GetString("Undo>>" + commandName) ?? commandName; 50 | undoPtr = new LinkedListNode>( 51 | new KeyValuePair(localizedCommandName, (T)state.Clone())); 52 | redoPtr = undoPtr; 53 | 54 | undoStack.AddLast(undoPtr); 55 | if (undoStack.Count > UNDO_STACK_SIZE) undoStack.RemoveFirst(); 56 | } 57 | public T Undo(T state) 58 | { 59 | if (CanUndo) 60 | { 61 | if (!CanRedo) 62 | { 63 | newestRecord = state; 64 | } 65 | T result = undoPtr.Value.Value; 66 | if (undoPtr == undoStack.First) 67 | { 68 | undoPtr = null; 69 | } 70 | else undoPtr = undoPtr.Previous; 71 | return result; 72 | } 73 | return default; 74 | } 75 | public T Redo() 76 | { 77 | if (CanRedo) 78 | { 79 | undoPtr = undoPtr == null ? undoStack.First : undoPtr.Next; 80 | return CanRedo ? undoPtr.Next.Value.Value : newestRecord; 81 | } 82 | return default; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /WitnessVisualizer/FormHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Forms; 8 | 9 | namespace WitnessVisualizer 10 | { 11 | class FormHelper 12 | { 13 | internal static void ChangeDescriptionHeight(PropertyGrid grid, int height) 14 | { 15 | if (grid == null) throw new ArgumentNullException("grid"); 16 | 17 | foreach (Control control in grid.Controls) 18 | if (control.GetType().Name == "DocComment") 19 | { 20 | FieldInfo fieldInfo = control.GetType().BaseType.GetField("userSized", 21 | BindingFlags.Instance | 22 | BindingFlags.NonPublic); 23 | fieldInfo.SetValue(control, true); 24 | control.Height = height; 25 | return; 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /WitnessVisualizer/GraphManipulation.cs: -------------------------------------------------------------------------------- 1 | using MathHelper; 2 | using PuzzleGraph; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace WitnessVisualizer 10 | { 11 | class GraphManipulation 12 | { 13 | public static Face QueryFace(Graph graph, Node node1, Node node2) 14 | { 15 | foreach (Face face in graph.Faces) 16 | { 17 | for (int i = 0; i < face.Nodes.Count; ++i) 18 | { 19 | if (face.Nodes[i] == node2 && face.Nodes[i == 0 ? face.Nodes.Count - 1 : i - 1] == node1) 20 | { 21 | return face; 22 | } 23 | } 24 | } 25 | return null; 26 | } 27 | 28 | public static Edge QueryEdge(Graph graph, Node node1, Node node2) 29 | { 30 | foreach (Edge edge in graph.Edges) 31 | { 32 | if (edge.Start == node1 && edge.End == node2) return edge; 33 | if (edge.Start == node2 && edge.End == node1) return edge; 34 | } 35 | return null; 36 | } 37 | 38 | public static Node QueryNearByNodes(Graph graph, Vector query, double Eps = 1e-3) 39 | { 40 | foreach (Node node in graph.Nodes) 41 | { 42 | Vector position = new Vector(node.X, node.Y); 43 | if (Vector.PointDistance(position, query) <= Eps) 44 | return node; 45 | } 46 | return null; 47 | } 48 | private static List OrientedPolygon(List shape) 49 | { 50 | // Algorithm from https://stackoverflow.com/a/1165943 51 | if (shape.Count <= 2) return shape; 52 | double total = 0; 53 | for (int i = 0; i < shape.Count; ++i) 54 | { 55 | Node node1 = shape[i == 0 ? shape.Count - 1 : i - 1]; 56 | Node node2 = shape[i]; 57 | total += (node2.X - node1.X) * (node2.Y + node1.Y); 58 | } 59 | if(total>0) 60 | { 61 | List result = new List(); 62 | result.AddRange(shape); 63 | result.Reverse(); 64 | return result; 65 | } 66 | return shape; 67 | } 68 | private static List MappingShapesToNewPosition(List shape, Node node0, Node node1) 69 | { 70 | if (shape.Count < 2) 71 | { 72 | throw new NotSupportedException("The shape has too few nodes."); 73 | } 74 | Vector o1 = new Vector(shape[0].X, shape[0].Y); 75 | Vector o2 = new Vector(node0.X, node0.Y); 76 | Vector v1 = new Vector(shape[1].X - shape[0].X, shape[1].Y - shape[0].Y); 77 | Vector v2 = new Vector(node1.X - node0.X, node1.Y - node0.Y); 78 | Vector u1 = new Vector(v1.Y, -v1.X); 79 | Vector u2 = new Vector(v2.Y, -v2.X); 80 | double l1 = v1.X * v1.X + v1.Y * v1.Y; 81 | double l2 = v2.X * v2.X + v2.Y * v2.Y; 82 | List newShape = new List(shape.Count); 83 | foreach (Node node in shape) 84 | { 85 | Vector pos = new Vector(node.X, node.Y) - o1; 86 | double uCoord = (pos ^ u1) / l1; 87 | double vCoord = (pos ^ v1) / l1; 88 | Vector pos2 = uCoord * u2 + vCoord * v2 + o2; 89 | newShape.Add(new Node(pos2.X, pos2.Y)); 90 | } 91 | return newShape; 92 | } 93 | public static void AddShape(Graph graph,List shape) 94 | { 95 | shape = OrientedPolygon(shape); 96 | List existNodes = shape.Select(node => QueryNearByNodes(graph, new Vector(node.X, node.Y))).ToList(); 97 | List faceNodes = new List(shape.Count); 98 | for (int i = 0; i < shape.Count; ++i) 99 | { 100 | if (existNodes[i] is null) 101 | { 102 | graph.Nodes.Add(shape[i]); 103 | faceNodes.Add(shape[i]); 104 | } 105 | else 106 | { 107 | faceNodes.Add(existNodes[i]); 108 | } 109 | } 110 | if (faceNodes.Count > 1) 111 | { 112 | for (int i = 0; i < shape.Count; ++i) 113 | { 114 | int prev = i == 0 ? shape.Count - 1 : i - 1; 115 | if (QueryEdge(graph, faceNodes[prev], faceNodes[i]) is null) 116 | { 117 | graph.Edges.Add(new Edge(faceNodes[prev], faceNodes[i])); 118 | } 119 | } 120 | if (faceNodes.Count > 2) 121 | graph.Faces.Add(new Face(faceNodes)); 122 | } 123 | 124 | } 125 | public static void AddShapeWithBaseDirectedSegment(Graph graph, Node node0, Node node1, List shape) 126 | { 127 | List mappedShape = MappingShapesToNewPosition(shape, node0, node1); 128 | AddShape(graph, mappedShape); 129 | } 130 | public static List CreateRegularPolygon(int edges) 131 | { 132 | double angle = 2 * Math.PI / edges; 133 | return Enumerable.Range(0, edges).Select(i => new Node(Math.Cos(i * angle), Math.Sin(i * angle))).ToList(); 134 | } 135 | 136 | public static void TryAddShapeWithBaseSegment(Graph graph, Edge edge, List shape) 137 | { 138 | if(QueryFace(graph, edge.Start, edge.End) is null) 139 | AddShapeWithBaseDirectedSegment(graph, edge.Start, edge.End, shape); 140 | else if(QueryFace(graph, edge.End, edge.Start) is null) 141 | AddShapeWithBaseDirectedSegment(graph, edge.End, edge.Start, shape); 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /WitnessVisualizer/Icons/ColorPicker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instr3/WitnessVisualizer/158f7f4535309879dda782d024ad2bd5dd062810/WitnessVisualizer/Icons/ColorPicker.png -------------------------------------------------------------------------------- /WitnessVisualizer/Icons/Cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instr3/WitnessVisualizer/158f7f4535309879dda782d024ad2bd5dd062810/WitnessVisualizer/Icons/Cursor.png -------------------------------------------------------------------------------- /WitnessVisualizer/Icons/Paint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instr3/WitnessVisualizer/158f7f4535309879dda782d024ad2bd5dd062810/WitnessVisualizer/Icons/Paint.png -------------------------------------------------------------------------------- /WitnessVisualizer/InputDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | 8 | namespace WitnessVisualizer 9 | { 10 | class InputDialog 11 | { 12 | // Code from https://stackoverflow.com/a/17546909 13 | public static DialogResult ShowInputDialog(string title, ref string input) 14 | { 15 | System.Drawing.Size size = new System.Drawing.Size(200, 70); 16 | Form inputBox = new Form(); 17 | 18 | inputBox.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 19 | inputBox.ClientSize = size; 20 | inputBox.Text = title; 21 | 22 | System.Windows.Forms.TextBox textBox = new TextBox(); 23 | textBox.Size = new System.Drawing.Size(size.Width - 10, 23); 24 | textBox.Location = new System.Drawing.Point(5, 5); 25 | textBox.Text = input; 26 | inputBox.Controls.Add(textBox); 27 | 28 | Button okButton = new Button(); 29 | okButton.DialogResult = System.Windows.Forms.DialogResult.OK; 30 | okButton.Name = "okButton"; 31 | okButton.Size = new System.Drawing.Size(75, 23); 32 | okButton.Text = "&OK"; 33 | okButton.Location = new System.Drawing.Point(size.Width - 80 - 80, 39); 34 | inputBox.Controls.Add(okButton); 35 | 36 | Button cancelButton = new Button(); 37 | cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; 38 | cancelButton.Name = "cancelButton"; 39 | cancelButton.Size = new System.Drawing.Size(75, 23); 40 | cancelButton.Text = "&Cancel"; 41 | cancelButton.Location = new System.Drawing.Point(size.Width - 80, 39); 42 | inputBox.Controls.Add(cancelButton); 43 | 44 | inputBox.AcceptButton = okButton; 45 | inputBox.CancelButton = cancelButton; 46 | 47 | DialogResult result = inputBox.ShowDialog(); 48 | input = textBox.Text; 49 | return result; 50 | } 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /WitnessVisualizer/PaintingModeControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace WitnessVisualizer 9 | { 10 | class PaintingModeControl 11 | { 12 | public Color Color { get; set; } = Color.White; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /WitnessVisualizer/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace WitnessVisualizer 12 | { 13 | static class Program 14 | { 15 | /// 16 | /// 应用程序的主入口点。 17 | /// 18 | [STAThread] 19 | static void Main(string[] args) 20 | { 21 | string exeDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 22 | Directory.SetCurrentDirectory(exeDir); 23 | Application.EnableVisualStyles(); 24 | Application.SetCompatibleTextRenderingDefault(false); 25 | Application.Run(new MainForm(args)); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /WitnessVisualizer/Prompt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | 8 | namespace WitnessVisualizer 9 | { 10 | public static class Prompt 11 | { 12 | // Code from https://stackoverflow.com/a/5427121 13 | public static string ShowDialog(string text, string caption) 14 | { 15 | Form prompt = new Form() 16 | { 17 | Width = 500, 18 | Height = 150, 19 | FormBorderStyle = FormBorderStyle.FixedDialog, 20 | Text = caption, 21 | StartPosition = FormStartPosition.CenterScreen 22 | }; 23 | Label textLabel = new Label() { Left = 50, Top = 20, Width = 400, Text = text }; 24 | TextBox textBox = new TextBox() { Left = 50, Top = 50, Width = 400 }; 25 | Button confirmation = new Button() { Text = "Ok", Left = 350, Width = 100, Top = 70, DialogResult = DialogResult.OK }; 26 | confirmation.Click += (sender, e) => { prompt.Close(); }; 27 | prompt.Controls.Add(textBox); 28 | prompt.Controls.Add(confirmation); 29 | prompt.Controls.Add(textLabel); 30 | prompt.AcceptButton = confirmation; 31 | 32 | return prompt.ShowDialog() == DialogResult.OK ? textBox.Text : ""; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /WitnessVisualizer/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("WitnessVisualizer")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WitnessVisualizer")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("1bc3cf7a-223a-4ff4-9ada-cbe66bbcba49")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /WitnessVisualizer/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WitnessVisualizer.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WitnessVisualizer.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 重写当前线程的 CurrentUICulture 属性 51 | /// 重写当前线程的 CurrentUICulture 属性。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /WitnessVisualizer/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /WitnessVisualizer/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WitnessVisualizer.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.2.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /WitnessVisualizer/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WitnessVisualizer/PuzzleSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace WitnessVisualizer 9 | { 10 | class PuzzleSettings 11 | { 12 | private string tempUnit; 13 | private int tempValue; 14 | 15 | [Category("Global Settings"), 16 | ReadOnly(false), 17 | DefaultValue("Celsius")] 18 | public string TemperatureUnit 19 | { 20 | get { return tempUnit; } 21 | set { tempUnit = value; } 22 | } 23 | 24 | [Category("Global Settings"), 25 | ReadOnly(false), 26 | DefaultValue(2)] 27 | public int TemperatureValue 28 | { 29 | get { return tempValue; } 30 | set { tempValue = value; } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /WitnessVisualizer/PuzzleToolkit.cs: -------------------------------------------------------------------------------- 1 | using PuzzleGraph; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Xml.Serialization; 10 | 11 | namespace WitnessVisualizer 12 | { 13 | public class PuzzleToolkit 14 | { 15 | public List Items { get; set; } = new List(); 16 | 17 | public static PuzzleToolkit CreateDefaultPuzzleToolkit() 18 | { 19 | List> exampleShapes = new List>() { 20 | new List() { new Node(1.0,1.0), new Node(2.0, 1.0), new Node(2.0,2.0), new Node(1.0, 2.0) } 21 | }; 22 | List exampleIndex = new List() { 0 }; 23 | PuzzleToolkit Toolkit = new PuzzleToolkit(); 24 | Toolkit.Items.Add(new PuzzleToolkitMiscItem(Resources.Lang.Pointer, "Icons/Cursor.png")); 25 | Toolkit.Items.Add(new PuzzleToolkitMiscItem(Resources.Lang.Painter, "Icons/Paint.png")); 26 | // Toolkit.Items.Add(new PuzzleToolkitMiscItem(Resources.Lang.ColorPicker, Image.FromFile("Icons/ColorPicker.png"))); 27 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Empty, null)); 28 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Eliminator, new PuzzleGraph.Decorators.EliminatorDecorator())); 29 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Triangle1, new PuzzleGraph.Decorators.TriangleDecorator() { Count = 1 })); 30 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Triangle2, new PuzzleGraph.Decorators.TriangleDecorator() { Count = 2 })); 31 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Triangle3, new PuzzleGraph.Decorators.TriangleDecorator() { Count = 3 })); 32 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Triangle4, new PuzzleGraph.Decorators.TriangleDecorator() { Count = 4 })); 33 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Arrow, new PuzzleGraph.Decorators.ArrowDecorator() { Count = 2 })); 34 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Tetris, new PuzzleGraph.Decorators.TetrisDecorator() { Indexes = exampleIndex, Shapes = exampleShapes })); 35 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.HollowTetris, new PuzzleGraph.Decorators.HollowTetrisDecorator() { Indexes = exampleIndex, Shapes = exampleShapes })); 36 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.SkewTetris, new PuzzleGraph.Decorators.TetrisDecorator() { Indexes = exampleIndex, Shapes = exampleShapes, Angle = -15 })); 37 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.SkewHollowTetris, new PuzzleGraph.Decorators.HollowTetrisDecorator() { Indexes = exampleIndex, Shapes = exampleShapes, Angle = -15 })); 38 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Star, new PuzzleGraph.Decorators.StarDecorator())); 39 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Square, new PuzzleGraph.Decorators.SquareDecorator())); 40 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Circle, new PuzzleGraph.Decorators.CircleDecorator())); 41 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Ring, new PuzzleGraph.Decorators.RingDecorator())); 42 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Point, new PuzzleGraph.Decorators.PointDecorator(), 0.5)); 43 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.SelfIntersection, new PuzzleGraph.Decorators.SelfIntersectionDecorator(), 0.5)); 44 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Broken, new PuzzleGraph.Decorators.BrokenDecorator(), 0.25)); 45 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Start, new PuzzleGraph.Decorators.StartDecorator(), 0.25)); 46 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.EndR, new PuzzleGraph.Decorators.EndDecorator() { Angle = 0 }, 0.25)); 47 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.EndL, new PuzzleGraph.Decorators.EndDecorator() { Angle = 180 }, 0.25)); 48 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.EndU, new PuzzleGraph.Decorators.EndDecorator() { Angle = -90 }, 0.25)); 49 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.EndD, new PuzzleGraph.Decorators.EndDecorator() { Angle = 90 }, 0.25)); 50 | // Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.EndRD, new PuzzleGraph.Decorators.EndDecorator() { Angle = 45 }, 0.25)); 51 | // Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.EndLD, new PuzzleGraph.Decorators.EndDecorator() { Angle = 135 }, 0.25)); 52 | // Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.EndLU, new PuzzleGraph.Decorators.EndDecorator() { Angle = -135 }, 0.25)); 53 | // Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.EndRU, new PuzzleGraph.Decorators.EndDecorator() { Angle = -45 }, 0.25)); 54 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Text, new PuzzleGraph.Decorators.TextDecorator() { Font = SystemFonts.MessageBoxFont, Text = "A" })); 55 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Symbol, new PuzzleGraph.Decorators.TextDecorator() { Font = SystemFonts.MessageBoxFont, Text = "\u2460" })); 56 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Emoji, new PuzzleGraph.Decorators.TextDecorator() { Font = new Font("Segoe UI Emoji",9), Text = "\U0001F600" })); 57 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.Box, new PuzzleGraph.Decorators.BoxDecorator())); 58 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.VerticalSymmetry, new PuzzleGraph.Decorators.SymmetryPuzzleDecorator() { IsRotational = false, Angle = 0 })); 59 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.HorizontalSymmetry, new PuzzleGraph.Decorators.SymmetryPuzzleDecorator() { IsRotational = false, Angle = 90 })); 60 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.RotationalSymmetry, new PuzzleGraph.Decorators.SymmetryPuzzleDecorator() { IsRotational = true, Angle = 0 })); 61 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.ParallelSymmetry, new PuzzleGraph.Decorators.ParallelPuzzleDecorator() { TranslationX = 0.35, TranslationY = 0.0 })); 62 | Toolkit.Items.Add(new PuzzleToolkitDecoratorItem(Resources.Lang.ThreeWaySymmetry, new PuzzleGraph.Decorators.ThreeWayPuzzleDecorator() { Angle = 0 })); 63 | return Toolkit; 64 | } 65 | public static double GetSuggestedDecorationScale(PuzzleGraph.Decorator decorator) 66 | { 67 | if (decorator is PuzzleGraph.Decorators.StartDecorator) return 0.25; 68 | if (decorator is PuzzleGraph.Decorators.BrokenDecorator) return 0.25; 69 | if (decorator is PuzzleGraph.Decorators.EndDecorator) return 0.25; 70 | if (decorator is PuzzleGraph.Decorators.PointDecorator) return 0.5; 71 | return 1.0; 72 | } 73 | public void SaveToFile(string fileName) 74 | { 75 | XmlSerializer xml = new XmlSerializer(typeof(PuzzleToolkit)); 76 | using (FileStream fs = new FileStream(fileName, FileMode.Create)) 77 | { 78 | xml.Serialize(fs, this); 79 | } 80 | } 81 | public static PuzzleToolkit LoadFromFile(string fileName) 82 | { 83 | XmlSerializer xml = new XmlSerializer(typeof(PuzzleToolkit)); 84 | using (FileStream fs = new FileStream(fileName, FileMode.Open)) 85 | { 86 | return xml.Deserialize(fs) as PuzzleToolkit; 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /WitnessVisualizer/PuzzleToolkitDecoratorItem.cs: -------------------------------------------------------------------------------- 1 | using PuzzleGraph; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using MathHelper; 9 | using System.Drawing.Drawing2D; 10 | 11 | namespace WitnessVisualizer 12 | { 13 | public class PuzzleToolkitDecoratorItem : PuzzleToolkitItem 14 | { 15 | public Decorator Decorator { get; set; } 16 | private static MetaData metaData; 17 | public double AdditionalScale { get; set; } 18 | Image image; 19 | static PuzzleToolkitDecoratorItem() 20 | { 21 | metaData = new MetaData(); 22 | metaData.BackgroundColor = Color.FromArgb(240, 240, 240); 23 | metaData.ForegroundColor = Color.Black; 24 | metaData.TetrisTemplate = new TetrisTemplate() 25 | { 26 | Shapes = new List>() { 27 | new List() { new Node(1.0,1.0), new Node(2.0, 1.0), new Node(2.0,2.0), new Node(1.0, 2.0) } 28 | } 29 | }; 30 | } 31 | public PuzzleToolkitDecoratorItem(string inputName, Decorator inputDecorator,double inputAdditionalScale=1.0) 32 | { 33 | Name = inputName; 34 | Decorator = inputDecorator; 35 | AdditionalScale = inputAdditionalScale; 36 | } 37 | 38 | private PuzzleToolkitDecoratorItem() { } 39 | 40 | public void Draw(Graphics graphics, int width, int height) 41 | { 42 | PuzzleGraphRenderer renderer = new PuzzleGraphRenderer(graphics); 43 | renderer.DrawDecorator(Decorator, new Vector(width / 2.0, height / 2.0), width * AdditionalScale, metaData, metaData.BackgroundColor, true); 44 | } 45 | public override Image GetImage(int width, int height) 46 | { 47 | if(image==null) 48 | { 49 | image = new Bitmap(width, height); 50 | using (Graphics g = Graphics.FromImage(image)) 51 | { 52 | using (Pen pen = new Pen(Color.Gray, 3)) 53 | { 54 | g.Clear(metaData.BackgroundColor); 55 | g.DrawRectangle(pen, 0.0f, 0.0f, width - 1, height - 1); 56 | } 57 | g.SmoothingMode = SmoothingMode.AntiAlias; 58 | Draw(g, width, height); 59 | } 60 | } 61 | return image; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /WitnessVisualizer/PuzzleToolkitItem.cs: -------------------------------------------------------------------------------- 1 | using PuzzleGraph; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Xml.Serialization; 9 | 10 | namespace WitnessVisualizer 11 | { 12 | [ 13 | XmlInclude(typeof(PuzzleToolkitMiscItem)), 14 | XmlInclude(typeof(PuzzleToolkitDecoratorItem)), 15 | ] 16 | public abstract class PuzzleToolkitItem 17 | { 18 | public string Name { get; set; } 19 | public abstract Image GetImage(int width, int height); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /WitnessVisualizer/PuzzleToolkitMiscItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace WitnessVisualizer 10 | { 11 | public class PuzzleToolkitMiscItem : PuzzleToolkitItem 12 | { 13 | public string IconPath { get; set; } 14 | Image icon; 15 | public PuzzleToolkitMiscItem(string inputName,string inputIconPath) 16 | { 17 | Name = inputName; 18 | IconPath = inputIconPath; 19 | } 20 | 21 | private PuzzleToolkitMiscItem() { } 22 | 23 | public override Image GetImage(int width, int height) 24 | { 25 | if(icon==null) 26 | { 27 | try 28 | { 29 | icon = Image.FromFile(IconPath); 30 | } 31 | catch 32 | { 33 | return null; 34 | } 35 | } 36 | return icon; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /WitnessVisualizer/Puzzles/README.txt: -------------------------------------------------------------------------------- 1 | This is the puzzle folder. -------------------------------------------------------------------------------- /WitnessVisualizer/Resources/Lang.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 WitnessVisualizer.Resources { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Lang { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Lang() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WitnessVisualizer.Resources.Lang", typeof(Lang).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Arrow. 65 | /// 66 | internal static string Arrow { 67 | get { 68 | return ResourceManager.GetString("Arrow", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Box. 74 | /// 75 | internal static string Box { 76 | get { 77 | return ResourceManager.GetString("Box", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to Broken. 83 | /// 84 | internal static string Broken { 85 | get { 86 | return ResourceManager.GetString("Broken", resourceCulture); 87 | } 88 | } 89 | 90 | /// 91 | /// Looks up a localized string similar to Circle. 92 | /// 93 | internal static string Circle { 94 | get { 95 | return ResourceManager.GetString("Circle", resourceCulture); 96 | } 97 | } 98 | 99 | /// 100 | /// Looks up a localized string similar to DeltaX. 101 | /// 102 | internal static string DeltaX { 103 | get { 104 | return ResourceManager.GetString("DeltaX", resourceCulture); 105 | } 106 | } 107 | 108 | /// 109 | /// Looks up a localized string similar to DeltaY. 110 | /// 111 | internal static string DeltaY { 112 | get { 113 | return ResourceManager.GetString("DeltaY", resourceCulture); 114 | } 115 | } 116 | 117 | /// 118 | /// Looks up a localized string similar to Eliminator. 119 | /// 120 | internal static string Eliminator { 121 | get { 122 | return ResourceManager.GetString("Eliminator", resourceCulture); 123 | } 124 | } 125 | 126 | /// 127 | /// Looks up a localized string similar to Emoji. 128 | /// 129 | internal static string Emoji { 130 | get { 131 | return ResourceManager.GetString("Emoji", resourceCulture); 132 | } 133 | } 134 | 135 | /// 136 | /// Looks up a localized string similar to Empty. 137 | /// 138 | internal static string Empty { 139 | get { 140 | return ResourceManager.GetString("Empty", resourceCulture); 141 | } 142 | } 143 | 144 | /// 145 | /// Looks up a localized string similar to EndD. 146 | /// 147 | internal static string EndD { 148 | get { 149 | return ResourceManager.GetString("EndD", resourceCulture); 150 | } 151 | } 152 | 153 | /// 154 | /// Looks up a localized string similar to EndL. 155 | /// 156 | internal static string EndL { 157 | get { 158 | return ResourceManager.GetString("EndL", resourceCulture); 159 | } 160 | } 161 | 162 | /// 163 | /// Looks up a localized string similar to EndR. 164 | /// 165 | internal static string EndR { 166 | get { 167 | return ResourceManager.GetString("EndR", resourceCulture); 168 | } 169 | } 170 | 171 | /// 172 | /// Looks up a localized string similar to EndU. 173 | /// 174 | internal static string EndU { 175 | get { 176 | return ResourceManager.GetString("EndU", resourceCulture); 177 | } 178 | } 179 | 180 | /// 181 | /// Looks up a localized string similar to [Error] Please name the object using the text box.. 182 | /// 183 | internal static string Errors_NameEmpty { 184 | get { 185 | return ResourceManager.GetString("Errors.NameEmpty", resourceCulture); 186 | } 187 | } 188 | 189 | /// 190 | /// Looks up a localized string similar to [Error] Please select an edge first.. 191 | /// 192 | internal static string Errors_NoEdge { 193 | get { 194 | return ResourceManager.GetString("Errors.NoEdge", resourceCulture); 195 | } 196 | } 197 | 198 | /// 199 | /// Looks up a localized string similar to [Error] Please select at least an element first.. 200 | /// 201 | internal static string Errors_NoElement { 202 | get { 203 | return ResourceManager.GetString("Errors.NoElement", resourceCulture); 204 | } 205 | } 206 | 207 | /// 208 | /// Looks up a localized string similar to [Error] Please select at least an tetris element first.. 209 | /// 210 | internal static string Errors_NoTetris { 211 | get { 212 | return ResourceManager.GetString("Errors.NoTetris", resourceCulture); 213 | } 214 | } 215 | 216 | /// 217 | /// Looks up a localized string similar to ExtraScale. 218 | /// 219 | internal static string ExtraScale { 220 | get { 221 | return ResourceManager.GetString("ExtraScale", resourceCulture); 222 | } 223 | } 224 | 225 | /// 226 | /// Looks up a localized string similar to Hint. 227 | /// 228 | internal static string Hint { 229 | get { 230 | return ResourceManager.GetString("Hint", resourceCulture); 231 | } 232 | } 233 | 234 | /// 235 | /// Looks up a localized string similar to Hollow Tetris. 236 | /// 237 | internal static string HollowTetris { 238 | get { 239 | return ResourceManager.GetString("HollowTetris", resourceCulture); 240 | } 241 | } 242 | 243 | /// 244 | /// Looks up a localized string similar to Horizontal Symmetry. 245 | /// 246 | internal static string HorizontalSymmetry { 247 | get { 248 | return ResourceManager.GetString("HorizontalSymmetry", resourceCulture); 249 | } 250 | } 251 | 252 | /// 253 | /// Looks up a localized string similar to Added {0} Items.. 254 | /// 255 | internal static string Info_AddItems { 256 | get { 257 | return ResourceManager.GetString("Info.AddItems", resourceCulture); 258 | } 259 | } 260 | 261 | /// 262 | /// Looks up a localized string similar to Please (use Ctrl) to select two decorations to combine them.. 263 | /// 264 | internal static string Info_Combine { 265 | get { 266 | return ResourceManager.GetString("Info.Combine", resourceCulture); 267 | } 268 | } 269 | 270 | /// 271 | /// Looks up a localized string similar to Enter the angle (clockwise) in degrees:. 272 | /// 273 | internal static string Info_EnterDegrees { 274 | get { 275 | return ResourceManager.GetString("Info.EnterDegrees", resourceCulture); 276 | } 277 | } 278 | 279 | /// 280 | /// Looks up a localized string similar to Enter the scale factor of X:. 281 | /// 282 | internal static string Info_EnterXScale { 283 | get { 284 | return ResourceManager.GetString("Info.EnterXScale", resourceCulture); 285 | } 286 | } 287 | 288 | /// 289 | /// Looks up a localized string similar to Enter the scale factor of Y:. 290 | /// 291 | internal static string Info_EnterYScale { 292 | get { 293 | return ResourceManager.GetString("Info.EnterYScale", resourceCulture); 294 | } 295 | } 296 | 297 | /// 298 | /// Looks up a localized string similar to Please enter a float scale factor (e.g., 2.0 or 0.5).. 299 | /// 300 | internal static string Info_FloatScale { 301 | get { 302 | return ResourceManager.GetString("Info.FloatScale", resourceCulture); 303 | } 304 | } 305 | 306 | /// 307 | /// Looks up a localized string similar to You cannot undo this.. 308 | /// 309 | internal static string Info_NoUndo { 310 | get { 311 | return ResourceManager.GetString("Info.NoUndo", resourceCulture); 312 | } 313 | } 314 | 315 | /// 316 | /// Looks up a localized string similar to Are you sure you want to delete . 317 | /// 318 | internal static string Info_ToDelete { 319 | get { 320 | return ResourceManager.GetString("Info.ToDelete", resourceCulture); 321 | } 322 | } 323 | 324 | /// 325 | /// Looks up a localized string similar to Metadata. 326 | /// 327 | internal static string MetaData { 328 | get { 329 | return ResourceManager.GetString("MetaData", resourceCulture); 330 | } 331 | } 332 | 333 | /// 334 | /// Looks up a localized string similar to No Property Shown. 335 | /// 336 | internal static string NoPropertyShown { 337 | get { 338 | return ResourceManager.GetString("NoPropertyShown", resourceCulture); 339 | } 340 | } 341 | 342 | /// 343 | /// Looks up a localized string similar to Painter. 344 | /// 345 | internal static string Painter { 346 | get { 347 | return ResourceManager.GetString("Painter", resourceCulture); 348 | } 349 | } 350 | 351 | /// 352 | /// Looks up a localized string similar to Painting Mode Control. 353 | /// 354 | internal static string PaintingModeControl { 355 | get { 356 | return ResourceManager.GetString("PaintingModeControl", resourceCulture); 357 | } 358 | } 359 | 360 | /// 361 | /// Looks up a localized string similar to Parallel Symmetry. 362 | /// 363 | internal static string ParallelSymmetry { 364 | get { 365 | return ResourceManager.GetString("ParallelSymmetry", resourceCulture); 366 | } 367 | } 368 | 369 | /// 370 | /// Looks up a localized string similar to Point. 371 | /// 372 | internal static string Point { 373 | get { 374 | return ResourceManager.GetString("Point", resourceCulture); 375 | } 376 | } 377 | 378 | /// 379 | /// Looks up a localized string similar to Pointer. 380 | /// 381 | internal static string Pointer { 382 | get { 383 | return ResourceManager.GetString("Pointer", resourceCulture); 384 | } 385 | } 386 | 387 | /// 388 | /// Looks up a localized string similar to Puzzle Title. 389 | /// 390 | internal static string PuzzleTitle { 391 | get { 392 | return ResourceManager.GetString("PuzzleTitle", resourceCulture); 393 | } 394 | } 395 | 396 | /// 397 | /// Looks up a localized string similar to Redo. 398 | /// 399 | internal static string Redo { 400 | get { 401 | return ResourceManager.GetString("Redo", resourceCulture); 402 | } 403 | } 404 | 405 | /// 406 | /// Looks up a localized string similar to Ring. 407 | /// 408 | internal static string Ring { 409 | get { 410 | return ResourceManager.GetString("Ring", resourceCulture); 411 | } 412 | } 413 | 414 | /// 415 | /// Looks up a localized string similar to Rotational Symmetry. 416 | /// 417 | internal static string RotationalSymmetry { 418 | get { 419 | return ResourceManager.GetString("RotationalSymmetry", resourceCulture); 420 | } 421 | } 422 | 423 | /// 424 | /// Looks up a localized string similar to Self Intersection. 425 | /// 426 | internal static string SelfIntersection { 427 | get { 428 | return ResourceManager.GetString("SelfIntersection", resourceCulture); 429 | } 430 | } 431 | 432 | /// 433 | /// Looks up a localized string similar to Skew Hollow Tetris. 434 | /// 435 | internal static string SkewHollowTetris { 436 | get { 437 | return ResourceManager.GetString("SkewHollowTetris", resourceCulture); 438 | } 439 | } 440 | 441 | /// 442 | /// Looks up a localized string similar to Skew Tetris. 443 | /// 444 | internal static string SkewTetris { 445 | get { 446 | return ResourceManager.GetString("SkewTetris", resourceCulture); 447 | } 448 | } 449 | 450 | /// 451 | /// Looks up a localized string similar to Square. 452 | /// 453 | internal static string Square { 454 | get { 455 | return ResourceManager.GetString("Square", resourceCulture); 456 | } 457 | } 458 | 459 | /// 460 | /// Looks up a localized string similar to Star. 461 | /// 462 | internal static string Star { 463 | get { 464 | return ResourceManager.GetString("Star", resourceCulture); 465 | } 466 | } 467 | 468 | /// 469 | /// Looks up a localized string similar to Start. 470 | /// 471 | internal static string Start { 472 | get { 473 | return ResourceManager.GetString("Start", resourceCulture); 474 | } 475 | } 476 | 477 | /// 478 | /// Looks up a localized string similar to Symbol. 479 | /// 480 | internal static string Symbol { 481 | get { 482 | return ResourceManager.GetString("Symbol", resourceCulture); 483 | } 484 | } 485 | 486 | /// 487 | /// Looks up a localized string similar to Tetris. 488 | /// 489 | internal static string Tetris { 490 | get { 491 | return ResourceManager.GetString("Tetris", resourceCulture); 492 | } 493 | } 494 | 495 | /// 496 | /// Looks up a localized string similar to Text. 497 | /// 498 | internal static string Text { 499 | get { 500 | return ResourceManager.GetString("Text", resourceCulture); 501 | } 502 | } 503 | 504 | /// 505 | /// Looks up a localized string similar to Three-way Symmetry. 506 | /// 507 | internal static string ThreeWaySymmetry { 508 | get { 509 | return ResourceManager.GetString("ThreeWaySymmetry", resourceCulture); 510 | } 511 | } 512 | 513 | /// 514 | /// Looks up a localized string similar to Triangle 1. 515 | /// 516 | internal static string Triangle1 { 517 | get { 518 | return ResourceManager.GetString("Triangle1", resourceCulture); 519 | } 520 | } 521 | 522 | /// 523 | /// Looks up a localized string similar to Triangle 2. 524 | /// 525 | internal static string Triangle2 { 526 | get { 527 | return ResourceManager.GetString("Triangle2", resourceCulture); 528 | } 529 | } 530 | 531 | /// 532 | /// Looks up a localized string similar to Triangle 3. 533 | /// 534 | internal static string Triangle3 { 535 | get { 536 | return ResourceManager.GetString("Triangle3", resourceCulture); 537 | } 538 | } 539 | 540 | /// 541 | /// Looks up a localized string similar to Triangle 4. 542 | /// 543 | internal static string Triangle4 { 544 | get { 545 | return ResourceManager.GetString("Triangle4", resourceCulture); 546 | } 547 | } 548 | 549 | /// 550 | /// Looks up a localized string similar to Triangle 5. 551 | /// 552 | internal static string Triangle5 { 553 | get { 554 | return ResourceManager.GetString("Triangle5", resourceCulture); 555 | } 556 | } 557 | 558 | /// 559 | /// Looks up a localized string similar to Undo. 560 | /// 561 | internal static string Undo { 562 | get { 563 | return ResourceManager.GetString("Undo", resourceCulture); 564 | } 565 | } 566 | 567 | /// 568 | /// Looks up a localized string similar to Paint {0} with {1}.. 569 | /// 570 | internal static string Undo_Paint { 571 | get { 572 | return ResourceManager.GetString("Undo.Paint", resourceCulture); 573 | } 574 | } 575 | 576 | /// 577 | /// Looks up a localized string similar to Vertical Symmetry. 578 | /// 579 | internal static string VerticalSymmetry { 580 | get { 581 | return ResourceManager.GetString("VerticalSymmetry", resourceCulture); 582 | } 583 | } 584 | 585 | /// 586 | /// Looks up a localized string similar to Warning. 587 | /// 588 | internal static string Warning { 589 | get { 590 | return ResourceManager.GetString("Warning", resourceCulture); 591 | } 592 | } 593 | 594 | /// 595 | /// Looks up a localized string similar to [Warning] Corrupted Toolkit. Click YES to create a new one.. 596 | /// 597 | internal static string Warnings_CorruptedToolkit { 598 | get { 599 | return ResourceManager.GetString("Warnings.CorruptedToolkit", resourceCulture); 600 | } 601 | } 602 | 603 | /// 604 | /// Looks up a localized string similar to [Warning] Failed to load . 605 | /// 606 | internal static string Warnings_FailToLoad { 607 | get { 608 | return ResourceManager.GetString("Warnings.FailToLoad", resourceCulture); 609 | } 610 | } 611 | } 612 | } 613 | -------------------------------------------------------------------------------- /WitnessVisualizer/Resources/Lang.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Arrow 122 | 123 | 124 | Box 125 | 126 | 127 | Broken 128 | 129 | 130 | Circle 131 | 132 | 133 | DeltaX 134 | 135 | 136 | DeltaY 137 | 138 | 139 | Eliminator 140 | 141 | 142 | Emoji 143 | 144 | 145 | Empty 146 | 147 | 148 | EndD 149 | 150 | 151 | EndL 152 | 153 | 154 | EndR 155 | 156 | 157 | EndU 158 | 159 | 160 | [Error] Please name the object using the text box. 161 | 162 | 163 | [Error] Please select an edge first. 164 | 165 | 166 | [Error] Please select at least an element first. 167 | 168 | 169 | [Error] Please select at least an tetris element first. 170 | 171 | 172 | ExtraScale 173 | 174 | 175 | Hint 176 | 177 | 178 | Hollow Tetris 179 | 180 | 181 | Horizontal Symmetry 182 | 183 | 184 | Added {0} Items. 185 | 186 | 187 | Please (use Ctrl) to select two decorations to combine them. 188 | 189 | 190 | Enter the angle (clockwise) in degrees: 191 | 192 | 193 | Enter the scale factor of X: 194 | 195 | 196 | Enter the scale factor of Y: 197 | 198 | 199 | Please enter a float scale factor (e.g., 2.0 or 0.5). 200 | 201 | 202 | You cannot undo this. 203 | 204 | 205 | Are you sure you want to delete 206 | 207 | 208 | Metadata 209 | 210 | 211 | No Property Shown 212 | 213 | 214 | Painter 215 | 216 | 217 | Painting Mode Control 218 | 219 | 220 | Parallel Symmetry 221 | 222 | 223 | Point 224 | 225 | 226 | Pointer 227 | 228 | 229 | Puzzle Title 230 | 231 | 232 | Redo 233 | 234 | 235 | Ring 236 | 237 | 238 | Rotational Symmetry 239 | 240 | 241 | Self Intersection 242 | 243 | 244 | Skew Hollow Tetris 245 | 246 | 247 | Skew Tetris 248 | 249 | 250 | Square 251 | 252 | 253 | Star 254 | 255 | 256 | Start 257 | 258 | 259 | Symbol 260 | 261 | 262 | Tetris 263 | 264 | 265 | Text 266 | 267 | 268 | Three-way Symmetry 269 | 270 | 271 | Triangle 1 272 | 273 | 274 | Triangle 2 275 | 276 | 277 | Triangle 3 278 | 279 | 280 | Triangle 4 281 | 282 | 283 | Triangle 5 284 | 285 | 286 | Undo 287 | 288 | 289 | Paint {0} with {1}. 290 | 291 | 292 | Vertical Symmetry 293 | 294 | 295 | Warning 296 | 297 | 298 | [Warning] Corrupted Toolkit. Click YES to create a new one. 299 | 300 | 301 | [Warning] Failed to load 302 | 303 | -------------------------------------------------------------------------------- /WitnessVisualizer/Resources/Lang.zh-CN.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 箭头 122 | 123 | 124 | 板条箱 125 | 126 | 127 | 断路 128 | 129 | 130 | 圆圈 131 | 132 | 133 | 抗体 134 | 135 | 136 | 表情 137 | 138 | 139 | 空白 140 | 141 | 142 | 终点下 143 | 144 | 145 | 终点左 146 | 147 | 148 | 终点右 149 | 150 | 151 | 终点上 152 | 153 | 154 | [错误] 请用文本框键入物体的名字。 155 | 156 | 157 | [错误] 请先选择一条边。 158 | 159 | 160 | [错误] 请至少选择一个元素。 161 | 162 | 163 | [错误] 请至少选择一个俄罗斯方块元素。 164 | 165 | 166 | 提示 167 | 168 | 169 | 空心俄罗斯方块 170 | 171 | 172 | 横向对称 173 | 174 | 175 | 增加了{0}个项目。 176 | 177 | 178 | 请用Ctrl键选两个装饰元素后再合并它们 179 | 180 | 181 | 请输入旋转度数(顺时针): 182 | 183 | 184 | 请输入一个浮点数来表示缩放尺寸(如0.5或2.0)。 185 | 186 | 187 | 该操作无法撤销。 188 | 189 | 190 | 你确定你要删除: 191 | 192 | 193 | 元数据 194 | 195 | 196 | 没有显示属性 197 | 198 | 199 | 染色工具 200 | 201 | 202 | 染色模式控制 203 | 204 | 205 | 平行对称 206 | 207 | 208 | 209 | 210 | 211 | 指针工具 212 | 213 | 214 | 谜题标题 215 | 216 | 217 | 重做 218 | 219 | 220 | 圆环 221 | 222 | 223 | 旋转对称 224 | 225 | 226 | 二重点 227 | 228 | 229 | 空心斜俄罗斯方块 230 | 231 | 232 | 斜俄罗斯方块 233 | 234 | 235 | 色块 236 | 237 | 238 | 星形 239 | 240 | 241 | 起点 242 | 243 | 244 | 符号 245 | 246 | 247 | 俄罗斯方块 248 | 249 | 250 | 文本 251 | 252 | 253 | 三相对称 254 | 255 | 256 | 三角形1 257 | 258 | 259 | 三角形2 260 | 261 | 262 | 三角形3 263 | 264 | 265 | 三角形4 266 | 267 | 268 | 三角形5 269 | 270 | 271 | 取消 272 | 273 | 274 | 把{0}染色为{1}。 275 | 276 | 277 | 应用装饰元素 278 | 279 | 280 | 清除装饰元素 281 | 282 | 283 | 合并装饰元素 284 | 285 | 286 | 增加网格元素 287 | 288 | 289 | 删除网格元素 290 | 291 | 292 | 绘制正多边形 293 | 294 | 295 | 水平翻转 296 | 297 | 298 | 垂直翻转 299 | 300 | 301 | 翻转X/Y轴 302 | 303 | 304 | 重新生成俄罗斯方块模板 305 | 306 | 307 | 移除装饰元素 308 | 309 | 310 | 旋转图结构 311 | 312 | 313 | 俄罗斯方块装饰元素 314 | 315 | 316 | 纵向对称 317 | 318 | 319 | 警告 320 | 321 | 322 | [警告] 工具箱损坏。点击“是”来创建一个新的。 323 | 324 | 325 | [警告] 加载不成功: 326 | 327 | -------------------------------------------------------------------------------- /WitnessVisualizer/Templates/README.txt: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /WitnessVisualizer/TetrisTemplateRenderer.cs: -------------------------------------------------------------------------------- 1 | using MathHelper; 2 | using PuzzleGraph; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace WitnessVisualizer 11 | { 12 | class TetrisTemplateRenderer 13 | { 14 | Graphics graphics; 15 | double borderPercent = 0.1; 16 | public TetrisTemplateRenderer(Graphics inputGraphics) 17 | { 18 | graphics = inputGraphics; 19 | } 20 | public void Draw(EditView view) 21 | { 22 | Graph graph = view.Graph; 23 | TetrisTemplate template = graph.MetaData.TetrisTemplate; 24 | double scale = view.TetrisTemplateScale; 25 | Vector origin = view.TetrisTemplateOrigin; 26 | graphics.Clear(graph.MetaData.BackgroundColor); 27 | if (template.Shapes.Count == 0) 28 | return; 29 | using (Brush activatedBrush = new SolidBrush(Color.Yellow), deactivatedBrush = new SolidBrush(graph.MetaData.ForegroundColor)) 30 | { 31 | for (int k = 0; k < template.Shapes.Count; ++k) 32 | { 33 | List shape = template.Shapes[k]; 34 | graphics.FillClosedCurve(view.SelectedTetrisShapes[k] ? activatedBrush : deactivatedBrush, 35 | shape.Select(node => new Vector(node.X, node.Y).MapToScreen(scale, origin).ToPoint()).ToArray(), 36 | System.Drawing.Drawing2D.FillMode.Alternate, 0.0f); 37 | } 38 | } 39 | float penWidth = (float)(borderPercent * scale); 40 | using (Pen pen = new Pen(graph.MetaData.BackgroundColor, penWidth )) 41 | { 42 | for (int k = 0; k < template.Shapes.Count; ++k) 43 | { 44 | List shape = template.Shapes[k]; 45 | graphics.DrawClosedCurve(pen, 46 | shape.Select(node => new Vector(node.X, node.Y).MapToScreen(scale, origin).ToPoint()).ToArray(), 47 | 0.0f, System.Drawing.Drawing2D.FillMode.Alternate); 48 | } 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /WitnessVisualizer/TetrisTransferHelper.cs: -------------------------------------------------------------------------------- 1 | using PuzzleGraph; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace WitnessVisualizer 9 | { 10 | class TetrisTransferHelper 11 | { 12 | private const double EPS = 1e-6; 13 | private static bool ShapeCompatible(List shape1, List shape2) 14 | { 15 | if (shape1.Count != shape2.Count) return false; 16 | for(int i=0;i EPS || p2.X - p1.X > EPS) return false; 20 | if (p1.Y - p2.Y > EPS || p2.Y - p1.Y > EPS) return false; 21 | } 22 | return true; 23 | } 24 | public static bool TetrisCompatible(Graph graph, List indexes, List> shapes) 25 | { 26 | if (indexes.Count != shapes.Count) return false; 27 | TetrisTemplate template = graph.MetaData.TetrisTemplate; 28 | for (int i = 0; i < indexes.Count; ++i) 29 | { 30 | int index = indexes[i]; 31 | if (index >= template.Shapes.Count) return false; 32 | if (!ShapeCompatible(template.Shapes[index], shapes[i])) return false; 33 | } 34 | return true; 35 | } 36 | public static bool TetrisCompatible(Graph graph, Decorator decorator) 37 | { 38 | if (decorator is PuzzleGraph.Decorators.AbstractTetrisDecorator tetris) 39 | { 40 | return TetrisCompatible(graph, tetris.Indexes, tetris.Shapes); 41 | } 42 | else return false; 43 | } 44 | 45 | internal static void ClearTetrisIndex(Decorator decorator) 46 | { 47 | if (decorator is PuzzleGraph.Decorators.AbstractTetrisDecorator tetris) 48 | { 49 | tetris.Indexes = new List(); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /WitnessVisualizer/Toolkit/README.txt: -------------------------------------------------------------------------------- 1 | This is the toolkit layout folder. -------------------------------------------------------------------------------- /WitnessVisualizer/WitnessVisualizer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1BC3CF7A-223A-4FF4-9ADA-CBE66BBCBA49} 8 | WinExe 9 | WitnessVisualizer 10 | WitnessVisualizer 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | 18 | publish\ 19 | true 20 | Disk 21 | false 22 | Foreground 23 | 7 24 | Days 25 | false 26 | false 27 | true 28 | 0 29 | 1.0.0.%2a 30 | false 31 | false 32 | true 33 | 34 | 35 | AnyCPU 36 | true 37 | full 38 | false 39 | bin\Debug\ 40 | DEBUG;TRACE 41 | prompt 42 | 4 43 | 44 | 45 | AnyCPU 46 | pdbonly 47 | true 48 | bin\Release\ 49 | TRACE 50 | prompt 51 | 4 52 | 53 | 54 | designer2.ico 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | Form 78 | 79 | 80 | MainForm.cs 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | True 94 | True 95 | Lang.resx 96 | 97 | 98 | 99 | 100 | MainForm.cs 101 | 102 | 103 | MainForm.cs 104 | 105 | 106 | ResXFileCodeGenerator 107 | Resources.Designer.cs 108 | Designer 109 | 110 | 111 | True 112 | Resources.resx 113 | True 114 | 115 | 116 | ResXFileCodeGenerator 117 | Lang.Designer.cs 118 | 119 | 120 | 121 | 122 | SettingsSingleFileGenerator 123 | Settings.Designer.cs 124 | 125 | 126 | True 127 | Settings.settings 128 | True 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | {C64B9CF7-F436-4296-AD96-54BAE4B7EB5F} 137 | MathHelper 138 | 139 | 140 | {e3452841-69be-4ec8-90d3-8ec07758d230} 141 | PuzzleGraph 142 | 143 | 144 | 145 | 146 | 147 | 148 | Always 149 | 150 | 151 | Always 152 | 153 | 154 | Always 155 | 156 | 157 | Always 158 | 159 | 160 | Always 161 | 162 | 163 | Always 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | False 172 | Microsoft .NET Framework 4.7.2 %28x86 和 x64%29 173 | true 174 | 175 | 176 | False 177 | .NET Framework 3.5 SP1 178 | false 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /WitnessVisualizer/designer.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instr3/WitnessVisualizer/158f7f4535309879dda782d024ad2bd5dd062810/WitnessVisualizer/designer.ico -------------------------------------------------------------------------------- /WitnessVisualizer/designer2.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/instr3/WitnessVisualizer/158f7f4535309879dda782d024ad2bd5dd062810/WitnessVisualizer/designer2.ico -------------------------------------------------------------------------------- /WitnessVisualizer/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | --------------------------------------------------------------------------------