├── .gitignore ├── Scenes ├── Materials │ ├── eppz! Geometry Star.png │ ├── eppz! Geometry Winding.png │ ├── eppz! Geometry Star.mat.meta │ ├── eppz! Geometry Solid color.mat.meta │ ├── eppz! Geometry Star.svg.meta │ ├── eppz! Geometry Solid color.shader │ ├── eppz! Geometry Solid color.shader.meta │ ├── eppz! Geometry Vertex color.shader.meta │ ├── eppz! Geometry Winding.mat.meta │ ├── eppz! Geometry Vertex color.mat.meta │ ├── eppz! Geometry Star.mat │ ├── eppz! Geometry Winding.mat │ ├── eppz! Geometry Solid color.mat │ ├── eppz! Geometry Vertex color.mat │ ├── eppz! Geometry Vertex color.shader │ ├── eppz! Geometry Star.png.meta │ ├── eppz! Geometry Winding.png.meta │ └── eppz! Geometry Star.svg ├── 0. Polygon-point containment.unity.meta ├── Controllers.meta ├── Materials.meta ├── README.md.meta ├── 6. Vertex facing.unity.meta ├── 9. Polygon offset.unity.meta ├── 1. Polygon-Segment intersection.unity.meta ├── 10. Multiple polygon centroid.unity.meta ├── 11. Polygon triangulation (1).unity.meta ├── 11. Polygon triangulation (2).unity.meta ├── 4. Polygon-Segment containment.unity.meta ├── 7. Polygon area, Polygon winding.unity.meta ├── 5. Polygon-Polygon containment (1).unity.meta ├── 5. Polygon-Polygon containment (2).unity.meta ├── 8. Segment-Segment intersection point.unity.meta ├── Animations.meta ├── 2. Polygon permiter-Point containment (Precise).unity.meta ├── 3. Polygon permiter-Point containment (Default).unity.meta ├── Animations │ ├── eppz! Geometry Drift.anim.meta │ ├── eppz! Geometry Spin.anim.meta │ └── eppz! Geometry Drift.anim ├── Controllers │ ├── Controller_0.cs.meta │ ├── Controller_1.cs.meta │ ├── Controller_2.cs.meta │ ├── Controller_3.cs.meta │ ├── Controller_4.cs.meta │ ├── Controller_5.cs.meta │ ├── Controller_6.cs.meta │ ├── Controller_8.cs.meta │ ├── Controller_9.cs.meta │ ├── Controller_10.cs.meta │ ├── Controller_10.cs │ ├── Controller_9.cs │ ├── Controller_3.cs │ ├── Controller_2.cs │ ├── Controller_0.cs │ ├── Controller_1.cs │ ├── Controller_8.cs │ ├── Controller_4.cs │ ├── Controller_6.cs │ └── Controller_5.cs └── README.md ├── LICENSE.md.meta ├── README.md.meta ├── CHANGELOG.md.meta ├── .gitmodules ├── Lines.meta ├── Model.meta ├── AddOns.meta ├── Clipper.meta ├── Editor.meta ├── Extensions.meta ├── Inspector.meta ├── Scenes.meta ├── Source.meta ├── Triangle.NET.meta ├── Inspector ├── Editor.meta ├── PolygonInspector.cs.meta ├── Editor │ ├── PolygonInspector.cs.meta │ └── PolygonInspector.cs └── PolygonInspector.cs ├── Geometry.cs.meta ├── Model ├── Edge.cs.meta ├── Polygon.cs.meta ├── Segment.cs.meta ├── Vertex.cs.meta ├── Edge.cs ├── Vertex.cs ├── Segment.cs └── Polygon.cs ├── Source ├── Mesh.cs.meta ├── Points.cs.meta ├── Polygon.cs.meta ├── Segment.cs.meta ├── Points.cs ├── Segment.cs ├── Mesh.cs └── Polygon.cs ├── Editor ├── Define.cs.meta └── Define.cs ├── AddOns ├── ClipperAddOns.cs.meta ├── TriangleNetAddOns.cs.meta ├── UnityEngineAddOns.cs.meta ├── ClipperAddOns.cs ├── TriangleNetAddOns.cs └── UnityEngineAddOns.cs ├── Extensions ├── Vector2.cs.meta ├── Vector3.cs.meta ├── Vector3.cs └── Vector2.cs ├── Lines ├── CornerLineRenderer.cs.meta ├── GeometryLineRenderer.cs.meta ├── PolygonLineRenderer.cs.meta ├── SegmentLineRenderer.cs.meta ├── ExtendedPolygonLineRenderer.cs.meta ├── CornerLineRenderer.cs ├── SegmentLineRenderer.cs ├── PolygonLineRenderer.cs ├── ExtendedPolygonLineRenderer.cs └── GeometryLineRenderer.cs ├── LICENSE.md ├── CHANGELOG.md ├── Geometry.cs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ### Ignore meta (OSX) 2 | .DS_Store -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Geri-Borbas/Unity.Library.eppz.Geometry/HEAD/Scenes/Materials/eppz! Geometry Star.png -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Winding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Geri-Borbas/Unity.Library.eppz.Geometry/HEAD/Scenes/Materials/eppz! Geometry Winding.png -------------------------------------------------------------------------------- /Scenes/0. Polygon-point containment.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e02b7c9085e204e069ae845f325553bd 3 | DefaultImporter: 4 | userData: 5 | assetBundleName: 6 | assetBundleVariant: 7 | -------------------------------------------------------------------------------- /Scenes/Controllers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f08989fac9016469caf3821a1d940500 3 | folderAsset: yes 4 | DefaultImporter: 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Scenes/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 080c1a8210ced48ac92f18d29ea5a884 3 | folderAsset: yes 4 | DefaultImporter: 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 06d2f746cf4e440a29cfee71b4a267fd 3 | timeCreated: 1497714734 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 069d45a9676e948c4b1146cc9bccc4a6 3 | timeCreated: 1497713744 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7bc712b87c3914c40a77a0de88362bef 3 | timeCreated: 1497714734 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 570c8868b089a46129e63e831d69c64d 3 | timeCreated: 1497911901 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Star.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5982048bedd05448ea6ebc18c9756e26 3 | NativeFormatImporter: 4 | mainObjectFileID: -1 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Scenes/6. Vertex facing.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d666d571743524056864e011c8f55eca 3 | timeCreated: 1498050921 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/9. Polygon offset.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7e93876e5145a464d95a3e5d2118c6e1 3 | timeCreated: 1498092868 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Solid color.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7c061e9fd66494953b8c6f5e8551732f 3 | NativeFormatImporter: 4 | mainObjectFileID: -1 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Clipper"] 2 | path = Clipper 3 | url = https://github.com/eppz/Clipper 4 | branch = Release 5 | [submodule "Triangle.NET"] 6 | path = Triangle.NET 7 | url = https://github.com/eppz/Triangle.NET 8 | branch = Release 9 | -------------------------------------------------------------------------------- /Lines.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aac3609318e6245b085144952c707182 3 | folderAsset: yes 4 | timeCreated: 1497913169 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Model.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f16e57316bac740f6b1e7f515f82111b 3 | folderAsset: yes 4 | timeCreated: 1497897220 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /AddOns.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1cd35a4304cc444118c93b824de3044d 3 | folderAsset: yes 4 | timeCreated: 1497897220 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Clipper.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 08b837d20ea514f5a9f147319de87281 3 | folderAsset: yes 4 | timeCreated: 1497718686 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6ff1fe5e7ef3e466ba1a2ca31287054b 3 | folderAsset: yes 4 | timeCreated: 1497896207 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Extensions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c0e9b58bb7ce348caab337b9b386c633 3 | folderAsset: yes 4 | timeCreated: 1497896101 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Inspector.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e62a78f31a6fa425eb220d22450f9377 3 | folderAsset: yes 4 | timeCreated: 1498154815 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ba2cc6c3c72734587b55513faba0275d 3 | folderAsset: yes 4 | timeCreated: 1497911901 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Star.svg.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e36a479e39783471e97138414b7a3830 3 | timeCreated: 1498005035 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Source.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0995988883c5f450daad1deb59214d31 3 | folderAsset: yes 4 | timeCreated: 1497897326 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scenes/1. Polygon-Segment intersection.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f926ca1c66e9b4be9a8848d793a7554e 3 | timeCreated: 1498002429 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/10. Multiple polygon centroid.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6e32cb6f5418040009a33168be2f0978 3 | timeCreated: 1498094770 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/11. Polygon triangulation (1).unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4c9eb6241793848bcb16704dfbdc2746 3 | timeCreated: 1498151656 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/11. Polygon triangulation (2).unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f65207aae8b8e4ed8b0793b9281ceed1 3 | timeCreated: 1498263534 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/4. Polygon-Segment containment.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9be22de292def42a89a3428b8d6a1de4 3 | timeCreated: 1498007156 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/7. Polygon area, Polygon winding.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b3875e1adb8e04c4d99f1af1ad2398ac 3 | timeCreated: 1498053405 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Triangle.NET.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 740dfcbf418ec42dfb19dd33879c406a 3 | folderAsset: yes 4 | timeCreated: 1497718686 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Inspector/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f8f2dcc0c620840539ee6d7deac48d40 3 | folderAsset: yes 4 | timeCreated: 1498154874 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scenes/5. Polygon-Polygon containment (1).unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3b6ad0b2719ea446ea5cb62b685306c3 3 | timeCreated: 1498014118 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/5. Polygon-Polygon containment (2).unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4c58e2d7e6b4b437d8a93d933c07de4e 3 | timeCreated: 1498014137 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/8. Segment-Segment intersection point.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a36f809f659b041b581eb9b62a096bc8 3 | timeCreated: 1498083392 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/Animations.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d340b255fb2824c6c808ed07190e3ecf 3 | folderAsset: yes 4 | timeCreated: 1498005378 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Solid color.shader: -------------------------------------------------------------------------------- 1 | Shader "eppz!/Geometry/Solid color" 2 | { 3 | Properties 4 | { 5 | _Color ("Color", Color) = (1,1,1) 6 | } 7 | 8 | SubShader 9 | { 10 | Color [_Color] 11 | Pass {} 12 | } 13 | } -------------------------------------------------------------------------------- /Scenes/2. Polygon permiter-Point containment (Precise).unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d7885f0dcad942b7b8da07ce763aaac 3 | timeCreated: 1498004298 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scenes/3. Polygon permiter-Point containment (Default).unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d945816aa19e84ff18b514562f0ed1fe 3 | timeCreated: 1498012570 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Geometry.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 878b0d44b0b284ac0ab5bc2a5198a424 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Model/Edge.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f8f04e7f419e0481e89a4855c1afe48d 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Model/Polygon.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3024a1cbde06044dcafead4cd24f3951 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Model/Segment.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 578ca8bb78e354a369b7aa397c854195 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Model/Vertex.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bb3b0c75aa3b7408dab5053d6c9a7c70 3 | MonoImporter: 4 | serializedVersion: 2 5 | defaultReferences: [] 6 | executionOrder: 0 7 | icon: {instanceID: 0} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Scenes/Animations/eppz! Geometry Drift.anim.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 18641437c1b9842b88b3cc0ece6343b4 3 | timeCreated: 1498270794 4 | licenseType: Free 5 | NativeFormatImporter: 6 | mainObjectFileID: -1 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scenes/Animations/eppz! Geometry Spin.anim.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d15258d94e7e04b69a168a2ea7249441 3 | timeCreated: 1498005102 4 | licenseType: Free 5 | NativeFormatImporter: 6 | mainObjectFileID: -1 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Solid color.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 624e7bb379bc34ba2a33f5466bf22177 3 | timeCreated: 1497914795 4 | licenseType: Free 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Vertex color.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 648320c5e6aa44cae8e41e668725a60f 3 | timeCreated: 1498156354 4 | licenseType: Free 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Winding.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 489fe84c7d27343df8ab8e6466d2a963 3 | timeCreated: 1498012570 4 | licenseType: Free 5 | NativeFormatImporter: 6 | mainObjectFileID: -1 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Vertex color.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 026668cf8595a4ba98235aeba073174b 3 | timeCreated: 1498156354 4 | licenseType: Free 5 | NativeFormatImporter: 6 | mainObjectFileID: -1 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Source/Mesh.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 860e2ec07f219485599d0781d0dd85f5 3 | timeCreated: 1498168825 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Editor/Define.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0262ffd8508fa49458efb1e8dcca8e85 3 | timeCreated: 1497795889 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Source/Points.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dab07af4868cd4c1d93d8606f38ccc73 3 | timeCreated: 1498268155 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Source/Polygon.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ba7a569d9f84344fd8f559eacf1ceb8b 3 | timeCreated: 1497897326 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Source/Segment.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: da61256570a8c4e098ba98d18e3728d9 3 | timeCreated: 1497897326 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /AddOns/ClipperAddOns.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6803417002d2a4b9c8db703bac12f6ec 3 | timeCreated: 1498134866 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Extensions/Vector2.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 82101dd1a6fa5449ba20dfecd0484231 3 | timeCreated: 1497896101 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Extensions/Vector3.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 39707300bf96649e9a562b8928486e25 3 | timeCreated: 1497896101 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /AddOns/TriangleNetAddOns.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4e1cfae3ee4014ce48283dc0231497e4 3 | timeCreated: 1498140463 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /AddOns/UnityEngineAddOns.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b133bb002ab4a4f95a451607be3b517e 3 | timeCreated: 1498140464 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Inspector/PolygonInspector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a04c8437858394175bf2df9d59dc216e 3 | timeCreated: 1497897326 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Lines/CornerLineRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4b8e8313fc9274e84bd1bc1be293263c 3 | timeCreated: 1474121880 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 1100 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Lines/GeometryLineRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cab55df2272dc47bb9a91830c38acfbf 3 | timeCreated: 1474121879 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 1100 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Lines/PolygonLineRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0b0de8b2d921d454fb29a849a0e578ad 3 | timeCreated: 1474121879 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 1100 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Lines/SegmentLineRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8688db05fd6164131917f90631dc7e52 3 | timeCreated: 1474121881 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 1100 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_0.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 19df9899f9375406dbc2f7e6021a5552 3 | timeCreated: 1497913130 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_1.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 037d000350edf4451ad8e72279aab154 3 | timeCreated: 1498002457 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_2.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 775f7021c685b4387b9058026247cfa9 3 | timeCreated: 1498004299 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_3.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 37357bc0d70d64e1c901063e480484c8 3 | timeCreated: 1498006461 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_4.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 539c44952ae854db1ab253813e36257a 3 | timeCreated: 1498007557 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_5.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7728c220505db4cf4bf7617872e1a3c2 3 | timeCreated: 1498014125 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_6.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5fd993e5dbca24239af8c7c0bd59dc40 3 | timeCreated: 1498050916 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_8.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c98aad19b017941b6baf0e5681732e1b 3 | timeCreated: 1498083402 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_9.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e27d5917dbd284404b61ad95207c5151 3 | timeCreated: 1498092869 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Inspector/Editor/PolygonInspector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 73ccd8c1ccf0e4694a872bc8925d6c61 3 | timeCreated: 1497898474 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Lines/ExtendedPolygonLineRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ac9e1ffc88486455ea813df2ab160865 3 | timeCreated: 1498093951 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 1100 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_10.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fc0b24ddec557433d9c1fc10ea772953 3 | timeCreated: 1498094781 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Star.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: eppz! Geometry Star 10 | m_Shader: {fileID: 30, guid: 0000000000000000f000000000000000, type: 0} 11 | m_ShaderKeywords: 12 | m_LightmapFlags: 5 13 | m_EnableInstancingVariants: 0 14 | m_DoubleSidedGI: 0 15 | m_CustomRenderQueue: -1 16 | stringTagMap: {} 17 | disabledShaderPasses: [] 18 | m_SavedProperties: 19 | serializedVersion: 3 20 | m_TexEnvs: 21 | - _MainTex: 22 | m_Texture: {fileID: 2800000, guid: 643497948b6324a888e28fc3cd1cb964, type: 3} 23 | m_Scale: {x: 1, y: 1} 24 | m_Offset: {x: 0, y: 0} 25 | m_Floats: [] 26 | m_Colors: 27 | - _Color: {r: 1, g: 1, b: 1, a: 1} 28 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Winding.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: eppz! Geometry Winding 10 | m_Shader: {fileID: 30, guid: 0000000000000000f000000000000000, type: 0} 11 | m_ShaderKeywords: 12 | m_LightmapFlags: 5 13 | m_EnableInstancingVariants: 0 14 | m_DoubleSidedGI: 0 15 | m_CustomRenderQueue: -1 16 | stringTagMap: {} 17 | disabledShaderPasses: [] 18 | m_SavedProperties: 19 | serializedVersion: 3 20 | m_TexEnvs: 21 | - _MainTex: 22 | m_Texture: {fileID: 2800000, guid: 9d715ae3a587948808be900f38d3d902, type: 3} 23 | m_Scale: {x: 1, y: 1} 24 | m_Offset: {x: 0, y: 0} 25 | m_Floats: [] 26 | m_Colors: 27 | - _Color: {r: 1, g: 1, b: 1, a: 1} 28 | -------------------------------------------------------------------------------- /Source/Points.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | 6 | namespace EPPZ.Geometry.Source 7 | { 8 | 9 | 10 | /// 11 | /// Utility component to create point transforms from mesh vertices 12 | /// suitable to feed data into `Source.Polygon.points` component. 13 | /// 14 | [ExecuteInEditMode] 15 | public class Points : MonoBehaviour 16 | { 17 | 18 | 19 | public float scale = 0.1f; 20 | 21 | 22 | [ContextMenu("Create")] 23 | void Create() 24 | { 25 | int index = 1; 26 | foreach (Vector3 eachVertex in GetComponent().mesh.vertices) 27 | { 28 | GameObject point = GameObject.CreatePrimitive(PrimitiveType.Sphere); 29 | point.transform.parent = transform; 30 | point.transform.localPosition = eachVertex; 31 | point.transform.localScale = Vector3.one * scale; 32 | point.name = "Point "+index.ToString("00"); 33 | index++; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Geri Borbás 4 | https://twitter.com/_eppz 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Solid color.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: eppz! Geometry Solid color 10 | m_Shader: {fileID: 4800000, guid: 624e7bb379bc34ba2a33f5466bf22177, type: 3} 11 | m_ShaderKeywords: 12 | m_LightmapFlags: 5 13 | m_EnableInstancingVariants: 0 14 | m_DoubleSidedGI: 0 15 | m_CustomRenderQueue: -1 16 | stringTagMap: {} 17 | disabledShaderPasses: [] 18 | m_SavedProperties: 19 | serializedVersion: 3 20 | m_TexEnvs: 21 | - _BumpMap: 22 | m_Texture: {fileID: 0} 23 | m_Scale: {x: 1, y: 1} 24 | m_Offset: {x: 0, y: 0} 25 | - _MainTex: 26 | m_Texture: {fileID: 0} 27 | m_Scale: {x: 1, y: 1} 28 | m_Offset: {x: 0, y: 0} 29 | - _ParallaxMap: 30 | m_Texture: {fileID: 0} 31 | m_Scale: {x: 1, y: 1} 32 | m_Offset: {x: 0, y: 0} 33 | m_Floats: 34 | - _Parallax: 0.02 35 | - _Shininess: 0.01 36 | m_Colors: 37 | - _Color: {r: 0.9843137, g: 0.9843137, b: 0.44313726, a: 1} 38 | - _Emission: {r: 0, g: 0, b: 0, a: 0} 39 | - _SpecColor: {r: 1, g: 1, b: 1, a: 1} 40 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Vertex color.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: eppz! Geometry Vertex color 10 | m_Shader: {fileID: 4800000, guid: 648320c5e6aa44cae8e41e668725a60f, type: 3} 11 | m_ShaderKeywords: 12 | m_LightmapFlags: 5 13 | m_EnableInstancingVariants: 0 14 | m_DoubleSidedGI: 0 15 | m_CustomRenderQueue: -1 16 | stringTagMap: {} 17 | disabledShaderPasses: [] 18 | m_SavedProperties: 19 | serializedVersion: 3 20 | m_TexEnvs: 21 | - _BumpMap: 22 | m_Texture: {fileID: 0} 23 | m_Scale: {x: 1, y: 1} 24 | m_Offset: {x: 0, y: 0} 25 | - _MainTex: 26 | m_Texture: {fileID: 0} 27 | m_Scale: {x: 1, y: 1} 28 | m_Offset: {x: 0, y: 0} 29 | - _ParallaxMap: 30 | m_Texture: {fileID: 0} 31 | m_Scale: {x: 1, y: 1} 32 | m_Offset: {x: 0, y: 0} 33 | m_Floats: 34 | - _Parallax: 0.02 35 | - _Shininess: 0.01 36 | m_Colors: 37 | - _Color: {r: 0.9843137, g: 0.9843137, b: 0.44313726, a: 1} 38 | - _Emission: {r: 0, g: 0, b: 0, a: 0} 39 | - _SpecColor: {r: 1, g: 1, b: 1, a: 1} 40 | -------------------------------------------------------------------------------- /Inspector/PolygonInspector.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Inspector 13 | { 14 | 15 | 16 | public class PolygonInspector : MonoBehaviour 17 | { 18 | 19 | 20 | public Model.Polygon polygon; 21 | public int currentEdgeIndex = 0; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Vertex color.shader: -------------------------------------------------------------------------------- 1 | // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' 2 | 3 | Shader "eppz!/Geometry/Vertex color" 4 | { 5 | 6 | Properties 7 | { } 8 | 9 | 10 | SubShader 11 | { 12 | 13 | 14 | Tags {"Queue" = "Transparent"} 15 | Pass 16 | { 17 | 18 | 19 | Cull Off 20 | Lighting Off 21 | ZWrite Off 22 | ZTest Always 23 | Blend SrcAlpha OneMinusSrcAlpha // Alpha blending 24 | 25 | 26 | CGPROGRAM 27 | 28 | #pragma vertex vert 29 | #pragma fragment frag 30 | #pragma fragmentoption ARB_precision_hint_fastest 31 | #include "UnityCG.cginc" 32 | 33 | 34 | struct vertexInput 35 | { 36 | float4 vertex : POSITION; 37 | float4 color : COLOR; 38 | float4 texcoord : TEXCOORD0; 39 | }; 40 | 41 | struct vertexOutput 42 | { 43 | float4 position : SV_POSITION; 44 | float4 color : COLOR; // Vertex color 45 | float2 uv : TEXCOORD0; 46 | }; 47 | 48 | 49 | vertexOutput vert (vertexInput input) 50 | { 51 | vertexOutput output; 52 | 53 | // Usual projection stuff. 54 | output.position = UnityObjectToClipPos(input.vertex); 55 | output.color = input.color; 56 | output.uv = input.texcoord; 57 | 58 | return output; 59 | } 60 | 61 | half4 frag (vertexOutput input) : COLOR 62 | { 63 | // Color (vertex). 64 | half4 output = input.color; 65 | return output; 66 | } 67 | 68 | 69 | ENDCG 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /Lines/CornerLineRenderer.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | #if EPPZ_LINES 9 | using UnityEngine; 10 | using System.Collections; 11 | 12 | 13 | namespace EPPZ.Geometry.Lines 14 | { 15 | 16 | 17 | using Model; 18 | 19 | 20 | public class CornerLineRenderer : GeometryLineRenderer 21 | { 22 | 23 | 24 | public Color segmentAColor; 25 | public Color segmentBColor; 26 | public Color segmentNormalColor; 27 | 28 | public Segment segmentA; 29 | public Segment segmentB; 30 | public Segment normal; 31 | 32 | 33 | protected override void OnDraw() 34 | { 35 | DrawSegment(segmentA, segmentAColor); 36 | DrawSegment(segmentB, segmentBColor); 37 | DrawSegment(normal, segmentNormalColor); 38 | } 39 | } 40 | } 41 | #endif -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_10.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections.Generic; 10 | 11 | 12 | namespace EPPZ.Geometry.Scenes 13 | { 14 | 15 | 16 | using Model; 17 | using Lines; 18 | 19 | 20 | /// 21 | /// 10. Multiple polygon centroid 22 | /// 23 | public class Controller_10 : MonoBehaviour 24 | { 25 | 26 | public Transform centroid; 27 | public Source.Polygon[] polygonSources; 28 | List polygons = new List(); 29 | 30 | 31 | void Update() 32 | { 33 | // Collect polygons. 34 | polygons.Clear(); 35 | foreach (Source.Polygon eachPolygonSource in polygonSources) 36 | { polygons.Add(eachPolygonSource.polygon); } 37 | 38 | // Calculate compund centroid. 39 | centroid.position = Geometry.CentroidOfPolygons(polygons.ToArray()); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Editor/Define.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using System; 9 | using UnityEngine; 10 | using UnityEditor; 11 | 12 | 13 | namespace EPPZ.Geometry.Editor 14 | { 15 | 16 | 17 | [InitializeOnLoad] 18 | public class Define 19 | { 20 | 21 | 22 | const string define = "EPPZ_GEOMETRY"; 23 | 24 | 25 | static Define() 26 | { AddDefineIfNeeded(); } 27 | 28 | static void AddDefineIfNeeded() 29 | { 30 | BuildTargetGroup buildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup; 31 | string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup); 32 | if (defines.Contains(define)) return; // Change only if needed 33 | PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, (defines + ";" + define)); 34 | Debug.LogWarning(""+define+" added to Scripting Define Symbols for selected build target ("+EditorUserBuildSettings.activeBuildTarget.ToString()+")."); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Extensions/Vector3.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using System; 9 | using UnityEngine; 10 | 11 | 12 | namespace EPPZ.Geometry 13 | { 14 | 15 | 16 | public static class Vector3_Extensions 17 | { 18 | 19 | 20 | public static Vector2 xy(this Vector3 this_) 21 | { 22 | return new UnityEngine.Vector2( this_.x, this_.y); 23 | } 24 | 25 | public static Vector2 xz(this Vector3 this_) 26 | { 27 | return new UnityEngine.Vector2( this_.x, this_.z); 28 | } 29 | 30 | public static Vector2 yz(this Vector3 this_) 31 | { 32 | return new UnityEngine.Vector2( this_.y, this_.z); 33 | } 34 | 35 | public static Vector2 yx(this Vector3 this_) 36 | { 37 | return new UnityEngine.Vector2( this_.y, this_.x); 38 | } 39 | 40 | public static Vector2 zx(this Vector3 this_) 41 | { 42 | return new UnityEngine.Vector2( this_.z, this_.x); 43 | } 44 | 45 | public static Vector2 zy(this Vector3 this_) 46 | { 47 | return new UnityEngine.Vector2( this_.z, this_.y); 48 | } 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Source/Segment.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Source 13 | { 14 | 15 | 16 | using Model; 17 | 18 | 19 | public class Segment : MonoBehaviour 20 | { 21 | 22 | 23 | [UnityEngine.Serialization.FormerlySerializedAs("pointTransforms")] 24 | public Transform[] points; 25 | 26 | public enum UpdateMode { Awake, Update, LateUpdate }; 27 | public UpdateMode update = UpdateMode.Awake; 28 | 29 | public enum Coordinates { World, Local } 30 | public Coordinates coordinates = Coordinates.World; 31 | 32 | public Model.Segment segment; 33 | 34 | 35 | void Awake() 36 | { 37 | segment = Model.Segment.SegmentWithSource(this); 38 | } 39 | 40 | void Update() 41 | { 42 | if (update == UpdateMode.Update) 43 | { UpdateModel(); } 44 | } 45 | 46 | void LateUpdate() 47 | { 48 | if (update == UpdateMode.LateUpdate) 49 | { UpdateModel(); } 50 | } 51 | 52 | void UpdateModel() 53 | { 54 | segment.UpdateWithSource(this); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Lines/SegmentLineRenderer.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | #if EPPZ_LINES 9 | using UnityEngine; 10 | using System.Collections; 11 | 12 | 13 | namespace EPPZ.Geometry.Lines 14 | { 15 | 16 | 17 | using EPPZ.Lines; 18 | using Model; 19 | 20 | 21 | public class SegmentLineRenderer : GeometryLineRenderer 22 | { 23 | 24 | 25 | public Color lineColor; 26 | public Color boundsColor; 27 | public bool normals = false; 28 | 29 | Segment segment; 30 | Source.Segment segmentSource; 31 | 32 | void Start() 33 | { 34 | // Model reference. 35 | segmentSource = GetComponent(); 36 | segment = segmentSource.segment; 37 | } 38 | 39 | protected override void OnDraw() 40 | { 41 | if (segmentSource.coordinates == Source.Segment.Coordinates.World) 42 | { 43 | DrawRect(segment.bounds, boundsColor); 44 | DrawSegment(segment, lineColor, normals); 45 | } 46 | else 47 | { 48 | DrawRectWithTransform(segment.bounds, boundsColor, this.transform); 49 | DrawSegmentWithTransform(segment, lineColor, this.transform, normals); 50 | } 51 | } 52 | } 53 | } 54 | #endif -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_9.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Scenes 13 | { 14 | 15 | 16 | using Lines; 17 | using Model; 18 | using Inspector; 19 | 20 | 21 | /// 22 | /// 9. Polygon offset 23 | /// 24 | public class Controller_9 : MonoBehaviour 25 | { 26 | 27 | 28 | [Range(0,2)] public float offset = 0.2f; 29 | 30 | public Source.Polygon polygonSource; 31 | public PolygonLineRenderer offsetPolygonRenderer; 32 | 33 | private Polygon offsetPolygon; 34 | private Polygon polygon { get { return polygonSource.polygon; } } 35 | 36 | public PolygonInspector polygonInspector; 37 | public PolygonInspector offsetPolygonInspector; 38 | 39 | 40 | void Start() 41 | { 42 | // Debug. 43 | polygonInspector.polygon = polygonSource.polygon; 44 | } 45 | 46 | void Update() 47 | { 48 | offsetPolygon = polygon.OffsetPolygon(offset); 49 | 50 | // Render. 51 | offsetPolygonRenderer.polygon = offsetPolygon; 52 | 53 | // Debug. 54 | offsetPolygonInspector.polygon = offsetPolygon; 55 | } 56 | } 57 | } 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_3.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Scenes 13 | { 14 | 15 | 16 | using Lines; 17 | using Model; 18 | 19 | 20 | /// 21 | /// 3. Polygon permiter-Point containment (Default) 22 | /// 23 | public class Controller_3 : MonoBehaviour 24 | { 25 | 26 | 27 | public Color defaultColor; 28 | public Color passingColor; 29 | 30 | public Source.Polygon polygonSource; 31 | public GameObject pointSource; 32 | public PolygonLineRenderer polygonRenderer; 33 | 34 | private Polygon polygon { get { return polygonSource.polygon; } } 35 | private Vector2 point { get { return pointSource.transform.position.xy(); } } 36 | 37 | 38 | void Update() 39 | { RenderTestResult(PointContainmentTest()); } 40 | 41 | bool PointContainmentTest() 42 | { 43 | float accuracy = 0.1f; 44 | return polygon.PermiterContainsPoint(point, accuracy); 45 | } 46 | 47 | void RenderTestResult(bool testResult) 48 | { 49 | Color color = (testResult) ? passingColor : defaultColor; 50 | 51 | // Layout colors. 52 | polygonRenderer.lineColor = color; 53 | pointSource.GetComponent().material.color = color; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Lines/PolygonLineRenderer.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | #if EPPZ_LINES 9 | using UnityEngine; 10 | using System.Collections; 11 | 12 | 13 | namespace EPPZ.Geometry.Lines 14 | { 15 | 16 | 17 | using Model; 18 | 19 | 20 | public class PolygonLineRenderer : GeometryLineRenderer 21 | { 22 | 23 | 24 | public Color lineColor; 25 | public Color boundsColor; 26 | public bool normals = false; 27 | 28 | public Polygon polygon; 29 | Source.Polygon polygonSource; 30 | 31 | 32 | void Start() 33 | { 34 | // Model reference. 35 | polygonSource = GetComponent(); 36 | 37 | if (polygonSource != null) 38 | { polygon = polygonSource.polygon; } 39 | } 40 | 41 | protected override void OnDraw() 42 | { 43 | if (polygonSource != null) 44 | { polygon = polygonSource.polygon; } 45 | 46 | if (polygon == null) return; // Only having polygon 47 | 48 | if (polygonSource.coordinates == Source.Polygon.Coordinates.World) 49 | { 50 | DrawRect(polygon.bounds, boundsColor); 51 | DrawPolygon(polygon, lineColor, normals); 52 | } 53 | else 54 | { 55 | DrawRectWithTransform(polygon.bounds, boundsColor, this.transform); 56 | DrawPolygonWithTransform(polygon, lineColor, this.transform, normals); 57 | } 58 | } 59 | } 60 | } 61 | #endif -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_2.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Scenes 13 | { 14 | 15 | 16 | using Lines; 17 | using Model; 18 | 19 | 20 | /// 21 | /// 2. Polygon permiter-Point containment (precise) 22 | /// 23 | public class Controller_2 : MonoBehaviour 24 | { 25 | 26 | 27 | public Color defaultColor; 28 | public Color passingColor; 29 | 30 | public float accuracy = 1.0f; 31 | private float _previousAccuracy; 32 | 33 | public Source.Polygon polygonSource; 34 | public GameObject pointSource; 35 | public PolygonLineRenderer polygonRenderer; 36 | 37 | private Polygon polygon { get { return polygonSource.polygon; } } 38 | private Vector2 point { get { return pointSource.transform.position.xy(); } } 39 | 40 | 41 | void Update() 42 | { RenderTestResult(PointContainmentTest()); } 43 | 44 | bool PointContainmentTest() 45 | { 46 | return polygon.PermiterContainsPoint(point, accuracy, Segment.ContainmentMethod.Precise); 47 | } 48 | 49 | void RenderTestResult(bool testResult) 50 | { 51 | Color color = (testResult) ? passingColor : defaultColor; 52 | 53 | // Layout colors. 54 | polygonRenderer.lineColor = color; 55 | pointSource.GetComponent().material.color = color; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_0.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Scenes 13 | { 14 | 15 | 16 | using Lines; 17 | using Model; 18 | 19 | 20 | /// 21 | /// 0. Polygon-Point containment 22 | /// 23 | public class Controller_0 : MonoBehaviour 24 | { 25 | 26 | 27 | public Color defaultColor; 28 | public Color passingColor; 29 | 30 | public Source.Polygon polygonSource; 31 | public GameObject[] pointObjects; 32 | public PolygonLineRenderer polygonRenderer; 33 | 34 | Polygon polygon { get { return polygonSource.polygon; } } 35 | 36 | 37 | void Update() 38 | { RenderTestResult(PointContainmentTest()); } 39 | 40 | bool PointContainmentTest() 41 | { 42 | bool containsAllPoints = true; 43 | foreach (GameObject eachPointObject in pointObjects) 44 | { 45 | Vector2 eachPoint = eachPointObject.transform.position.xy(); 46 | containsAllPoints &= polygon.ContainsPoint(eachPoint); 47 | } 48 | return containsAllPoints; 49 | } 50 | 51 | void RenderTestResult(bool testResult) 52 | { 53 | Color color = (testResult) ? passingColor : defaultColor; 54 | 55 | // Layout colors. 56 | polygonRenderer.lineColor = color; 57 | foreach (GameObject eachPointObject in pointObjects) 58 | { eachPointObject.GetComponent().material.color = color; } 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_1.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Scenes 13 | { 14 | 15 | 16 | using Lines; 17 | 18 | 19 | /// 20 | /// 1. Polygon-Segment intersection 21 | /// 22 | public class Controller_1 : MonoBehaviour 23 | { 24 | 25 | 26 | public Color defaultColor; 27 | public Color passingColor; 28 | 29 | public Source.Polygon polygonSource; 30 | public Source.Segment segmentSourceA; 31 | public Source.Segment segmentSourceB; 32 | public PolygonLineRenderer polygonRenderer; 33 | public SegmentLineRenderer segmentRendererA; 34 | public SegmentLineRenderer segmentRendererB; 35 | 36 | private Model.Polygon polygon { get { return polygonSource.polygon; } } 37 | private Model.Segment segment_a { get { return segmentSourceA.segment; } } 38 | private Model.Segment segment_b { get { return segmentSourceB.segment; } } 39 | 40 | 41 | void Update() 42 | { RenderTestResult(SegmentIntersectingTest()); } 43 | 44 | bool SegmentIntersectingTest() 45 | { 46 | return ( 47 | polygon.IsIntersectingWithSegment(segment_a) || 48 | polygon.IsIntersectingWithSegment(segment_b) 49 | ); 50 | } 51 | 52 | void RenderTestResult(bool testResult) 53 | { 54 | Color color = (testResult) ? passingColor : defaultColor; 55 | 56 | // Layout colors. 57 | polygonRenderer.lineColor = color; 58 | segmentRendererA.lineColor = color; 59 | segmentRendererB.lineColor = color; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Extensions/Vector2.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using System; 9 | using UnityEngine; 10 | 11 | 12 | namespace EPPZ.Geometry 13 | { 14 | 15 | 16 | public static class Vector2_Extensions 17 | { 18 | 19 | 20 | public static Vector2 Rotated(this Vector2 this_, float degrees) 21 | { 22 | // Checks. 23 | float radians = degrees * Mathf.Deg2Rad; 24 | if (radians == 0.0f) return this_; 25 | if (radians == (Mathf.PI * 2.0f)) return this_; 26 | 27 | float sin = Mathf.Sin(radians); 28 | float cos = Mathf.Cos(radians); 29 | 30 | Vector2 rotated = new Vector2( 31 | (cos * this_.x) - (sin * this_.y), 32 | (sin * this_.x) + (cos * this_.y) 33 | ); 34 | 35 | return rotated; 36 | } 37 | 38 | public static Vector2 RotatedAround(this Vector2 this_, Vector2 around, float degrees) 39 | { 40 | // Checks. 41 | float radians = degrees * Mathf.Deg2Rad; 42 | if (radians == 0.0f) return this_; 43 | if (radians == (Mathf.PI * 2.0f)) return this_; 44 | 45 | Vector2 τposition = this_ - around; 46 | τposition = τposition.Rotated(degrees); 47 | τposition = around + τposition; 48 | 49 | return τposition; 50 | } 51 | 52 | public static float AngleTo(this Vector2 this_, Vector3 to) 53 | { return this_.AngleTo((Vector2)to); } 54 | 55 | public static float AngleTo(this Vector2 this_, Vector2 to) 56 | { 57 | Vector2 direction = to - this_; 58 | float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; 59 | if (angle < 0.0f) angle += 360.0f; 60 | return angle; 61 | } 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Star.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 643497948b6324a888e28fc3cd1cb964 3 | timeCreated: 1498004404 4 | licenseType: Free 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 1 11 | sRGBTexture: 1 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapsPreserveCoverage: 0 16 | alphaTestReferenceValue: 0.5 17 | mipMapFadeDistanceStart: 1 18 | mipMapFadeDistanceEnd: 3 19 | bumpmap: 20 | convertToNormalMap: 0 21 | externalNormalMap: 0 22 | heightScale: 0.25 23 | normalMapFilter: 0 24 | isReadable: 0 25 | grayScaleToAlpha: 0 26 | generateCubemap: 6 27 | cubemapConvolution: 0 28 | seamlessCubemap: 0 29 | textureFormat: 1 30 | maxTextureSize: 2048 31 | textureSettings: 32 | serializedVersion: 2 33 | filterMode: -1 34 | aniso: -1 35 | mipBias: -1 36 | wrapU: -1 37 | wrapV: -1 38 | wrapW: -1 39 | nPOTScale: 1 40 | lightmap: 0 41 | compressionQuality: 50 42 | spriteMode: 0 43 | spriteExtrude: 1 44 | spriteMeshType: 1 45 | alignment: 0 46 | spritePivot: {x: 0.5, y: 0.5} 47 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 48 | spritePixelsToUnits: 100 49 | alphaUsage: 1 50 | alphaIsTransparency: 1 51 | spriteTessellationDetail: -1 52 | textureType: 0 53 | textureShape: 1 54 | maxTextureSizeSet: 0 55 | compressionQualitySet: 0 56 | textureFormatSet: 0 57 | platformSettings: 58 | - buildTarget: DefaultTexturePlatform 59 | maxTextureSize: 2048 60 | textureFormat: -1 61 | textureCompression: 1 62 | compressionQuality: 50 63 | crunchedCompression: 0 64 | allowsAlphaSplitting: 0 65 | overridden: 0 66 | - buildTarget: Standalone 67 | maxTextureSize: 2048 68 | textureFormat: -1 69 | textureCompression: 1 70 | compressionQuality: 50 71 | crunchedCompression: 0 72 | allowsAlphaSplitting: 0 73 | overridden: 0 74 | - buildTarget: iPhone 75 | maxTextureSize: 2048 76 | textureFormat: -1 77 | textureCompression: 1 78 | compressionQuality: 50 79 | crunchedCompression: 0 80 | allowsAlphaSplitting: 0 81 | overridden: 0 82 | - buildTarget: Android 83 | maxTextureSize: 2048 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | spriteSheet: 91 | serializedVersion: 2 92 | sprites: [] 93 | outline: [] 94 | physicsShape: [] 95 | spritePackingTag: 96 | userData: 97 | assetBundleName: 98 | assetBundleVariant: 99 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Winding.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d715ae3a587948808be900f38d3d902 3 | timeCreated: 1498012570 4 | licenseType: Free 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 1 11 | sRGBTexture: 1 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapsPreserveCoverage: 0 16 | alphaTestReferenceValue: 0.5 17 | mipMapFadeDistanceStart: 1 18 | mipMapFadeDistanceEnd: 3 19 | bumpmap: 20 | convertToNormalMap: 0 21 | externalNormalMap: 0 22 | heightScale: 0.25 23 | normalMapFilter: 0 24 | isReadable: 0 25 | grayScaleToAlpha: 0 26 | generateCubemap: 6 27 | cubemapConvolution: 0 28 | seamlessCubemap: 0 29 | textureFormat: 1 30 | maxTextureSize: 2048 31 | textureSettings: 32 | serializedVersion: 2 33 | filterMode: -1 34 | aniso: -1 35 | mipBias: -1 36 | wrapU: -1 37 | wrapV: -1 38 | wrapW: -1 39 | nPOTScale: 1 40 | lightmap: 0 41 | compressionQuality: 50 42 | spriteMode: 0 43 | spriteExtrude: 1 44 | spriteMeshType: 1 45 | alignment: 0 46 | spritePivot: {x: 0.5, y: 0.5} 47 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 48 | spritePixelsToUnits: 100 49 | alphaUsage: 1 50 | alphaIsTransparency: 1 51 | spriteTessellationDetail: -1 52 | textureType: 0 53 | textureShape: 1 54 | maxTextureSizeSet: 0 55 | compressionQualitySet: 0 56 | textureFormatSet: 0 57 | platformSettings: 58 | - buildTarget: DefaultTexturePlatform 59 | maxTextureSize: 2048 60 | textureFormat: -1 61 | textureCompression: 1 62 | compressionQuality: 50 63 | crunchedCompression: 0 64 | allowsAlphaSplitting: 0 65 | overridden: 0 66 | - buildTarget: Standalone 67 | maxTextureSize: 2048 68 | textureFormat: -1 69 | textureCompression: 1 70 | compressionQuality: 50 71 | crunchedCompression: 0 72 | allowsAlphaSplitting: 0 73 | overridden: 0 74 | - buildTarget: iPhone 75 | maxTextureSize: 2048 76 | textureFormat: -1 77 | textureCompression: 1 78 | compressionQuality: 50 79 | crunchedCompression: 0 80 | allowsAlphaSplitting: 0 81 | overridden: 0 82 | - buildTarget: Android 83 | maxTextureSize: 2048 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | spriteSheet: 91 | serializedVersion: 2 92 | sprites: [] 93 | outline: [] 94 | physicsShape: [] 95 | spritePackingTag: 96 | userData: 97 | assetBundleName: 98 | assetBundleVariant: 99 | -------------------------------------------------------------------------------- /Source/Mesh.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | 12 | 13 | namespace EPPZ.Geometry.Source 14 | { 15 | 16 | 17 | using AddOns; 18 | 19 | 20 | public class Mesh : MonoBehaviour 21 | { 22 | 23 | 24 | public TriangulatorType triangulator = TriangulatorType.Dwyer; 25 | public Color color = Color.white; 26 | 27 | public enum UpdateMode { Awake, Update, LateUpdate }; 28 | public UpdateMode update = UpdateMode.Awake; 29 | 30 | Source.Polygon polygonSource; 31 | Model.Polygon polygon; 32 | MeshFilter meshFilter; 33 | 34 | 35 | void Awake() 36 | { 37 | polygonSource = GetComponent(); 38 | meshFilter = GetComponent(); 39 | 40 | if (meshFilter == null) 41 | { 42 | Debug.LogWarning("No MeshFilter component on \""+name+"\" (for PolygonMesh to use as output). Disabled GameObject."); 43 | gameObject.SetActive(false); 44 | } 45 | 46 | if (polygonSource != null) 47 | { polygon = polygonSource.polygon; } 48 | 49 | if (update == UpdateMode.Awake) 50 | { CreateMesh(); } 51 | } 52 | 53 | void Update() 54 | { 55 | if (update == UpdateMode.Update) 56 | { CreateMesh(); } 57 | } 58 | 59 | void LateUpdate() 60 | { 61 | if (update == UpdateMode.LateUpdate) 62 | { CreateMesh(); } 63 | } 64 | 65 | void CreateMesh() 66 | { 67 | if (polygonSource != null) 68 | { polygon = polygonSource.polygon; } 69 | 70 | meshFilter.mesh = polygon.Mesh(color, triangulator); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Source/Polygon.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | using UnityEngine.Serialization; 11 | 12 | 13 | 14 | namespace EPPZ.Geometry.Source 15 | { 16 | 17 | 18 | public class Polygon : MonoBehaviour 19 | { 20 | 21 | 22 | [UnityEngine.Serialization.FormerlySerializedAs("pointTransforms")] 23 | public Transform[] points; 24 | public float offset = 0.0f; 25 | 26 | public enum UpdateMode { Awake, Update, LateUpdate }; 27 | public UpdateMode update = UpdateMode.Awake; 28 | 29 | public enum Coordinates { World, Local } 30 | public Coordinates coordinates = Coordinates.World; 31 | 32 | Model.Polygon _polygon; 33 | Model.Polygon _offsetPolygon; 34 | public Model.Polygon polygon { get { return (offset != 0.0f) ? _offsetPolygon : _polygon; } } 35 | 36 | 37 | void Awake() 38 | { 39 | // Construct a polygon model from transforms (if not created by a root polygon already). 40 | if (_polygon == null) _polygon = Model.Polygon.PolygonWithSource(this); 41 | if (offset != 0.0f) _offsetPolygon = _polygon.OffsetPolygon(offset); 42 | } 43 | 44 | void Update() 45 | { 46 | if (update == UpdateMode.Update) 47 | { UpdateModel(); } 48 | } 49 | 50 | void LateUpdate() 51 | { 52 | if (update == UpdateMode.LateUpdate) 53 | { UpdateModel(); } 54 | } 55 | 56 | void UpdateModel() 57 | { 58 | // Update polygon model with transforms, also update calculations. 59 | _polygon.UpdatePointPositionsWithSource(this); 60 | if (offset != 0.0f) _offsetPolygon = _polygon.OffsetPolygon(offset); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Inspector/Editor/PolygonInspector.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | using UnityEditor; 11 | 12 | 13 | namespace EPPZ.Geometry.Inspector.Editor 14 | { 15 | 16 | 17 | using Model; 18 | 19 | 20 | [CustomEditor(typeof(EPPZ.Geometry.Inspector.PolygonInspector))] 21 | public class PolygonInspector : UnityEditor.Editor 22 | { 23 | 24 | 25 | public override void OnInspectorGUI() 26 | { 27 | // References. 28 | Inspector.PolygonInspector polygonInspector = (Inspector.PolygonInspector)target; 29 | Polygon polygon = polygonInspector.polygon; 30 | if (polygon == null) return; 31 | Edge edge = polygon.edges[polygonInspector.currentEdgeIndex]; 32 | if (edge == null) return; 33 | 34 | if (GUILayout.Button("-")) 35 | { 36 | polygonInspector.currentEdgeIndex = edge.previousEdge.index; 37 | edge = polygon.edges[polygonInspector.currentEdgeIndex]; 38 | 39 | ShowUpEdges(edge); 40 | } 41 | 42 | if (GUILayout.Button("Show up ("+polygonInspector.currentEdgeIndex.ToString()+")")) 43 | { 44 | ShowUpEdges(edge); 45 | } 46 | 47 | if (GUILayout.Button("+")) 48 | { 49 | polygonInspector.currentEdgeIndex = edge.nextEdge.index; 50 | edge = polygon.edges[polygonInspector.currentEdgeIndex]; 51 | 52 | ShowUpEdges(edge); 53 | } 54 | } 55 | 56 | private void ShowUpEdges(Edge edge) 57 | { 58 | Debug.DrawLine(edge.previousEdge.a, edge.previousEdge.b, Color.blue, 1.0f); 59 | Debug.DrawLine(edge.a, edge.b, Color.red, 1.0f); 60 | Debug.DrawLine(edge.nextEdge.a, edge.nextEdge.b, Color.green, 1.0f); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Lines/ExtendedPolygonLineRenderer.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | #if EPPZ_LINES 9 | using UnityEngine; 10 | using System.Collections; 11 | 12 | 13 | namespace EPPZ.Geometry.Lines 14 | { 15 | 16 | 17 | public class ExtendedPolygonLineRenderer : PolygonLineRenderer 18 | { 19 | 20 | 21 | public GameObject windingObject; 22 | public TextMesh areaTextMesh; 23 | 24 | private float _previousArea; 25 | private Model.Polygon.Winding _previousWindingDirection; 26 | 27 | 28 | void Start() 29 | { 30 | // Model reference. 31 | Source.Polygon polygonSource = GetComponent(); 32 | if (polygonSource != null) 33 | { polygon = polygonSource.polygon; } 34 | } 35 | 36 | void Update() 37 | { 38 | if (polygon == null) return; // Only having polygon 39 | 40 | // Layout winding direction object if any. 41 | bool hasWindingDirectionObject = (windingObject != null); 42 | bool windingChanged = (polygon.winding != _previousWindingDirection); 43 | if (hasWindingDirectionObject && windingChanged) 44 | { 45 | windingObject.transform.localScale = (polygon.isCW) ? Vector3.one : new Vector3 (1.0f, -1.0f, 1.0f); 46 | windingObject.transform.rotation = (polygon.isCW) ? Quaternion.identity : Quaternion.Euler( new Vector3 (0.0f, 0.0f, 90.0f) ); 47 | } 48 | 49 | // Layout area text mesh if any. 50 | bool hasAreaTextMesh = (areaTextMesh != null); 51 | bool areaChanged = (polygon.area != _previousArea); 52 | if (hasAreaTextMesh && areaChanged) 53 | { 54 | areaTextMesh.text = polygon.area.ToString(); 55 | } 56 | 57 | // Track. 58 | _previousWindingDirection = polygon.winding; 59 | _previousArea = polygon.area; 60 | } 61 | } 62 | } 63 | #endif -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_8.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Scenes 13 | { 14 | 15 | 16 | using Lines; 17 | using Model; 18 | 19 | 20 | /// 21 | /// 8. Segment-Segment intersection point 22 | /// 23 | public class Controller_8 : MonoBehaviour 24 | { 25 | 26 | 27 | public Color defaultColor; 28 | public Color passingColor; 29 | 30 | public float accuracy = 0.0f; 31 | 32 | public Source.Segment segmentSourceA; 33 | public Source.Segment segmentSourceB; 34 | public SegmentLineRenderer segmentRendererA; 35 | public SegmentLineRenderer segmentRendererB; 36 | 37 | public GameObject intersectionPointObject; 38 | 39 | private Segment segment_a { get { return segmentSourceA.segment; } } 40 | private Segment segment_b { get { return segmentSourceB.segment; } } 41 | 42 | 43 | void Update() 44 | { RenderTestResult(SegmentIntersectionTest()); } 45 | 46 | bool SegmentIntersectionTest() 47 | { 48 | Vector2 intersectionPoint; 49 | bool isIntersecting = segment_a.IntersectionWithSegmentWithAccuracy(segment_b, accuracy, out intersectionPoint); 50 | if (isIntersecting) 51 | { 52 | intersectionPointObject.transform.position = new Vector3( 53 | intersectionPoint.x, 54 | intersectionPoint.y, 55 | intersectionPointObject.transform.position.z 56 | ); // Align point 57 | } 58 | 59 | return isIntersecting; 60 | } 61 | 62 | void RenderTestResult(bool testResult) 63 | { 64 | Color color = (testResult) ? passingColor : defaultColor; 65 | 66 | // Layout color. 67 | segmentRendererA.lineColor = color; 68 | segmentRendererB.lineColor = color; 69 | 70 | // Show / hide intersection point. 71 | intersectionPointObject.GetComponent().enabled = testResult; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_4.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Scenes 13 | { 14 | 15 | 16 | using Lines; 17 | using Model; 18 | 19 | 20 | /// 21 | /// 4. Polygon-Segment containment 22 | /// 23 | public class Controller_4 : MonoBehaviour 24 | { 25 | 26 | 27 | public Color defaultColor; 28 | public Color passingColor; 29 | 30 | public Source.Polygon starSource; 31 | public Source.Polygon squareSource; 32 | public PolygonLineRenderer starRenderer; 33 | public PolygonLineRenderer squareRenderer; 34 | 35 | private Polygon star { get { return starSource.polygon; } } 36 | private Polygon square { get { return squareSource.polygon; } } 37 | 38 | 39 | void Update() 40 | { RenderTestResult(IsSegmentsInsideTest()); } 41 | 42 | bool IsSegmentsInsideTest() 43 | { 44 | // Point containment. 45 | bool pointContainment = true; 46 | square.EnumeratePoints((Vector2 eachPoint) => 47 | { 48 | pointContainment &= star.ContainsPoint(eachPoint); 49 | }); 50 | 51 | // Segment-Polygon intersecion, Segment endpoint-permiter contaimnent. 52 | bool segmentIntersecting = false; 53 | bool permiterContainsSegment = false; 54 | foreach (Edge eachEdge in square.edges) 55 | { 56 | permiterContainsSegment |= star.PermiterContainsPoint(eachEdge.a) || star.PermiterContainsPoint(eachEdge.b); 57 | segmentIntersecting |= star.IsIntersectingWithSegment(eachEdge); 58 | } 59 | 60 | // Polygon inside test. 61 | bool polygonInside = pointContainment && segmentIntersecting == false && permiterContainsSegment == false; 62 | 63 | return polygonInside; 64 | } 65 | 66 | void RenderTestResult(bool testResult) 67 | { 68 | Color color = (testResult) ? passingColor : defaultColor; 69 | 70 | // Layout colors. 71 | starRenderer.lineColor = color; 72 | squareRenderer.lineColor = color; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_6.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Scenes 13 | { 14 | 15 | 16 | 17 | using Lines; 18 | using Model; 19 | 20 | 21 | /// 22 | /// 6. Vertex facing 23 | /// 24 | public class Controller_6 : MonoBehaviour 25 | { 26 | 27 | 28 | public Color defaultColor; 29 | public Color passingColor; 30 | 31 | public CornerLineRenderer cornerRenderer; 32 | public Renderer normalPointRenderer; 33 | 34 | public Transform[] segmentATransforms; 35 | public Transform[] segmentBTransforms; 36 | 37 | public Transform[] normalTransforms; 38 | 39 | private Segment segmentA; 40 | private Segment segmentB; 41 | private Segment normal; 42 | 43 | void Start() 44 | { 45 | // Create models. 46 | segmentA = Segment.SegmentWithPointTransforms(segmentATransforms); 47 | segmentB = Segment.SegmentWithPointTransforms(segmentBTransforms); 48 | normal = Segment.SegmentWithPointTransforms(normalTransforms); 49 | 50 | // Feed renderer. 51 | cornerRenderer.segmentA = segmentA; 52 | cornerRenderer.segmentB = segmentB; 53 | cornerRenderer.normal = normal; 54 | } 55 | 56 | void Update() 57 | { 58 | // Update model. 59 | segmentA.UpdateWithTransforms(segmentATransforms); 60 | segmentB.UpdateWithTransforms(segmentBTransforms); 61 | normal.UpdateWithTransforms(normalTransforms); 62 | 63 | // Test. 64 | RenderTestResult(NormalFacingTest()); 65 | } 66 | 67 | bool NormalFacingTest() 68 | { 69 | Vector2 point = normal.b; 70 | bool acute = segmentA.IsPointLeft(segmentB.b); 71 | bool leftA = segmentA.IsPointLeft(point); 72 | bool leftB = segmentB.IsPointLeft(point); 73 | bool outward = (acute) ? leftA && leftB : leftA || leftB; 74 | bool inward = !outward; 75 | return inward; 76 | } 77 | 78 | void RenderTestResult(bool testResult) 79 | { 80 | Color color = (testResult) ? passingColor : defaultColor; 81 | 82 | // Layout color. 83 | cornerRenderer.segmentNormalColor = color; 84 | normalPointRenderer.material.color = color; 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /Scenes/Controllers/Controller_5.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Scenes 13 | { 14 | 15 | 16 | using Lines; 17 | using Model; 18 | 19 | 20 | /// 21 | /// 5. Polygon-Polygon containment 22 | /// 23 | public class Controller_5 : MonoBehaviour 24 | { 25 | 26 | 27 | public Color defaultColor; 28 | public Color passingColor; 29 | 30 | public Source.Polygon starSource; 31 | public Source.Polygon squareSource; 32 | public PolygonLineRenderer starRenderer; 33 | public PolygonLineRenderer squareRenderer; 34 | 35 | private Polygon star { get { return starSource.polygon; } } 36 | private Polygon square { get { return squareSource.polygon; } } 37 | 38 | 39 | void Update() 40 | { RenderTestResult(IsPolygonInsideTest()); } 41 | 42 | bool IsPolygonInsideTest() 43 | { 44 | // Point containment. 45 | bool pointContainment = true; 46 | square.EnumeratePointsRecursive((Vector2 eachPoint) => 47 | { 48 | pointContainment &= star.ContainsPoint(eachPoint); 49 | }); 50 | 51 | // Segment-Polygon intersecion, Segment endpoint-permiter contaimnent. 52 | bool segmentIntersecting = false; 53 | bool permiterContainsSegment = false; 54 | foreach (Edge eachEdge in square.edges) 55 | { 56 | permiterContainsSegment |= star.PermiterContainsPoint(eachEdge.a) || star.PermiterContainsPoint(eachEdge.b); 57 | segmentIntersecting |= star.IsIntersectingWithSegment(eachEdge); 58 | } 59 | 60 | // A polygon contains another polygon, when 61 | // - other polygon vertices are contained by polygon, 62 | // - other polygon segments are not intersecting with polygon, 63 | // - other polygon vertices are not contained by polygon permiter. 64 | bool polygonInside = ( 65 | pointContainment && 66 | segmentIntersecting == false && 67 | permiterContainsSegment == false 68 | ); 69 | 70 | return polygonInside; 71 | } 72 | 73 | void RenderTestResult(bool testResult) 74 | { 75 | Color color = (testResult) ? passingColor : defaultColor; 76 | 77 | // Layout colors. 78 | starRenderer.lineColor = color; 79 | squareRenderer.lineColor = color; 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Lines/GeometryLineRenderer.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | #if EPPZ_LINES 9 | using UnityEngine; 10 | using System.Collections; 11 | 12 | 13 | namespace EPPZ.Geometry.Lines 14 | { 15 | 16 | 17 | using EPPZ.Lines; 18 | using Model; 19 | 20 | 21 | public class GeometryLineRenderer : DirectLineRenderer 22 | { 23 | 24 | 25 | protected void DrawSegment(Segment segment, Color color, bool drawNormals = false) 26 | { 27 | DrawLine(segment.a, segment.b, color); 28 | if (drawNormals) 29 | { 30 | Vector2 halfie = segment.a + ((segment.b - segment.a) / 2.0f); 31 | DrawLine(halfie, halfie + segment.normal * 0.1f, color); 32 | } 33 | } 34 | 35 | protected void DrawSegmentWithTransform(Segment segment, Color color, Transform transform_, bool drawNormals = false) 36 | { 37 | DrawLineWithTransform(segment.a, segment.b, color, transform_); 38 | if (drawNormals) 39 | { 40 | Vector2 halfie = segment.a + ((segment.b - segment.a) / 2.0f); 41 | DrawLineWithTransform(halfie, halfie + segment.normal * 0.1f, color, transform_); 42 | } 43 | } 44 | 45 | protected void DrawPolygon(Polygon polygon, Color color) 46 | { polygon.EnumerateEdgesRecursive((Edge eachEdge) => DrawLine(eachEdge.a, eachEdge.b, color)); } 47 | 48 | protected void DrawPolygon(Polygon polygon, Color color, bool drawNormals) 49 | { 50 | polygon.EnumerateEdgesRecursive((Edge eachEdge) => 51 | { 52 | DrawLine(eachEdge.a, eachEdge.b, color); 53 | if (drawNormals) 54 | { 55 | Vector2 halfie = eachEdge.a + ((eachEdge.b - eachEdge.a) / 2.0f); 56 | DrawLine(halfie, halfie + eachEdge.normal * 0.1f, color); 57 | } 58 | }); 59 | } 60 | 61 | protected void DrawPolygonWithTransform(Polygon polygon, Color color, Transform transform_) 62 | { DrawPolygonWithTransform(polygon, color, transform_, false); } 63 | 64 | protected void DrawPolygonWithTransform(Polygon polygon, Color color, Transform transform_, bool drawNormals) 65 | { 66 | polygon.EnumerateEdgesRecursive((Edge eachEdge) => 67 | { 68 | DrawLineWithTransform(eachEdge.a, eachEdge.b, color, transform_); 69 | if (drawNormals) 70 | { 71 | Vector2 halfie = eachEdge.a + ((eachEdge.b - eachEdge.a) / 2.0f); 72 | DrawLineWithTransform(halfie, halfie + eachEdge.normal * 0.1f, color, transform_); 73 | } 74 | }); 75 | } 76 | } 77 | } 78 | #endif 79 | 80 | -------------------------------------------------------------------------------- /AddOns/ClipperAddOns.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using System; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using UnityEngine; 12 | 13 | 14 | namespace EPPZ.Geometry.AddOns 15 | { 16 | 17 | 18 | using System.Linq; 19 | using ClipperLib; 20 | 21 | 22 | // Clipper definitions. 23 | using Path = List; 24 | using Paths = List>; 25 | 26 | 27 | using Model; 28 | 29 | 30 | public static class ClipperAddOns 31 | { 32 | 33 | 34 | #region Polygon 35 | 36 | public static Polygon PolygonFromClipperPaths(Paths paths, float scale) 37 | { 38 | Polygon polygon = null; 39 | for (int index = 0; index < paths.Count; index++) 40 | { 41 | Path eachPath = paths[index]; 42 | Polygon eachPolygon = PolygonFromClipperPath(eachPath, scale); 43 | 44 | if (index == 0) 45 | { polygon = Polygon.PolygonWithPoints(eachPolygon.points); } // Parent polygon 46 | else 47 | { polygon.AddPolygon(eachPolygon); } // Child polygons 48 | } 49 | return polygon; 50 | } 51 | 52 | public static Polygon PolygonFromClipperPath(Path path, float scale) 53 | { 54 | List points = new List(); 55 | for (int index = path.Count - 1; index >= 0; index--) // Reverse enumeration (to flip normals) 56 | { 57 | IntPoint eachPoint = path[index]; 58 | points.Add(new Vector2(eachPoint.X / scale, eachPoint.Y / scale)); 59 | } 60 | return Polygon.PolygonWithPointList(points); 61 | } 62 | 63 | public static Paths ClipperPaths(this Polygon this_, float scale) 64 | { 65 | Paths paths = new Paths(); 66 | this_.EnumeratePolygons((Polygon eachPolygon) => 67 | { 68 | paths.Add(eachPolygon.ClipperPath(scale)); 69 | }); 70 | return paths; 71 | } 72 | 73 | public static Path ClipperPath(this Polygon this_, float scale) 74 | { 75 | Path path = new Path(); 76 | this_.EnumeratePoints((Vector2 eachPoint) => 77 | { 78 | path.Add(new IntPoint( 79 | eachPoint.x * scale, 80 | eachPoint.y * scale 81 | )); 82 | }); 83 | return path; 84 | } 85 | 86 | #endregion 87 | 88 | 89 | #region Generic 90 | 91 | public static Vector2[] PointsFromClipperPath(Path path, float scale) 92 | { 93 | List points = new List(); 94 | for (int index = path.Count - 1; index >= 0; index--) // Reverse enumeration (to flip normals) 95 | { 96 | IntPoint eachPoint = path[index]; 97 | points.Add(new Vector2(eachPoint.X / scale, eachPoint.Y / scale)); 98 | } 99 | return points.ToArray(); 100 | } 101 | 102 | #endregion 103 | 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Scenes/Animations/eppz! Geometry Drift.anim: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!74 &7400000 4 | AnimationClip: 5 | m_ObjectHideFlags: 0 6 | m_PrefabParentObject: {fileID: 0} 7 | m_PrefabInternal: {fileID: 0} 8 | m_Name: eppz! Geometry Drift 9 | serializedVersion: 6 10 | m_Legacy: 1 11 | m_Compressed: 0 12 | m_UseHighQualityCurve: 1 13 | m_RotationCurves: [] 14 | m_CompressedRotationCurves: [] 15 | m_EulerCurves: [] 16 | m_PositionCurves: 17 | - curve: 18 | serializedVersion: 2 19 | m_Curve: 20 | - serializedVersion: 2 21 | time: 0 22 | value: {x: 6, y: 0, z: 0} 23 | inSlope: {x: 0, y: 0, z: 0} 24 | outSlope: {x: -0.3, y: -0, z: -0} 25 | tangentMode: 0 26 | - serializedVersion: 2 27 | time: 40 28 | value: {x: -6, y: 0, z: 0} 29 | inSlope: {x: -0.3, y: 0, z: 0} 30 | outSlope: {x: 0, y: 0, z: 0} 31 | tangentMode: 0 32 | m_PreInfinity: 2 33 | m_PostInfinity: 2 34 | m_RotationOrder: 4 35 | path: 36 | m_ScaleCurves: [] 37 | m_FloatCurves: [] 38 | m_PPtrCurves: [] 39 | m_SampleRate: 60 40 | m_WrapMode: 2 41 | m_Bounds: 42 | m_Center: {x: 0, y: 0, z: 0} 43 | m_Extent: {x: 0, y: 0, z: 0} 44 | m_ClipBindingConstant: 45 | genericBindings: [] 46 | pptrCurveMapping: [] 47 | m_AnimationClipSettings: 48 | serializedVersion: 2 49 | m_AdditiveReferencePoseClip: {fileID: 0} 50 | m_AdditiveReferencePoseTime: 0 51 | m_StartTime: 0 52 | m_StopTime: 40 53 | m_OrientationOffsetY: 0 54 | m_Level: 0 55 | m_CycleOffset: 0 56 | m_HasAdditiveReferencePose: 0 57 | m_LoopTime: 1 58 | m_LoopBlend: 0 59 | m_LoopBlendOrientation: 0 60 | m_LoopBlendPositionY: 0 61 | m_LoopBlendPositionXZ: 0 62 | m_KeepOriginalOrientation: 0 63 | m_KeepOriginalPositionY: 1 64 | m_KeepOriginalPositionXZ: 0 65 | m_HeightFromFeet: 0 66 | m_Mirror: 0 67 | m_EditorCurves: 68 | - curve: 69 | serializedVersion: 2 70 | m_Curve: 71 | - serializedVersion: 2 72 | time: 0 73 | value: 6 74 | inSlope: 0 75 | outSlope: -0.3 76 | tangentMode: 65 77 | - serializedVersion: 2 78 | time: 40 79 | value: -6 80 | inSlope: -0.3 81 | outSlope: 0 82 | tangentMode: 5 83 | m_PreInfinity: 2 84 | m_PostInfinity: 2 85 | m_RotationOrder: 4 86 | attribute: m_LocalPosition.x 87 | path: 88 | classID: 4 89 | script: {fileID: 0} 90 | - curve: 91 | serializedVersion: 2 92 | m_Curve: 93 | - serializedVersion: 2 94 | time: 0 95 | value: 0 96 | inSlope: 0 97 | outSlope: -0 98 | tangentMode: 65 99 | - serializedVersion: 2 100 | time: 40 101 | value: 0 102 | inSlope: 0 103 | outSlope: 0 104 | tangentMode: 5 105 | m_PreInfinity: 2 106 | m_PostInfinity: 2 107 | m_RotationOrder: 4 108 | attribute: m_LocalPosition.y 109 | path: 110 | classID: 4 111 | script: {fileID: 0} 112 | - curve: 113 | serializedVersion: 2 114 | m_Curve: 115 | - serializedVersion: 2 116 | time: 0 117 | value: 0 118 | inSlope: 0 119 | outSlope: -0 120 | tangentMode: 65 121 | - serializedVersion: 2 122 | time: 40 123 | value: 0 124 | inSlope: 0 125 | outSlope: 0 126 | tangentMode: 5 127 | m_PreInfinity: 2 128 | m_PostInfinity: 2 129 | m_RotationOrder: 4 130 | attribute: m_LocalPosition.z 131 | path: 132 | classID: 4 133 | script: {fileID: 0} 134 | m_EulerEditorCurves: [] 135 | m_HasGenericRootTransform: 0 136 | m_HasMotionFloatCurves: 0 137 | m_GenerateMotionCurves: 0 138 | m_Events: [] 139 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # eppz! `Geometry` 2 | 3 | * 1.0.13 4 | 5 | + Included `meta` files to fix example scenes 6 | 7 | * 1.0.11 8 | 9 | + Force text asset serialization 10 | 11 | * 1.0.1 12 | 13 | + Test scenes 14 | + `11. Polygon triangulation (1)` 15 | + `11. Polygon triangulation (2)` 16 | + `Polygon.UpdatePointPositionsWithSource()` 17 | + Update child transforms 18 | 19 | * 1.0.0 20 | 21 | + Triangulation 22 | + Resolved issue with inner triangles 23 | + Skip triangles if centroid not contained by polygon 24 | + `Source` 25 | + `Mesh` 26 | + Component to feed `MeshFilter` components 27 | + `Polygon` / `Segment` 28 | + Added `coordinates` to process `World` / `Local` coordinates 29 | 30 | * 0.9.7 31 | 32 | + Triangulation 33 | + Feature ready (`Triangle.Net` beta 4 hooked up) 34 | + API is not quiet done yet 35 | 36 | * 0.9.5 37 | 38 | + Namings 39 | + Model classes namespaced into `Model` 40 | + Source classes namespaced into `Source` 41 | + `Components.PolygonSource` is `Source.Polygon` 42 | + `Components.SegmentSource` is `Source.Segment` 43 | + `pointTransforms` is `points` 44 | + Updated controllers in `Scenes/Controllers` 45 | 46 | * 0.9.0 47 | 48 | + Added `TriangleNetAddOns` 49 | + Added `UnityEngineAdOns` 50 | 51 | * 0.8.3 52 | 53 | + Added `ClipperAddOns` 54 | 55 | * 0.8.2 56 | 57 | + `PolygonSource` 58 | + Offset now can be manipulated at runtime 59 | + Maintain the original polygon, so offset polygon can be recalculated any time 60 | 61 | * 0.8.0 62 | 63 | + Test scenes 64 | `8. Segment-Segment intersection point` 65 | `9. Polygon offset` 66 | `10. Multiple polygon centroid` 67 | + `ExtendedPolygonLineRenderer` 68 | + Winding and area hooks moved down here 69 | 70 | * 0.7.0 71 | 72 | + Test scenes 73 | `4. Polygon-Segment containment` 74 | `5. Polygon-Polygon containment` 75 | `6. Vertex facing` 76 | `7. Polygon area, Polygon winding` 77 | + `Segment` (with `SegmentLineRenderer`) 78 | + Can now draw normals 79 | + `normal` and `perpendicular` calculations moved up from `Edge` 80 | + `Polygon` 81 | + Fixed `area` (so `winding`) calculations 82 | 83 | * 0.6.0 84 | 85 | + Test scenes 86 | + `5. Polygon-Polygon containment (1)` 87 | + `5. Polygon-Polygon containment (2)` 88 | 89 | * 0.5.9 90 | 91 | + Polygon / segment sources now can be updates on `Update` or `LateUpdate` 92 | + Test scenes 93 | + Updated update modes 94 | 95 | * 0.5.8 96 | 97 | + Test scenes 98 | + `3. Polygon permiter-Point containment (Default)` 99 | + `4. Polygon-Segment containment` 100 | + Polygon / segment sources use world position (!) instead local 101 | + Line renderers use world positions as well (both segment and polygon) 102 | + Polygon and segment sources can be updated on `LateUpdate()` 103 | 104 | * 0.5.7 105 | 106 | + Test scene `2. Polygon permiter-Point containment (Precise)` 107 | 108 | * 0.5.6 109 | 110 | + Test scene `1. Polygon-Segment intersection` 111 | 112 | * 0.5.5 113 | 114 | + Only calculated winding direction 115 | + Removed option to define polygon winding 116 | + Removed distinct `_signedArea` 117 | + `area` is always (!) signed 118 | + Polygon calculations grouped together 119 | + Renamed to simply `winding` 120 | + `Geometry` 121 | + `CentroidOfPolygons` use `area` directly (being always signed) 122 | 123 | * 0.5.1 124 | 125 | + Added `Lines` (renderer classes) 126 | + Added `Scenes` 127 | + Yet with a single scene `0. Polygon-point containment` 128 | 129 | * 0.5.0 130 | 131 | + Added the root `Geometry.cs` static class 132 | + Added `Vector2` / `Vector3` extensions 133 | + Added `AddOns` (yet disabled) 134 | + Added `Components` 135 | + Added `Editor` scripts 136 | + Added `Model` classes 137 | + Added regions, XML-Doc summaries 138 | + Update `README.md` 139 | 140 | * 0.0.2 141 | 142 | + Added `Clipper` submodule 143 | + Added `Triangle.NET` submodule 144 | 145 | * 0.0.1 146 | 147 | + Ignore `.meta` files (no value for script assets) 148 | 149 | * 0.0.0 150 | 151 | + Initial commit -------------------------------------------------------------------------------- /Model/Edge.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Model 13 | { 14 | 15 | 16 | public class Edge : Segment 17 | { 18 | 19 | 20 | private int _index; 21 | public int index { get { return _index; } } // Readonly 22 | public Polygon polygon { get { return vertexA.polygon; } } // Readonly 23 | 24 | public Vertex vertexA; 25 | public Vertex vertexB; 26 | 27 | 28 | #region Factory 29 | 30 | public static Edge EdgeAtIndexWithVertices(int index, Vertex vertexA, Vertex vertexB) 31 | { 32 | Edge instance = new Edge(); 33 | instance._index = index; 34 | instance.vertexA = vertexA; 35 | instance.vertexB = vertexB; 36 | return instance; 37 | } 38 | 39 | #endregion 40 | 41 | 42 | #region Override segment point accessors (perefencing polygon points directly). 43 | 44 | public override Vector2 a 45 | { 46 | get { return polygon.points[vertexA.index]; } 47 | set { polygon.points[vertexA.index] = value; } 48 | } 49 | 50 | public override Vector2 b 51 | { 52 | get { return polygon.points[vertexB.index]; } 53 | set { polygon.points[vertexB.index] = value; } 54 | } 55 | 56 | #endregion 57 | 58 | 59 | #region Accessors 60 | 61 | public Edge _previousEdge; 62 | public virtual Edge previousEdge { get { return _previousEdge; } } // Readonly 63 | public void SetPreviousEdge(Edge edge) { _previousEdge = edge; } // Explicit setter (injected at creation time) 64 | 65 | public Edge _nextEdge; 66 | public virtual Edge nextEdge { get { return _nextEdge; } } // Readonly 67 | public void SetNextEdge(Edge edge) { _nextEdge = edge; } // Explicit setter (injected at creation time) 68 | 69 | #endregion 70 | 71 | 72 | #region Polygon features 73 | 74 | public bool ForwardIntersection(out Edge intersectingEdge, out Vector2 intersectionPoint, bool checkEntirePolygonLoop) 75 | { 76 | // Default. 77 | intersectingEdge = null; 78 | intersectionPoint = Vector2.zero; 79 | bool intersecting = false; 80 | 81 | // Only if there are edges enough to test. 82 | if (this.polygon.edges.Length <= 3) return false; 83 | 84 | Edge testEdge = this.nextEdge.nextEdge; // Skip next neighbour 85 | while(true) 86 | { 87 | intersecting = this.IntersectionWithSegment(testEdge, out intersectionPoint); 88 | if (intersecting) 89 | { 90 | intersectingEdge = testEdge; 91 | break; 92 | } 93 | 94 | // Step. 95 | testEdge = testEdge.nextEdge; 96 | 97 | // End conditions. 98 | bool end; 99 | if (checkEntirePolygonLoop) 100 | { 101 | end = (testEdge == this.previousEdge.previousEdge); // Only up till the previous neighbour 102 | } 103 | else 104 | { 105 | end = (testEdge == this.polygon.edges[0].previousEdge); // Only up till the end of the polygon loop 106 | } 107 | if (end) break; 108 | } 109 | 110 | return intersecting; 111 | } 112 | 113 | #endregion 114 | 115 | 116 | } 117 | } -------------------------------------------------------------------------------- /Model/Vertex.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | 11 | 12 | namespace EPPZ.Geometry.Model 13 | { 14 | 15 | 16 | public class Vertex 17 | { 18 | 19 | 20 | private int _index; 21 | public int index { get { return _index; } } // Readonly 22 | private Polygon _polygon; 23 | public Polygon polygon { get { return _polygon; } } // Readonly 24 | 25 | // If `alwaysCalculate` is on, every `normal` and `bisector` property access invokes recalculation of values based on actual topology. 26 | public bool alwaysCalculate = true; 27 | 28 | private Vector2 _normal; 29 | public Vector2 normal 30 | { 31 | get 32 | { 33 | if (_normal == Vector2.zero || alwaysCalculate) { CalculateNormal(); } // Lazy calculation or force calculate on every access 34 | return _normal; 35 | } 36 | 37 | set 38 | { _normal = value; } 39 | } 40 | 41 | // Bisector is simply the sum of the neighbouring edge normals (not normalized). 42 | public Vector2 _bisector; 43 | public Vector2 bisector 44 | { 45 | get 46 | { 47 | if (_bisector == Vector2.zero || alwaysCalculate) { CalculateBisector(); } // Lazy calculation or force calculate on every access 48 | return _bisector; 49 | } 50 | 51 | set 52 | { _bisector = value; } 53 | } 54 | 55 | public void CalculateNormal() 56 | { _normal = this.bisector.normalized; } 57 | 58 | public void CalculateBisector() 59 | { _bisector = previousEdge.normal + nextEdge.normal; } 60 | 61 | 62 | #region Factory 63 | 64 | public static Vertex VertexAtIndexInPolygon(int index, Polygon polygon) 65 | { 66 | Vertex instance = new Vertex(); 67 | instance._index = index; 68 | instance._polygon = polygon; 69 | return instance; 70 | } 71 | 72 | #endregion 73 | 74 | 75 | #region Accessors 76 | 77 | private Vertex _previousVertex; 78 | public virtual Vertex previousVertex { get { return _previousVertex; } } // Readonly 79 | public void SetPreviousVertex(Vertex vertex) { _previousVertex = vertex; } // Explicit setter (injected at creation time) 80 | 81 | private Vertex _nextVertex; 82 | public virtual Vertex nextVertex { get { return _nextVertex; } } // Readonly 83 | public void SetNextVertex(Vertex vertex) { _nextVertex = vertex; } // Explicit setter (injected at creation time) 84 | 85 | private Edge _previousEdge; 86 | public virtual Edge previousEdge { get { return _previousEdge; } } // Readonly 87 | public void SetPreviousEdge(Edge edge) { _previousEdge = edge; } // Explicit setter (injected at creation time) 88 | 89 | private Edge _nextEdge; 90 | public virtual Edge nextEdge { get { return _nextEdge; } } // Readonly 91 | public void SetNextEdge(Edge edge) { _nextEdge = edge; } // Explicit setter (injected at creation time) 92 | 93 | public virtual Vector2 point { get { return polygon.points[index]; } } // Readonly 94 | public float x { get { return point.x; } } // Readonly 95 | public float y { get { return point.y; } } // Readonly 96 | 97 | #endregion 98 | 99 | 100 | } 101 | } -------------------------------------------------------------------------------- /AddOns/TriangleNetAddOns.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using System; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using UnityEngine; 12 | 13 | 14 | namespace EPPZ.Geometry.AddOns 15 | { 16 | 17 | 18 | using System.Linq; 19 | 20 | using ClipperLib; 21 | using Path = List; 22 | using Paths = List>; 23 | 24 | using Model; 25 | 26 | 27 | public static class TriangleNetAddOns 28 | { 29 | 30 | 31 | #region Polygon 32 | 33 | public static TriangleNet.Geometry.Polygon TriangleNetPolygon(this Polygon this_) 34 | { 35 | TriangleNet.Geometry.Polygon polygon = new TriangleNet.Geometry.Polygon(); 36 | 37 | int boundary = 1; 38 | List vertices = new List(); 39 | this_.EnumeratePolygons((Polygon eachPolygon) => 40 | { 41 | // Collect vertices. 42 | vertices.Clear(); 43 | eachPolygon.EnumeratePoints((Vector2 eachPoint) => 44 | { 45 | vertices.Add(new TriangleNet.Geometry.Vertex( 46 | (double)eachPoint.x, 47 | (double)eachPoint.y, 48 | boundary 49 | )); 50 | }); 51 | 52 | // Add controur. 53 | polygon.Add(new TriangleNet.Geometry.Contour(vertices.ToArray(), boundary)); 54 | 55 | // Track. 56 | boundary++; 57 | }); 58 | 59 | return polygon; 60 | } 61 | 62 | #endregion 63 | 64 | 65 | #region Voronoi (beta 3) 66 | 67 | public static Rect Bounds(this TriangleNet.Voronoi.Legacy.SimpleVoronoi this_) 68 | { 69 | float xmin = float.MaxValue; 70 | float xmax = 0.0f; 71 | float ymin = float.MaxValue; 72 | float ymax = 0.0f; 73 | foreach (TriangleNet.Voronoi.Legacy.VoronoiRegion region in this_.Regions) 74 | { 75 | foreach (TriangleNet.Geometry.Point eachPoint in region.Vertices) 76 | { 77 | if (eachPoint.X > xmax) xmax = (float)eachPoint.X; 78 | if (eachPoint.X < xmin) xmin = (float)eachPoint.X; 79 | if (eachPoint.Y > ymax) ymax = (float)eachPoint.Y; 80 | if (eachPoint.Y < ymin) ymin = (float)eachPoint.Y; 81 | } 82 | } 83 | return Rect.MinMaxRect(xmin, ymin, xmax, ymax); 84 | } 85 | 86 | public static Paths ClipperPathsFromVoronoiRegions(List voronoiRegions, float scale = 1.0f) 87 | { 88 | Paths paths = new Paths(); 89 | 90 | foreach (TriangleNet.Voronoi.Legacy.VoronoiRegion eachRegion in voronoiRegions) 91 | { 92 | Path eachPath = new Path(); 93 | foreach (TriangleNet.Geometry.Point eachPoint in eachRegion.Vertices) 94 | { 95 | eachPath.Add(new IntPoint( 96 | eachPoint.X * scale, 97 | eachPoint.Y * scale 98 | )); 99 | } 100 | paths.Add(eachPath); 101 | } 102 | return paths; 103 | } 104 | 105 | #endregion 106 | 107 | 108 | #region Generic 109 | 110 | public static Vector2 VectorFromPoint(TriangleNet.Geometry.Point point) 111 | { 112 | return new Vector2((float)point.X, (float)point.Y); 113 | } 114 | 115 | public static Vector2[] PointsFromVertices(ICollection vertices) 116 | { 117 | Vector2[] points = new Vector2[vertices.Count]; 118 | int pointIndex = 0; 119 | foreach (TriangleNet.Geometry.Point eachPoint in vertices) 120 | { 121 | points[pointIndex] = VectorFromPoint(eachPoint); 122 | pointIndex++; 123 | } 124 | return points; 125 | } 126 | 127 | #endregion 128 | 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /AddOns/UnityEngineAddOns.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using System; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | using UnityEngine; 12 | 13 | 14 | namespace EPPZ.Geometry.AddOns 15 | { 16 | 17 | 18 | using TriangleNet.Geometry; 19 | using TriangleNet.Meshing; 20 | using TriangleNet.Meshing.Algorithm; 21 | using TriangleNet.Tools; 22 | 23 | 24 | public enum TriangulatorType { Incremental, Dwyer, SweepLine }; 25 | 26 | 27 | public static class UnityEngineAddOns 28 | { 29 | 30 | 31 | static ITriangulator TriangulatorForType(TriangulatorType triangulator) 32 | { 33 | switch (triangulator) 34 | { 35 | case TriangulatorType.Incremental : return new Incremental(); 36 | case TriangulatorType.Dwyer : return new Dwyer(); 37 | case TriangulatorType.SweepLine : return new SweepLine(); 38 | default : return new Dwyer(); 39 | } 40 | } 41 | 42 | static bool skipCentroidTest = false; // For debugging 43 | 44 | 45 | #region Polygon 46 | 47 | public static UnityEngine.Mesh Mesh(this EPPZ.Geometry.Model.Polygon this_, string name = "") 48 | { return this_.Mesh(Color.white, TriangulatorType.Dwyer, name); } 49 | 50 | public static UnityEngine.Mesh Mesh(this EPPZ.Geometry.Model.Polygon this_, TriangulatorType triangulator, string name = "") 51 | { return this_.Mesh(Color.white, triangulator, name); } 52 | 53 | public static UnityEngine.Mesh Mesh(this EPPZ.Geometry.Model.Polygon this_, Color color, TriangulatorType triangulator, string name = "") 54 | { 55 | // Create geometry. 56 | TriangleNet.Geometry.Polygon polygon = this_.TriangleNetPolygon(); 57 | 58 | // Triangulate. 59 | ConstraintOptions options = new ConstraintOptions(); 60 | // ConformingDelaunay 61 | // Convex 62 | // SegmentSplitting 63 | QualityOptions quality = new QualityOptions(); 64 | // MinimumAngle 65 | // MaximumArea 66 | // UserTest 67 | // VariableArea 68 | // SteinerPoints 69 | IMesh triangulatedMesh = polygon.Triangulate(options, quality, TriangulatorForType(triangulator)); 70 | 71 | // Counts. 72 | int vertexCount = triangulatedMesh.Vertices.Count; 73 | int triangleCount = triangulatedMesh.Triangles.Count; 74 | 75 | // Mesh store. 76 | Vector3[] _vertices = new Vector3[vertexCount]; 77 | Vector2[] _uv = new Vector2[vertexCount]; 78 | Vector3[] _normals = new Vector3[vertexCount]; 79 | Color[] _colors = new Color[vertexCount]; 80 | List _triangles = new List(); // Size may vary 81 | 82 | // Vertices. 83 | int index = 0; 84 | foreach (TriangleNet.Geometry.Vertex eachVertex in triangulatedMesh.Vertices) 85 | { 86 | _vertices[index] = new Vector3( 87 | (float)eachVertex.x, 88 | (float)eachVertex.y, 89 | 0.0f // As of 2D 90 | ); 91 | 92 | _uv[index] = _vertices[index]; 93 | _normals[index] = Vector3.forward; 94 | _colors[index] = color; 95 | 96 | index++; 97 | } 98 | 99 | // Triangles. 100 | foreach (TriangleNet.Topology.Triangle eachTriangle in triangulatedMesh.Triangles) 101 | { 102 | // Get vertices. 103 | Point P2 = eachTriangle.GetVertex(2); 104 | Point P1 = eachTriangle.GetVertex(1); 105 | Point P0 = eachTriangle.GetVertex(0); 106 | 107 | // Get centroid. 108 | Vector2 centroid = new Vector2( 109 | (float)(P2.X + P1.X + P0.X) / 3.0f, 110 | (float)(P2.Y + P1.Y + P0.Y) / 3.0f 111 | ); 112 | 113 | // Add only if centroid contained. 114 | if (this_.ContainsPoint(centroid) || skipCentroidTest) 115 | { 116 | _triangles.Add(P2.ID); 117 | _triangles.Add(P1.ID); 118 | _triangles.Add(P0.ID); 119 | } 120 | } 121 | 122 | // Create / setup mesh. 123 | Mesh mesh = new Mesh(); 124 | mesh.vertices = _vertices; 125 | mesh.uv = _uv; 126 | mesh.normals = _normals; 127 | mesh.colors = _colors; 128 | mesh.subMeshCount = 1; 129 | mesh.SetTriangles(_triangles.ToArray(), 0); 130 | mesh.name = name; 131 | 132 | return mesh; 133 | } 134 | 135 | #endregion 136 | 137 | 138 | } 139 | } 140 | 141 | -------------------------------------------------------------------------------- /Scenes/Materials/eppz! Geometry Star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 16 | 17 | 18 | 19 | 21 | 22 | 25 | 27 | 28 | 31 | 33 | 34 | 37 | 39 | 40 | 43 | 45 | 46 | 49 | 50 | 51 | 53 | 54 | 56 | 58 | 59 | 61 | 63 | 64 | 66 | 68 | 69 | 71 | 73 | 74 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /Geometry.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | 12 | 13 | namespace EPPZ.Geometry 14 | { 15 | 16 | 17 | using Model; // For `Polygon` region only 18 | 19 | 20 | public static class Geometry 21 | { 22 | 23 | 24 | #region Point 25 | 26 | // Determine if points are equal with a given accuracy. 27 | public static bool ArePointsEqualWithAccuracy(Vector2 a, Vector2 b, float accuracy) 28 | { 29 | return Vector2.Distance(a, b) <= accuracy; 30 | } 31 | 32 | // Determine winding direction of three points. 33 | public static bool ArePointsCCW(Vector2 a, Vector2 b, Vector2 c) 34 | { 35 | return ((c.y - a.y) * (b.x - a.x) > (b.y - a.y) * (c.x - a.x)); 36 | } 37 | 38 | #endregion 39 | 40 | 41 | #region Rect / Bounds 42 | 43 | // Determine if `rect2.size` fits into `rect1`. 44 | public static bool IsRectContainsRectSizeWithAccuracy(Rect rect1, Rect rect2) // Compare sizes only 45 | { 46 | return Geometry.IsRectContainsRectSizeWithAccuracy(rect1, rect2, 0.0f); 47 | } 48 | 49 | // Determine if `rect2.size` fits into `rect1` with a given accuracy. 50 | public static bool IsRectContainsRectSizeWithAccuracy(Rect rect1, Rect rect2, float accuracy) // Compare sizes only 51 | { 52 | return ( 53 | Mathf.Abs(rect1.width + accuracy * 2.0f) >= Mathf.Abs(rect2.width)) && 54 | (Mathf.Abs(rect1.height + accuracy * 2.0f) >= Mathf.Abs(rect2.height) 55 | ); 56 | } 57 | 58 | // Determine if `rect2` is contained by `rect1` (even if permiters are touching). 59 | public static bool IsRectContainsRectWithAccuracy(Rect rect1, Rect rect2) 60 | { return Geometry.IsRectContainsRectWithAccuracy(rect1, rect2, 0.0f); } 61 | 62 | // Determine if `rect2` is contained by `rect1` (even if permiters are touching) with a given accuracy. 63 | public static bool IsRectContainsRectWithAccuracy(Rect rect1, Rect rect2, float accuracy) 64 | { 65 | bool xMin = (rect1.xMin - accuracy <= rect2.xMin); 66 | bool xMax = (rect1.xMax + accuracy >= rect2.xMax); 67 | bool yMin = (rect1.yMin - accuracy <= rect2.yMin); 68 | bool yMax = (rect1.yMax + accuracy >= rect2.yMax); 69 | return xMin && xMax && yMin && yMax; 70 | } 71 | 72 | #endregion 73 | 74 | 75 | #region Line 76 | 77 | /// 78 | /// Returns intersection point of two lines (defined by segment endpoints). 79 | /// Returns zero, when segments have common points, or when a segment point lies on other. 80 | /// 81 | public static Vector2 IntersectionPointOfLines(Vector2 segment1_a, Vector2 segment1_b, Vector2 segment2_a, Vector2 segment2_b) 82 | { 83 | float crossProduct = (segment1_a.x - segment1_b.x) * (segment2_a.y - segment2_b.y) - (segment1_a.y - segment1_b.y) * (segment2_a.x - segment2_b.x); 84 | if (crossProduct == 0.0f) return Vector2.zero; 85 | 86 | float x = ((segment2_a.x - segment2_b.x) * (segment1_a.x * segment1_b.y - segment1_a.y * segment1_b.x) - (segment1_a.x - segment1_b.x) * (segment2_a.x * segment2_b.y - segment2_a.y * segment2_b.x)) / crossProduct; 87 | float y = ((segment2_a.y - segment2_b.y) * (segment1_a.x * segment1_b.y - segment1_a.y * segment1_b.x) - (segment1_a.y - segment1_b.y) * (segment2_a.x * segment2_b.y - segment2_a.y * segment2_b.x)) / crossProduct; 88 | 89 | // Skip segmental tests. 90 | // if (x < Mathf.Min(a1.x, b1.x) || x > Mathf.Max(a1.x, b1.x)) return Vector2.zero; 91 | // if (x < Mathf.Min(a2.x, b2.x) || x > Mathf.Max(a2.x, b2.x)) return Vector2.zero; 92 | 93 | return new Vector2(x, y); 94 | } 95 | 96 | // Determine point distance from line (defined by segment endpoints). 97 | public static float PointDistanceFromLine(Vector2 point, Vector2 segment_a, Vector2 segment_b) 98 | { 99 | float a_ = point.x - segment_a.x; 100 | float b_ = point.y - segment_a.y; 101 | float c_ = segment_b.x - segment_a.x; 102 | float d_ = segment_b.y - segment_a.y; 103 | return Mathf.Abs(a_ * d_ - c_ * b_) / Mathf.Sqrt(c_ * c_ + d_ * d_); 104 | } 105 | 106 | #endregion 107 | 108 | 109 | #region Segment 110 | 111 | // Determine if a given point lies on the left side of a segment (line beneath). 112 | public static bool PointIsLeftOfSegment(Vector2 point, Vector2 segment_a, Vector2 segment_b) 113 | { 114 | float crossProduct = (segment_b.x - segment_a.x) * (point.y - segment_a.y) - (segment_b.y - segment_a.y) * (point.x - segment_a.x); 115 | return (crossProduct > 0.0f); 116 | } 117 | 118 | // Determine if segments (defined by endpoints) are equal with a given accuracy. 119 | public static bool AreSegmentsEqualWithAccuracy(Vector2 segment1_a, Vector2 segment1_b, Vector2 segment2_a, Vector2 segment2_b, float accuracy) 120 | { 121 | return ( 122 | (ArePointsEqualWithAccuracy(segment1_a, segment2_a, accuracy) && ArePointsEqualWithAccuracy(segment1_b, segment2_b, accuracy)) || 123 | (ArePointsEqualWithAccuracy(segment1_a, segment2_b, accuracy) && ArePointsEqualWithAccuracy(segment1_b, segment2_a, accuracy)) 124 | ); 125 | } 126 | 127 | // Determine if segments (defined by endpoints) have common points with a given accuracy. 128 | public static bool HaveSegmentsCommonPointsWithAccuracy(Vector2 segment1_a, Vector2 segment1_b, Vector2 segment2_a, Vector2 segment2_b, float accuracy) 129 | { 130 | return ( 131 | ArePointsEqualWithAccuracy(segment1_a, segment2_a, accuracy) || 132 | ArePointsEqualWithAccuracy(segment1_a, segment2_b, accuracy) || 133 | ArePointsEqualWithAccuracy(segment1_b, segment2_a, accuracy) || 134 | ArePointsEqualWithAccuracy(segment1_b, segment2_b, accuracy) 135 | ); 136 | } 137 | 138 | /// 139 | /// Determine if two segments defined by endpoints are intersecting (defined by points). 140 | /// True when the two segments are intersecting. Not true when endpoints 141 | /// are equal, nor when a point is contained by other segment. 142 | /// From http://bryceboe.com/2006/10/23/line-segment-intersection-algorithm/ 143 | /// 144 | public static bool AreSegmentsIntersecting(Vector2 segment1_a, Vector2 segment1_b, Vector2 segment2_a, Vector2 segment2_b) 145 | { 146 | return ( 147 | (ArePointsCCW(segment1_a, segment2_a, segment2_b) != ArePointsCCW(segment1_b, segment2_a, segment2_b)) && 148 | (ArePointsCCW(segment1_a, segment1_b, segment2_a) != ArePointsCCW(segment1_a, segment1_b, segment2_b)) 149 | ); 150 | } 151 | 152 | #endregion 153 | 154 | 155 | #region Polygon 156 | 157 | /// 158 | /// Test if a polygon contains the given point (checks for sub-polygons recursive). 159 | /// Uses the same Bryce boe algorythm, so considerations are the same. 160 | /// From https://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm 161 | /// 162 | public static bool IsPolygonContainsPoint(Polygon polygon, Vector2 point) 163 | { 164 | // Winding ray left point. 165 | Vector2 left = new Vector2(polygon.bounds.xMin - polygon.bounds.width, point.y); 166 | 167 | // Enumerate polygon segments. 168 | int windingNumber = 0; 169 | polygon.EnumerateEdgesRecursive((Edge eachEdge) => 170 | { 171 | // Test winding ray against each polygon segment. 172 | if (AreSegmentsIntersecting(left, point, eachEdge.a, eachEdge.b)) 173 | { windingNumber++; } 174 | }); 175 | 176 | bool isOdd = (windingNumber % 2 != 0); // Odd winding number means point falls outside 177 | return isOdd; 178 | } 179 | 180 | public static Vector2 CentroidOfPolygons(Polygon[] polygons) 181 | { 182 | // From https://en.wikipedia.org/wiki/Centroid#By_geometric_decomposition 183 | float ΣxA = 0.0f; 184 | float ΣyA = 0.0f; 185 | float ΣA = 0.0f; 186 | foreach (Polygon eachPolygon in polygons) 187 | { 188 | // Get centroid. 189 | Vector2 eachCentroid = eachPolygon.centroid; 190 | 191 | // Sum weighted. 192 | ΣxA += eachCentroid.x * eachPolygon.area; 193 | ΣyA += eachCentroid.y * eachPolygon.area; 194 | ΣA += eachPolygon.area; 195 | } 196 | 197 | // "Remove" area. 198 | float x = ΣxA / ΣA; 199 | float y = ΣyA / ΣA; 200 | 201 | return new Vector2(x, y); 202 | } 203 | 204 | #endregion 205 | 206 | 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eppz! `Geometry` 2 | > part of [**Unity.Library.eppz**](https://github.com/eppz/Unity.Library.eppz) 3 | 4 | **📐 2D geometry for Unity.** Suited for everyday polygon hassle. 5 | 6 | Polygon clipping, polygon winding direction, polygon area, polygon centroid, centroid of multiple polygons, line intersection, point-line distance, segment intersection, polygon-point containment, polygon triangulation, polygon Voronoi diagram, polygon offset, polygon outline, polygon buffer, polygon union, polygon substraction, polygon boolean operations, and more. 7 | 8 | ![Unity.Library.eppz.Geometry.Model.Poygon.Mesh.Triangulation](https://github.com/eppz/Unity.Library.eppz.Geometry/raw/Documentation/Documentation/Unity.Library.eppz.Geometry.Model.Poygon.Mesh.Triangulation.gif) 9 | 10 | The library is **being used in production**. However, it comes with the disclaimed liability and warranty of [MIT License](https://en.wikipedia.org/wiki/MIT_License). 11 | 12 | ## Examples 13 | 14 | If you prefer to read example code immediately, you can find example scenes in [`Scenes`](Scenes) folder. 15 | 16 | + [Polygon-Point containment](Scenes/README.md/#0-polygon-point-containment) 17 | + [Polygon-Segment intersection test](Scenes/README.md/#1-polygon-segment-intersection) 18 | + [Polygon permiter-Point containment (Precise)](Scenes/README.md/#2-polygon-permiter-point-containment-precise) 19 | + [Polygon permiter-Point containment (Default)](Scenes/README.md/#3-polygon-permiter-point-containment-default) 20 | + [Polygon-Segment containment](Scenes/README.md/#4-polygon-segment-containment) 21 | + [Polygon-Polygon containment](Scenes/README.md/#5-polygon-polygon-containment) 22 | + [Vertex facing](Scenes/README.md/#6-vertex-facing) 23 | + [Polygon area, Polygon winding](Scenes/README.md/#7-polygon-area-polygon-winding) 24 | + [Segment-Segment intersection point](Scenes/README.md/#8-segment-segment-intersection-point) 25 | + [Polygon offset](Scenes/README.md/#9-polygon-offset) 26 | + [Multiple polygon centroid](Scenes/README.md/#10-multiple-polygon-centroid) 27 | + [Polygon triangulation](Scenes/README.md/#11-polygon-triangulation) 28 | 29 | ## Model classes 30 | 31 | * [`Vertex.cs`](Model/Vertex.cs) 32 | + Basically a `Vector2` point, but is aware of the polygon context it resides (neighbours, segments, edges, polygon, bisector, normal). 33 | * [`Segment.cs`](Model/Segment.cs) 34 | + Segment of two `Vector2` point. Carries out basic geometry features (point distance, point containment, segment intersection). 35 | * [`Edge.cs`](Model/Edge.cs) 36 | + Edge of two `Vertex` in a polygon (a special `Segment` subclass). Likewise vertices, this model is also aware of the polygon context it resides (neighbours, segments, edges, polygon, perpendicular, normal). 37 | * [`Polygon.cs`](Model/Edge.cs) 38 | + The role player, it really **embodies mostly every feature of this library**. Basically a polygon made of vertices. 39 | + Can be created with point array, transforms, [`Source.Polygon`](Source/Polygon.cs) components. Further polygons can be embedded into recursively. Vertices, edges, polygons can be enumerated (recursively). 40 | + Area, winding direction, centroid are being calculated. Also carries the basic geometry features (point containment, line-, segment-, polygon intersection and more). 41 | + Using library modules, it implements polygon offset (outline), union polygon (polygon clipping), basic mesh triangulation. It implements conversion to both [Clipper](https://github.com/eppz/Clipper) and [Triangle.NET](https://github.com/eppz/Triangle.NET), so you can implement further integration with those (awesome) libraries. 42 | 43 | ## [`Geometry.cs`](Geometry.cs) 44 | 45 | Most of the basic 2D geometry algorithm collection is implemented in this static base class. You can (mostly) **use them with Unity `Vector2` types directly**, so (almost entirely) without the model classes introduced above. 46 | 47 | * **Point** 48 | + [**`ArePointsEqualWithAccuracy()`**](Geometry.cs#L24) 49 | + Determine if points are equal with a given accuracy. 50 | + [**`ArePointsCCW()`**](Geometry.cs#L30) 51 | + Determine winding direction of three points. 52 | * **Rect / Bounds** 53 | + [**`IsRectContainsRectSizeWithAccuracy()`**](Geometry.cs#L41) 54 | + Determine if `rect2.size` fits into `rect1` (compare sizes only). 55 | + [**`IsRectContainsRectWithAccuracy()`**](Geometry.cs#L56) 56 | + Determine if `rect2` is contained by `rect1` (even if permiters are touching) with a given accuracy. 57 | * **Line** 58 | + [**`IntersectionPointOfLines()`**](Geometry.cs#L78) 59 | + Returns intersection point of two lines (defined by segment endpoints). Returns zero, when segments have common points, or when a segment point lies on other. 60 | + [**`PointDistanceFromLine()`**](Geometry.cs#L97) 61 | + Determine point distance from line (defined by segment endpoints). 62 | * **Segment** 63 | + [**`PointIsLeftOfSegment()`**](Geometry.cs#L109) 64 | + Determine if a given point lies on the left side of a segment (line beneath). 65 | + [**`AreSegmentsEqualWithAccuracy()`**](Geometry.cs#L116) 66 | + Determine if segments (defined by endpoints) are equal with a given accuracy. 67 | + [**`HaveSegmentsCommonPointsWithAccuracy()`**](Geometry.cs#L125) 68 | + Determine if segments (defined by endpoints) have common points with a given accuracy. 69 | + [**`AreSegmentsIntersecting()`**](Geometry.cs#L141) 70 | + Determine if two segments defined by endpoints are intersecting (defined by points). True when the two segments are intersecting. Not true when endpoints are equal, nor when a point is contained by other segment. Credits to [Bryce Boe](https://github.com/bboe) (@bboe) for his writeup [Line Segment Intersection Algorithm](http://bryceboe.com/2006/10/23/line-segment-intersection-algorithm). 71 | * **Polygon** (using `EPPZ.Geometry.Polygon`) 72 | + [**`IsPolygonContainsPoint()`**](Geometry.cs#L159) 73 | + Test if a polygon contains the given point (checks for sub-polygons recursive). Uses the same Bryce boe algorithm above, so considerations are the same. See [Point in polygon](https://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm) for more. 74 | + [**`CentroidOfPolygons()`**](Geometry.cs#L177) 75 | + Returns the compound centroid of multiple polygon using [Geometric decomposition](https://en.wikipedia.org/wiki/Centroid#By_geometric_decomposition). 76 | 77 | ## Modules 78 | 79 | For clipping, offsetting, triangulating the library use these brilliant third party `C#` libraries below. 80 | 81 | * [Clipper](https://github.com/eppz/Clipper) 82 | 83 | + Polygon and line clipping and offsetting library (C++, C#, Delphi) by Angus Johnson. See standalone project repository [Clipper](https://github.com/eppz/Clipper) for details. 84 | 85 | * [Triangle.NET](https://github.com/eppz/Triangle.NET) 86 | 87 | + Triangle.NET generates 2D (constrained) Delaunay triangulations and high-quality meshes of point sets or planar straight line graphs. It is a C# port by Christian Woltering of Jonathan Shewchuk's Triangle software. See standalone project repository [Triangle.NET](https://github.com/eppz/Triangle.NET) for details. 88 | 89 | ## Naming 90 | 91 | The library uses namespaces heavily. I like to **name things as they are**. An edge in this library called `Edge`, a polygon is called `Polygon`. If it is a polygon model, it resides the `Model` namespace (`EPPZ.Geometry.Model` actually). Whether it is a source component for polygon, it resides in the `Source` namespace. It becomes nicely readable, as you declare polygons like `Model.Polygon`, or reference polygon sources as `Source.Polygon`. 92 | 93 | > In addition, every class is **namespaced in the folder** it resides. If you look at a folder name, you can tell that classes are namespaced to the same as the folder name. 94 | 95 | ## Add-ons 96 | 97 | * [`ClipperAddOns`](AddOns/ClipperAddOns.cs) 98 | 99 | + Mainly `Polygon` extensions for easy conversion between **eppz! Geometry** and [Clipper](https://github.com/eppz/Clipper). It has a method to convert from generic `Vector2[]` array. **[Clipper](https://github.com/eppz/Clipper) works with integers**. So conversion involves a scale up (and a scale down), thus you'll need to pass a scale value to Clipper. (for example **eppz! Geometry** internals use `10e+5f` by default). 100 | + `Polygon PolygonFromClipperPaths(Paths paths, float scale)` 101 | + `Polygon PolygonFromClipperPath(Path path, float scale)` 102 | + `Paths ClipperPaths(this Polygon this_, float scale)` 103 | + `Path ClipperPath(this Polygon this_, float scale)` 104 | + `Vector2[] PointsFromClipperPath(Path path, float scale)` 105 | 106 | * [`TriangleNetAddOns`](AddOns/TriangleNetAddOns.cs) 107 | 108 | + Bridges the gap between library `Model.Polygon` objects and `Triangle.NET` models (meshes, voronoi diagrams). 109 | + `TriangleNet.Geometry.Polygon TriangleNetPolygon(this Polygon this_)` 110 | + `Rect Bounds(this TriangleNet.Voronoi.Legacy.SimpleVoronoi this_)` 111 | + `Paths ClipperPathsFromVoronoiRegions(List voronoiRegions, float scale = 1.0f)` 112 | + `Vector2 VectorFromPoint(TriangleNet.Geometry.Point point)` 113 | + `Vector2[] PointsFromVertices(ICollection vertices)` 114 | 115 | * [`UnityEngineAddOns`](AddOns/UnityEngineAddOns.cs) 116 | 117 | + Contains a single `Model.Polygon` (yet enormously useful) extension that triangulates the corresponding polygon, and hooks up the result into a `UnityEngine.MeshFilter` component. This is the core functionality embedded into `Source.Mesh` component (see example scene [Polygon triangulation](Scenes/README.md/#11-polygon-triangulation) for more). 118 | + `UnityEngine.Mesh Mesh(this EPPZ.Geometry.Model.Polygon this_, string name = "")` 119 | + `UnityEngine.Mesh Mesh(this EPPZ.Geometry.Model.Polygon this_, TriangulatorType triangulator, string name = "")` 120 | + `UnityEngine.Mesh Mesh(this EPPZ.Geometry.Model.Polygon this_, Color color, TriangulatorType triangulator, string name = "")` 121 | 122 | ## License 123 | 124 | > Licensed under the [**MIT License**](https://en.wikipedia.org/wiki/MIT_License). 125 | -------------------------------------------------------------------------------- /Scenes/README.md: -------------------------------------------------------------------------------- 1 | # [eppz! `Geometry`](https://github.com/eppz/Unity.Library.eppz,Geometry) 2 | > part of [**Unity.Library.eppz**](https://github.com/eppz/Unity.Library.eppz) 3 | 4 | ## Test scenes 5 | 6 | + [Polygon-Point containment](#0-polygon-point-containment) 7 | + [Polygon-Segment intersection test](#1-polygon-segment-intersection) 8 | + [Polygon permiter-Point containment (Precise)](#2-polygon-permiter-point-containment-precise) 9 | + [Polygon permiter-Point containment (Default)](#3-polygon-permiter-point-containment-default) 10 | + [Polygon-Segment containment](#4-polygon-segment-containment) 11 | + [Polygon-Polygon containment](#5-polygon-polygon-containment) 12 | + [Vertex facing](#6-vertex-facing) 13 | + [Polygon area, Polygon winding](#7-polygon-area-polygon-winding) 14 | + [Segment-Segment intersection point](#8-segment-segment-intersection-point) 15 | + [Polygon offset](#9-polygon-offset) 16 | + [Multiple polygon centroid](#10-multiple-polygon-centroid) 17 | + [Polygon triangulation](#11-polygon-triangulation) 18 | 19 | ![Unity.Library.eppz.Geometry.Model.Poygon.Mesh.Triangulation](https://github.com/eppz/Unity.Library.eppz.Geometry/raw/Documentation/Documentation/Unity.Library.eppz.Geometry.Model.Poygon.Mesh.Triangulation.gif) 20 | 21 | These test scenes are designed to experience / proof the **eppz! Geometry** library features. Hit play, then manipulate the geometry in Scene window while in game mode (watch out to move the points directly instead their parent container). Every relevant code is in the corresponding `Controller_#.cs`, so you can see **how to use the API**. 22 | 23 | You can define a polygon with simple `Vector2[]` array, but for sake of simplicity, test scenes uses some **polygon sourcing helper classes** ([`Components.PolygonSource`](../Components/PolygonSource.cs)) those take simple `GameObject` transforms as input. They also keep the polygon models updated on `GameObject` changes. 24 | 25 | Another helper objects are **polygon line renderers** ([`Lines.PolygonLineRenderer`](../Lines/PolygonLineRenderer.cs)). These renderers are [`DirectLineRenderer`](https://github.com/eppz/Unity.Library.eppz.Lines/blob/master/DirectLineRenderer.cs) using fellow library [eppz! Lines](https://github.com/eppz/Unity.Library.eppz.Lines). 26 | 27 | Beside these helper classes, you can easily construct `Polygon` / `Segment` instances using simple `Vector2` inputs as well. Having these test scenes, you can easily provision the mechanism of each geometry feature even with your own polygons. 28 | 29 | ## 0. Polygon-Point containment 30 | 31 | The star polygon drawn yellow when it contains all three points. 32 | 33 | + When points appear to be on a polygon edge, test will return false 34 | + When point is at a polygon vertex, test will return false 35 | 36 | ```C# 37 | bool test = polygon.ContainsPoint(point); 38 | ``` 39 | See [`Controller_0.cs`](Controllers/Controller_0.cs) for the full script context. 40 | 41 | ## 1. Polygon-Segment intersection 42 | 43 | The star polygon drawn yellow when any of the two segments intersects any polygon edge. 44 | 45 | + Returns false when a segment endpoint appears to be on a polygon edge 46 | + Returns false when a segment endpoint is at a polygon vertex 47 | 48 | ```C# 49 | bool test = polygon.IsIntersectingWithSegment(segment); 50 | ``` 51 | See [`Controller_1.cs`](Controllers/Controller_1.cs) for the full script context. 52 | 53 | ## 2. Polygon permiter-Point containment (Precise) 54 | 55 | The star polygon drawn yellow when the point is contained by the polygon permiter. Accuracy means the line width of the polygon permiter (is `1.0f` by default). 56 | 57 | + Returns true even if the point appears to be on a polygon edge 58 | + Returns true even if the point is at a polygon vertex 59 | 60 | ```C# 61 | bool test = polygon.PermiterContainsPoint(point, accuracy, Segment.ContainmentMethod.Precise); 62 | ``` 63 | See [`Controller_2.cs`](Controllers/Controller_2.cs) for the full script context. 64 | 65 | **Points contained by a segment** (even edge or polygon permiter) should be calculated with a given **accuracy**. This accuracy is set to `1e-6f` by default, but **can be set to any value** per each containment test (like above). 66 | 67 | Point containment tests has two **containment method**, `ContainmentMethod.Default` and `ContainmentMethod.Precise`. The former is less computation intensive than the latter. Depending on your ue case, you may trade precision over performance. The figure below summarizes the dissimilarities of the two method. 68 | 69 | ![Unity.Library.eppz.Geometry.Segment.ContainsPoint.ContainmentMethod](https://github.com/eppz/Unity.Library.eppz.Geometry/raw/Documentation/Documentation/Unity.Library.eppz.Geometry.Segment.ContainsPoint.ContainmentMethod.png) 70 | 71 | ## 3. Polygon permiter-Point containment (Default) 72 | 73 | Actually the same as before, but a smaller accuracy is given (`0.1f`). The star polygon drawn yellow when the point appears to be on any polygon edge of at a polygon vertex. 74 | 75 | + Returns true even if the point appears to be on a polygon edge 76 | + Returns true even if the point is at a polygon vertex 77 | 78 | ```C# 79 | float accuracy = 0.1f; 80 | bool test = polygon.PermiterContainsPoint(point, accuracy); 81 | ``` 82 | See [`Controller_3.cs`](Controllers/Controller_3.cs) for the full script context. 83 | 84 | ## 4. Polygon-Segment containment 85 | 86 | The star drawn yellow when it contains both edge. This is a compund test of polygon-point containment, polygon permiter-point containment, polygon-segment intersection. 87 | 88 | + Returns true even if the point appears to be on a polygon edge (thanks to permiter test) 89 | + Returns true even if the point is at a polygon vertex (thanks to permiter test) 90 | 91 | See [`Controller_4.cs`](Controllers/Controller_4.cs) for the full script context. 92 | 93 | ## 5. Polygon-Polygon containment 94 | 95 | The star drawn yellow when it contain the rectangular polygon. This is also a compund test of polygon-point containment, polygon-segment intersection, polygon permiter-point containment. 96 | 97 | A polygon contains another polygon, when 98 | + other polygon vertices are contained by polygon 99 | + other polygon segments are not intersecting with polygon 100 | + other polygon vertices are not contained by polygon permiter 101 | 102 | See [`Controller_5.cs`](Controllers/Controller_5.cs) for the full script context. 103 | 104 | ## 6. Vertex facing 105 | 106 | The segments in ths example can think of imaginary polygon edges. The corner vertex normal segment drawn yellow when it faces inward the imaginary polygon, drawn white when facing outward. 107 | 108 | It uses `Segment.IsPointLeft()` to create a compund test with both segments. It full calculation goes like below. 109 | 110 | The two segments encompasses an acute angle if 111 | + the endpoint of the second segment lies on the left of the first segment 112 | 113 | The vertex normal facing outward if 114 | + the neighbouring segment encompasses an acute angle 115 | + and the normal point lies on the left of both segments 116 | + or the neighbouring segments encompass an obtuse angle 117 | + and the normal point lies on the left of one of the segments 118 | 119 | See [`Controller_6.cs`](Controllers/Controller_6.cs) for the full script context. 120 | 121 | ## 7. Polygon area, Polygon winding 122 | 123 | The winding direction of a polygon comes to a good use when you want to validate the result of further polygon operations. The `winding` property of each `Polygon` instance gets calculated at construction time, and each time its topology gets updated (using `UpdatePointPositionsWithSource()`, `UpdatePointPositionsWithTransforms()`, `Scale()`, `Translate()`), or you can invoke `Calculate()` directly if you manipulated underlying point models directly. 124 | 125 | In this scene you can see how area and winding of a polygon gets calculated. Just hit play and nudge some points around. 126 | 127 | ```C# 128 | // After a polygon constructed, you can simply access values. 129 | float area = polygon.area; 130 | bool isCW = polygon.isCW; 131 | ``` 132 | 133 | See [`Model/Polygon.cs`](Model/Polygon.cs) source for the details. 134 | 135 | ## 8. Segment-Segment intersection point 136 | 137 | Segment intersection has two parts actually. Get the **intersection point of the lines** defined by the segment, then look up if the point **resides on the segments**. 138 | 139 | The first part has implemented as a generic `Geometry.IntersectionOfSegments()`. 140 | 141 | The second part gets more tricky, uses `accuracy` like many tests above. Checks if bounds are overlap, after that it uses the segment-point containment for the endpoints, then checks if the segments has intersection point at all (using winding tests), then returns with the intersection point of lines. 142 | 143 | > To avoid redundant test method calls, the method follows API style of `Physics.Raycast`, where you can query if there is intersection at all, then use point only if any. 144 | 145 | ```C# 146 | // Output will have non-zero value only on having a valid intersection. 147 | Vector2 intersectionPoint; 148 | bool isIntersecting = a.IntersectionWithSegment(b, out intersectionPoint); 149 | ``` 150 | 151 | See [`Controller_8.cs`](Controllers/Controller_8.cs) for the full script context. 152 | 153 | ## 9. Polygon offset 154 | 155 | Robust polygon offset (also known as polygon outline / polygon buffer) solution (using [Clipper](https://github.com/eppz/Clipper) by Angus Johnson). 156 | 157 | ```C# 158 | float offset = 0.2f; 159 | Polygon offsetPolygon = polygon.OffsetPolygon(offset); 160 | ``` 161 | 162 | See [`Controller_9.cs`](Controllers/Controller_9.cs) for the full script context. 163 | 164 | ## 10. Multiple polygon centroid 165 | 166 | You can see how the compound centorid changes as you nudge polygons, vertices around. Algorithm uses [Geometric decomposition](https://en.wikipedia.org/wiki/Centroid#By_geometric_decomposition). 167 | 168 | ```C# 169 | // Calculate compund centroid. 170 | centroid.position = Geometry.CentroidOfPolygons(polygons)); 171 | ``` 172 | See [`Controller_10.cs`](Controllers/Controller_10.cs) for the full script context. 173 | 174 | ## 11. Polygon triangulation 175 | 176 | This scene uses a `Source.Mesh` component to simply **triangluate a polygon**. If both `Source.Polygon` and `UnityEngine.MeshFilter` component is present on a `GameObject`, you can use this setup. It uses an extension method `Polygon.Mesh()` that hooks up `Triangle.NET` mesh output into a `UnityEngine.MeshFilter` (with some additional issue resolved regarding self intersecting polygons). 177 | 178 | ```C# 179 | // Assign trianglated mesh. 180 | meshFilter.mesh = polygon.Mesh(color, triangulator); 181 | ``` 182 | See [`Source/Mesh.cs`](Source/Mesh.cs) source for the details. 183 | 184 | ## License 185 | 186 | > Licensed under the [**MIT License**](https://en.wikipedia.org/wiki/MIT_License). -------------------------------------------------------------------------------- /Model/Segment.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | 12 | 13 | namespace EPPZ.Geometry.Model 14 | { 15 | 16 | 17 | public class Segment 18 | { 19 | 20 | 21 | static public float defaultAccuracy = 1e-6f; 22 | 23 | public enum ContainmentMethod { Default, Precise } 24 | static public ContainmentMethod defaultContainmentMethod = ContainmentMethod.Default; 25 | 26 | private Vector2 _a; 27 | public virtual Vector2 a 28 | { 29 | get { return _a; } 30 | set { _a = value; } 31 | } 32 | private Vector2 _b; 33 | public virtual Vector2 b 34 | { 35 | get { return _b; } 36 | set { _b = value; } 37 | } 38 | 39 | #region Calculations 40 | 41 | // If `alwaysCalculate` is on, every `normal` and `perpendicular` property access invokes recalculation of values based on actual topology. 42 | public bool alwaysCalculate = true; 43 | 44 | private Vector2 _normal; 45 | public Vector2 normal 46 | { 47 | get 48 | { 49 | if (_normal == Vector2.zero || alwaysCalculate) { CalculateNormal(); } // Lazy calculation or force calculate on every access 50 | return _normal; 51 | } 52 | 53 | set 54 | { _normal = value; } 55 | } 56 | 57 | public Vector2 _perpendicular; 58 | public Vector2 perpendicular 59 | { 60 | get 61 | { 62 | if (_perpendicular == Vector2.zero || alwaysCalculate) { CalculatePerpendicular(); } // Lazy calculation or force calculate on every access 63 | return _perpendicular; 64 | } 65 | 66 | set 67 | { _perpendicular = value; } 68 | } 69 | 70 | public void CalculateNormal() 71 | { 72 | _normal = this.perpendicular.normalized; 73 | } 74 | 75 | public void CalculatePerpendicular() 76 | { 77 | Vector2 translated = (this.b - this.a); // Translate to origin 78 | _perpendicular = new Vector2( -translated.y, translated.x); // Rotate CCW 79 | } 80 | 81 | #endregion 82 | 83 | 84 | #region Factories 85 | 86 | public static Segment SegmentWithSource(Source.Segment segmentSource) 87 | { 88 | return Segment.SegmentWithPointTransforms(segmentSource.points, segmentSource.coordinates); 89 | } 90 | 91 | public static Segment SegmentWithPointTransforms(Transform[] pointTransforms, Source.Segment.Coordinates coordinates = Source.Segment.Coordinates.World) // Uses Transform.localPosition.xy() 92 | { 93 | if (coordinates == Source.Segment.Coordinates.World) 94 | { return Segment.SegmentWithPoints(pointTransforms[0].position, pointTransforms[1].position); } 95 | 96 | // Source.Segment.Coordinates.Local 97 | return Segment.SegmentWithPoints(pointTransforms[0].localPosition, pointTransforms[1].localPosition); 98 | } 99 | 100 | public static Segment SegmentWithPoints(Vector2 a_, Vector2 b_) 101 | { 102 | Segment instance = new Segment(); 103 | instance.a = a_; 104 | instance.b = b_; 105 | return instance; 106 | } 107 | 108 | #endregion 109 | 110 | 111 | #region Model updates 112 | 113 | public void UpdateWithSource(Source.Segment segmentSource) // Assuming unchanged point count 114 | { 115 | UpdateWithTransforms(segmentSource.points, segmentSource.coordinates); 116 | } 117 | 118 | public void UpdateWithTransforms(Transform[] pointTransforms, Source.Segment.Coordinates coordinates = Source.Segment.Coordinates.World) // Assuming unchanged point count 119 | { 120 | if (coordinates == Source.Segment.Coordinates.World) 121 | { 122 | a = pointTransforms[0].position; 123 | b = pointTransforms[1].position; 124 | return; 125 | } 126 | 127 | // Source.Segment.Coordinates.Local 128 | a = pointTransforms[0].localPosition; 129 | b = pointTransforms[1].localPosition; 130 | } 131 | 132 | #endregion 133 | 134 | 135 | #region Accessors 136 | 137 | public Rect bounds // Readonly 138 | { 139 | get 140 | { 141 | Rect bounds_ = new Rect(); 142 | 143 | // Set bounds. 144 | bounds_.xMin = Mathf.Min(a.x, b.x); 145 | bounds_.xMax = Mathf.Max(a.x, b.x); 146 | bounds_.yMin = Mathf.Min(a.y, b.y); 147 | bounds_.yMax = Mathf.Max(a.y, b.y); 148 | 149 | return bounds_; 150 | } 151 | } 152 | 153 | public Rect ExpandedBounds(float accuracy) 154 | { 155 | float treshold = accuracy / 2.0f; 156 | Rect bounds_ = this.bounds; 157 | return Rect.MinMaxRect( 158 | bounds_.xMin - treshold, 159 | bounds_.yMin - treshold, 160 | bounds_.xMax + treshold, 161 | bounds_.yMax + treshold); 162 | } 163 | 164 | public bool ContainsPoint(Vector2 point) 165 | { return ContainsPoint(point, defaultAccuracy); } 166 | 167 | public bool ContainsPoint(Vector2 point, float accuracy) 168 | { return ContainsPoint(point, accuracy, ContainmentMethod.Default); } 169 | 170 | public bool IsPointLeft(Vector2 point) 171 | { return Geometry.PointIsLeftOfSegment(point, this.a, this.b); } 172 | 173 | public bool ContainsPoint(Vector2 point, float accuracy, ContainmentMethod containmentMethod) 174 | { 175 | float treshold = accuracy / 2.0f; 176 | 177 | // Expanded bounds containment test. 178 | Rect expandedBounds = this.ExpandedBounds(accuracy); 179 | bool expandedBoundsContainment = expandedBounds.Contains(point); 180 | if (expandedBoundsContainment == false) return false; // Only if passed 181 | 182 | // Line distance test. 183 | float distance = this.DistanceToPoint(point); 184 | bool lineDistanceTest = distance < treshold; 185 | if (lineDistanceTest == false) return false; // Only if passed 186 | 187 | if (containmentMethod == ContainmentMethod.Precise) 188 | { 189 | // Perpendicular segment. 190 | Vector2 normalizedHalf = (this.b - this.a) / 2.0f; 191 | float halfLength = normalizedHalf.magnitude; 192 | Vector2 normalizedHalfPerpendicular = new Vector2( -normalizedHalf.y, normalizedHalf.x ); 193 | Vector2 perpendicular_a = this.a + normalizedHalf; 194 | Vector2 perpendicular_b = this.a + normalizedHalf + normalizedHalfPerpendicular; 195 | 196 | // Perpendicular line distance test. 197 | float perpendicularDistance = Geometry.PointDistanceFromLine(point, perpendicular_a, perpendicular_b); 198 | bool perpendicularDistanceTest = perpendicularDistance < halfLength; 199 | 200 | // Endpoint distance test if previous failed. 201 | if (perpendicularDistanceTest == false) 202 | { 203 | float distanceFromEndPoints = Mathf.Min( Vector2.Distance(this.a, point), Vector2.Distance(this.b, point) ); 204 | bool endpointDistanceTest = distanceFromEndPoints < treshold; 205 | if (endpointDistanceTest == false) return false; // Only if passed 206 | } 207 | } 208 | 209 | // All passed. 210 | return true; 211 | } 212 | 213 | #endregion 214 | 215 | 216 | #region Geometry features 217 | 218 | /// 219 | /// True when the two segments are intersecting. Not true when endpoints 220 | /// are equal, nor when a point is contained by other segment. 221 | /// Can say this algorithm has infinite precision. 222 | /// 223 | public bool IsIntersectingWithSegment(Segment segment) 224 | { 225 | // No intersecting if bounds don't even overlap (slight optimization). 226 | bool boundsOverlaps = this.bounds.Overlaps(segment.bounds); 227 | if (boundsOverlaps == false) return false; 228 | 229 | // Do the Bryce Boe test. 230 | return Geometry.AreSegmentsIntersecting(this.a, this.b, segment.a, segment.b); 231 | } 232 | 233 | /// 234 | /// Returns intersection when the two segments are intersecting. Not returns anything when endpoints 235 | /// are equal, nor when a point is contained by other segment. 236 | /// Can say this algorithm has infinite precision. 237 | /// 238 | public bool IntersectionWithSegment(Segment segment, out Vector2 intersectionPoint) 239 | { return IntersectionWithSegmentWithAccuracy(segment, 0.0f, out intersectionPoint); } 240 | 241 | public bool IntersectionWithSegmentWithAccuracy(Segment segment, float accuracy, out Vector2 intersectionPoint) 242 | { return IntersectionWithSegmentWithAccuracy(segment, accuracy, defaultContainmentMethod, out intersectionPoint); } 243 | 244 | public bool IntersectionWithSegmentWithAccuracy(Segment segment, ContainmentMethod containmentMethod, out Vector2 intersectionPoint) 245 | { return IntersectionWithSegmentWithAccuracy(segment, defaultAccuracy, containmentMethod, out intersectionPoint); } 246 | 247 | public bool IntersectionWithSegmentWithAccuracy(Segment segment, float accuracy, ContainmentMethod containmentMethod, out Vector2 intersectionPoint) 248 | { 249 | intersectionPoint = Vector2.zero; // Default 250 | 251 | // No intersecting if bounds don't even overlap. 252 | Rect expandedBounds = this.ExpandedBounds(accuracy); 253 | Rect otherExpandedBounds = segment.ExpandedBounds(accuracy); 254 | bool boundsOverlaps = expandedBounds.Overlaps(otherExpandedBounds); 255 | if (boundsOverlaps == false) 256 | { 257 | return false; // No intersection 258 | } 259 | 260 | if (accuracy > 0.0f) // Only any accuracy is given 261 | { 262 | // Look up point containments. 263 | bool containsA = this.ContainsPoint (segment.a, accuracy, containmentMethod); 264 | if (containsA) 265 | { 266 | intersectionPoint = segment.a; 267 | return true; // Intersecting 268 | } 269 | 270 | bool containsB = this.ContainsPoint (segment.b, accuracy, containmentMethod); 271 | if (containsB) 272 | { 273 | intersectionPoint = segment.b; 274 | return true; // Intersecting 275 | } 276 | 277 | bool otherContainsA = segment.ContainsPoint (this.a, accuracy, containmentMethod); 278 | if (otherContainsA) 279 | { 280 | intersectionPoint = this.a; 281 | return true; // Intersecting 282 | } 283 | 284 | bool otherContainsB = segment.ContainsPoint (this.b, accuracy, containmentMethod); 285 | if (otherContainsB) 286 | { 287 | intersectionPoint = this.b; 288 | return true; // Intersecting 289 | } 290 | } 291 | 292 | // Do the Bryce Boe test. 293 | bool isIntersecting = Geometry.AreSegmentsIntersecting(this.a, this.b, segment.a, segment.b); 294 | if (isIntersecting == false) 295 | { 296 | return false; // No intersection 297 | } 298 | 299 | // All fine, intersection point can be determined. 300 | intersectionPoint = Geometry.IntersectionPointOfLines(this.a, this.b, segment.a, segment.b); // Actually the intersection of lines defined by segments 301 | return true; // Intersecting 302 | } 303 | 304 | public float DistanceToPoint(Vector2 point_) 305 | { 306 | return Geometry.PointDistanceFromLine(point_, this.a, this.b); 307 | } 308 | 309 | #endregion 310 | 311 | 312 | } 313 | } -------------------------------------------------------------------------------- /Model/Polygon.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Geri Borbás http://www.twitter.com/_eppz 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 | // 8 | using UnityEngine; 9 | using System; 10 | using System.Collections; 11 | using System.Collections.Generic; 12 | using System.Linq; 13 | 14 | 15 | namespace EPPZ.Geometry.Model 16 | { 17 | 18 | 19 | using ClipperLib; 20 | using Path = List; 21 | using Paths = List>; 22 | 23 | 24 | public class Polygon 25 | { 26 | 27 | 28 | // Identifiers. 29 | public int index; 30 | public string name; 31 | 32 | // Windings. 33 | public bool isCW { get { return (Mathf.Sign(_area) < 0.0f); } } 34 | public bool isCCW { get { return (Mathf.Sign(_area) > 0.0f); } } 35 | public enum Winding { CCW, CW }; 36 | public Winding winding { get { return (isCCW) ? Winding.CCW : Winding.CW; } } 37 | 38 | /// 39 | /// For internal use. 40 | /// Edge, Vertex class can read from this directly 41 | /// Debug renderers can access raw points during development 42 | /// From the outside, use vertices, edges only, or enumerators 43 | /// 44 | private Vector2[] _points; 45 | public Vector2[] points { get { return _points; } } // Readonly 46 | 47 | public Vertex[] vertices; // Vertices of this polygon (excluding sub polygon vertices) 48 | public Edge[] edges; // Edges of this polygon (excluding sub polygon edges) 49 | private List polygons = new List(); // Sub-polygons (if any) 50 | 51 | private Rect _bounds = new Rect(); 52 | public Rect bounds { get { return _bounds; } } 53 | 54 | private float _area = 0.0f; 55 | public float area { get { return _area; } } 56 | 57 | // Yet for single polygons only (see centroid of compound polygons). 58 | private Vector2 _centroid; 59 | public Vector2 centroid { get { return _centroid; } } 60 | 61 | 62 | #region Factories 63 | 64 | public static Polygon PolygonWithPointList(List pointList) 65 | { return Polygon.PolygonWithPoints(pointList.ToArray()); } 66 | 67 | public static Polygon PolygonWithSource(Source.Polygon polygonSource) 68 | { 69 | Polygon rootPolygon = Polygon.PolygonWithPointTransforms(polygonSource.points, polygonSource.coordinates); 70 | 71 | // Collect sub-polygons if any. 72 | foreach (Transform eachChildTransform in polygonSource.gameObject.transform) 73 | { 74 | GameObject eachChildGameObject = eachChildTransform.gameObject; 75 | Source.Polygon eachChildPolygonSource = eachChildGameObject.GetComponent(); 76 | if (eachChildPolygonSource != null) 77 | { 78 | Polygon eachSubPolygon = Polygon.PolygonWithSource(eachChildPolygonSource); 79 | rootPolygon.AddPolygon(eachSubPolygon); 80 | } 81 | } 82 | 83 | return rootPolygon; 84 | } 85 | 86 | public Polygon Copy() 87 | { return Polygon.PolygonWithPolygon(this); } 88 | 89 | public static Polygon PolygonWithPolygon(Polygon polygon) 90 | { 91 | Polygon rootPolygon = null; 92 | 93 | // Compose with sub-olygons (if any). 94 | polygon.EnumeratePolygons((Polygon eachPolygon) => 95 | { 96 | if (rootPolygon == null) 97 | { rootPolygon = Polygon.PolygonWithPoints(eachPolygon.points); } 98 | else 99 | { rootPolygon.AddPolygon(Polygon.PolygonWithPoints(eachPolygon.points)); } 100 | }); 101 | 102 | return rootPolygon; 103 | } 104 | 105 | public static Polygon PolygonWithPointTransforms(Transform[] pointTransforms, Source.Polygon.Coordinates coordinates) 106 | { 107 | // Create points array. 108 | Vector2[] points = new Vector2[pointTransforms.Length]; 109 | for (int index = 0; index < pointTransforms.Length; index++) 110 | { 111 | Transform eachPointTransform = pointTransforms[index]; 112 | 113 | if (coordinates == Source.Polygon.Coordinates.World) 114 | { points[index] = eachPointTransform.position.xy(); } 115 | 116 | if (coordinates == Source.Polygon.Coordinates.Local) 117 | { points[index] = eachPointTransform.localPosition.xy(); } 118 | } 119 | 120 | return Polygon.PolygonWithPoints(points); 121 | } 122 | 123 | public static Polygon PolygonWithPoints(Vector2[] points) 124 | { return PolygonWithPoints(points, 0.0f); } 125 | 126 | public static Polygon PolygonWithPoints(Vector2[] points, float angle) 127 | { 128 | Polygon polygon = new Polygon(points.Length); 129 | 130 | // Create points (copy actually). 131 | for (int index = 0; index < points.Length; index++) 132 | { 133 | if (angle == 0.0f) 134 | { polygon._points[index] = points[index]; } 135 | else 136 | { polygon._points[index] = points[index].Rotated(angle); } 137 | } 138 | 139 | // Polygon calculations. 140 | polygon.Calculate(); 141 | 142 | // Create members. 143 | polygon.CreateVerticesFromPoints(); 144 | polygon.CreateEdgesConnectingPoints(); 145 | 146 | return polygon; 147 | } 148 | 149 | public Polygon(int pointCount = 1) 150 | { 151 | this._points = new Vector2[pointCount]; 152 | this.vertices = new Vertex[pointCount]; 153 | this.edges = new Edge[pointCount]; 154 | } 155 | 156 | #endregion 157 | 158 | 159 | #region Model updates 160 | 161 | public void UpdatePointPositionsWithSource(Source.Polygon polygonSource) // Assuming unchanged point count 162 | { 163 | UpdatePointPositionsWithTransforms(polygonSource.points, polygonSource.coordinates); 164 | 165 | // Update sub-polygons if any. 166 | foreach (Transform eachChildTransform in polygonSource.gameObject.transform) 167 | { 168 | GameObject eachChildGameObject = eachChildTransform.gameObject; 169 | Source.Polygon eachChildPolygonSource = eachChildGameObject.GetComponent(); 170 | if (eachChildPolygonSource != null) 171 | { 172 | eachChildPolygonSource.polygon.UpdatePointPositionsWithTransforms(eachChildPolygonSource.points, eachChildPolygonSource.coordinates); 173 | } 174 | } 175 | } 176 | 177 | public void UpdatePointPositionsWithTransforms(Transform[] pointTransforms, Source.Polygon.Coordinates coordinates) // Assuming unchanged point count 178 | { 179 | for (int index = 0; index < pointTransforms.Length; index++) 180 | { 181 | Transform eachPointTransform = pointTransforms[index]; 182 | 183 | if (coordinates == Source.Polygon.Coordinates.World) 184 | { _points[index] = eachPointTransform.position.xy(); } 185 | 186 | if (coordinates == Source.Polygon.Coordinates.Local) 187 | { _points[index] = eachPointTransform.localPosition.xy(); } 188 | } 189 | 190 | // Polygon calculations. 191 | Calculate(); 192 | } 193 | 194 | public void AddPolygon(Polygon polygon) 195 | { 196 | polygons.Add(polygon); 197 | 198 | // Polygon calculations. 199 | Calculate(); 200 | } 201 | 202 | #endregion 203 | 204 | 205 | #region Accessors 206 | 207 | public int pointCount { get { return _points.Length; } } // Readonly 208 | public int vertexCount { get { return vertices.Length; } } // Readonly 209 | public int edgeCount { get { return edges.Length; } } // Readonly 210 | public int polygonCount { get { return polygons.Count; } } // Readonly 211 | public int pointCountRecursive 212 | { 213 | get 214 | { 215 | int pointCountRecursive = pointCount; 216 | foreach (Polygon eachPolygon in polygons) 217 | { 218 | pointCountRecursive += eachPolygon.pointCount; 219 | } 220 | return pointCountRecursive; 221 | } 222 | } 223 | 224 | #endregion 225 | 226 | 227 | #region Enumerators 228 | 229 | public void EnumeratePoints(Action action) 230 | { 231 | // Enumerate local points. 232 | foreach (Vector2 eachPoint in _points) 233 | { 234 | action(eachPoint); 235 | } 236 | } 237 | 238 | public void EnumerateVertices(Action action) 239 | { 240 | // Enumerate local points. 241 | foreach (Vertex eachVertex in vertices) 242 | { 243 | action(eachVertex); 244 | } 245 | } 246 | 247 | public void EnumerateEdges(Action action) 248 | { 249 | // Enumerate local points. 250 | foreach (Edge eachEdge in edges) 251 | { 252 | action(eachEdge); 253 | } 254 | } 255 | 256 | public void EnumeratePointsRecursive(Action action) 257 | { 258 | // Enumerate local points. 259 | foreach (Vector2 eachPoint in _points) 260 | { 261 | action(eachPoint); 262 | } 263 | 264 | // Enumerate each sub-polygon points. 265 | foreach (Polygon eachPolygon in polygons) 266 | { 267 | eachPolygon.EnumeratePointsRecursive((Vector2 eachPoint_) => 268 | { 269 | action(eachPoint_); 270 | }); 271 | } 272 | } 273 | 274 | public void EnumerateVerticesRecursive(Action action) 275 | { 276 | // Enumerate local points. 277 | foreach (Vertex eachVertex in vertices) 278 | { 279 | action(eachVertex); 280 | } 281 | 282 | // Enumerate each sub-polygon points. 283 | foreach (Polygon eachPolygon in polygons) 284 | { 285 | eachPolygon.EnumerateVerticesRecursive((Vertex eachVertex_) => 286 | { 287 | action(eachVertex_); 288 | }); 289 | } 290 | } 291 | 292 | public void EnumerateEdgesRecursive(Action action) 293 | { 294 | // Enumerate local points. 295 | foreach (Edge eachEdge in edges) 296 | { 297 | action(eachEdge); 298 | } 299 | 300 | // Enumerate each sub-polygon points. 301 | foreach (Polygon eachPolygon in polygons) 302 | { 303 | eachPolygon.EnumerateEdgesRecursive((Edge eachEdge_) => 304 | { 305 | action(eachEdge_); 306 | }); 307 | } 308 | } 309 | 310 | public void EnumeratePolygons(Action action) 311 | { 312 | action(this); // Including this (a bit unexpected) 313 | 314 | // Enumerate sub-polygons. 315 | foreach (Polygon eachPolygon in polygons) 316 | { 317 | action(eachPolygon); 318 | } 319 | } 320 | 321 | #endregion 322 | 323 | 324 | #region Polygon calculations 325 | 326 | public void Calculate() 327 | { 328 | _CalculateBounds(); 329 | _CalculateArea(); 330 | _CalculateCentroid(); 331 | } 332 | 333 | void _CalculateBounds() 334 | { 335 | float left = float.MaxValue; // Out in the right 336 | float right = float.MinValue; // Out in the left 337 | float top = float.MinValue; // Out in the bottom 338 | float bottom = float.MaxValue; // Out in the top 339 | 340 | // Enumerate points. 341 | EnumeratePointsRecursive((Vector2 eachPoint) => 342 | { 343 | // Track bounds. 344 | if (eachPoint.x < left) left = eachPoint.x; // Seek leftmost 345 | if (eachPoint.x > right) right = eachPoint.x; // Seek rightmost 346 | if (eachPoint.y < bottom) bottom = eachPoint.y; // Seek bottommost 347 | if (eachPoint.y > top) top = eachPoint.y; // Seek topmost 348 | }); 349 | 350 | // Set bounds. 351 | _bounds.xMin = left; 352 | _bounds.yMin = bottom; 353 | _bounds.xMax = right; 354 | _bounds.yMax = top; 355 | } 356 | 357 | private void _CalculateArea() 358 | { 359 | 360 | // From https://en.wikipedia.org/wiki/Shoelace_formula 361 | Vector2[] points_ = new Vector2[_points.Length + 1]; 362 | System.Array.Copy(_points, points_, _points.Length); 363 | points_[_points.Length] = _points[0]; 364 | 365 | // Calculate area. 366 | float firstProducts = 0.0f; 367 | float secondProducts = 0.0f; 368 | for (int index = 0; index < points_.Length - 1; index++) 369 | { 370 | Vector2 eachPoint = points_[index]; 371 | Vector2 eachNextPoint = points_[index + 1]; 372 | 373 | firstProducts += eachPoint.x * eachNextPoint.y; 374 | secondProducts += eachPoint.y * eachNextPoint.x; 375 | } 376 | _area = (firstProducts - secondProducts) / 2.0f; 377 | 378 | // Add / Subtract sub-polygon areas. 379 | foreach (Polygon eachPolygon in polygons) 380 | { 381 | // Outer or inner polygon (supposing there is no self-intersection). 382 | _area += eachPolygon.area; 383 | } 384 | } 385 | 386 | private void _CalculateCentroid() 387 | { 388 | // Enumerate points. 389 | float Σx = 0.0f; 390 | float Σy = 0.0f; 391 | EnumeratePoints((Vector2 eachPoint) => 392 | { 393 | Σx += eachPoint.x; 394 | Σy += eachPoint.y; 395 | }); 396 | 397 | // Average. 398 | float x = Σx / pointCount; 399 | float y = Σy / pointCount; 400 | 401 | // Assign. 402 | _centroid = new Vector2(x, y); 403 | } 404 | 405 | private void CreateVerticesFromPoints() 406 | { 407 | // Enumerate points (only for index). 408 | Vertex eachVertex = null; 409 | Vertex eachPreviousVertex = null; 410 | for (int index = 0; index < _points.Length; index++) 411 | { 412 | eachVertex = Vertex.VertexAtIndexInPolygon(index, this); 413 | 414 | // Inject references. 415 | if (eachPreviousVertex != null) 416 | { 417 | eachPreviousVertex.SetNextVertex(eachVertex); 418 | eachVertex.SetPreviousVertex(eachPreviousVertex); 419 | } 420 | 421 | // Collect. 422 | vertices[index] = eachVertex; 423 | 424 | // Track. 425 | eachPreviousVertex = eachVertex; 426 | } 427 | 428 | // Inject last references. 429 | Vertex firstVertex = vertices[0]; 430 | eachVertex.SetNextVertex(firstVertex); 431 | firstVertex.SetPreviousVertex(eachVertex); 432 | } 433 | 434 | void CreateEdgesConnectingPoints() 435 | { 436 | // Enumerate vertices. 437 | Edge eachEdge = null; 438 | Edge eachPreviousEdge = null; 439 | EnumerateVertices((Vertex eachVertex) => 440 | { 441 | int index = eachVertex.index; 442 | eachEdge = Edge.EdgeAtIndexWithVertices(index, eachVertex, eachVertex.nextVertex); 443 | 444 | // Inject references. 445 | if (eachPreviousEdge != null) 446 | { 447 | eachPreviousEdge.SetNextEdge(eachEdge); 448 | eachEdge.SetPreviousEdge(eachPreviousEdge); 449 | } 450 | 451 | // Collect. 452 | edges[index] = eachEdge; 453 | 454 | // Track. 455 | eachPreviousEdge = eachEdge; 456 | }); 457 | 458 | // Inject last references. 459 | Edge firstEdge = edges[0]; 460 | eachEdge.SetNextEdge(firstEdge); 461 | firstEdge.SetPreviousEdge(eachEdge); 462 | 463 | // Inject vertex edge references. 464 | EnumerateEdges((Edge eachEdge_) => 465 | { 466 | eachEdge_.vertexA.SetPreviousEdge(eachEdge_.previousEdge); 467 | eachEdge_.vertexA.SetNextEdge(eachEdge_); 468 | }); 469 | } 470 | 471 | #endregion 472 | 473 | 474 | #region Geometry features 475 | 476 | public bool ContainsPoint(Vector2 point) 477 | { 478 | return Geometry.IsPolygonContainsPoint(this, point); 479 | } 480 | 481 | public bool PermiterContainsPoint(Vector2 point) 482 | { return PermiterContainsPoint(point, Segment.defaultAccuracy); } 483 | 484 | public bool PermiterContainsPoint(Vector2 point, float accuracy) 485 | { return PermiterContainsPoint(point, accuracy, Segment.ContainmentMethod.Default); } 486 | 487 | public bool PermiterContainsPoint(Vector2 point, float accuracy, Segment.ContainmentMethod containmentMethod) 488 | { 489 | bool contains = false; 490 | EnumerateEdgesRecursive ((Edge eachEdge) => 491 | { 492 | contains |= eachEdge.ContainsPoint(point, accuracy, containmentMethod); 493 | }); 494 | 495 | return contains; 496 | } 497 | 498 | public bool IsIntersectingWithSegment(Segment segment) 499 | { 500 | bool isIntersecting = false; 501 | EnumerateEdgesRecursive ((Edge eachEdge) => 502 | { 503 | isIntersecting |= segment.IsIntersectingWithSegment(eachEdge); 504 | }); 505 | 506 | return isIntersecting; 507 | } 508 | 509 | #endregion 510 | 511 | 512 | #region Geometry features (Offset) 513 | 514 | // Clipper precision. 515 | public static float clipperScale = 10e+5f; 516 | public static float clipperArcTolerance = 10e+3f; // 2 magnitude smaller 517 | 518 | // Not simplified, nor rounded. 519 | public Polygon OffsetPolygon(float offset) 520 | { return OffsetPolygon(offset, false, false); } 521 | 522 | // Not simplified. 523 | public Polygon RoundedOffsetPolygon(float offset) 524 | { return OffsetPolygon(offset, false, true); } 525 | 526 | // Full featured. 527 | public Polygon SimplifiedAndRoundedOffsetPolygon(float offset) 528 | { return OffsetPolygon(offset, true, true); } 529 | 530 | Polygon OffsetPolygon(float offset, bool simplify, bool rounded) 531 | { 532 | // Calculate Polygon-Clipper scale. 533 | float maximum = Mathf.Max(bounds.width, bounds.height) + offset * 2.0f + offset; 534 | float maximumScale = (float)Int32.MaxValue / maximum; 535 | float scale = Mathf.Min(clipperScale, maximumScale); 536 | 537 | 538 | // Convert to Clipper. 539 | Paths paths = new Paths(); 540 | { 541 | Path path = new Path(); 542 | EnumeratePoints((Vector2 eachPoint) => 543 | { 544 | path.Add(new IntPoint(eachPoint.x * scale, eachPoint.y * scale)); 545 | }); 546 | paths.Add(path); 547 | } 548 | foreach (Polygon eachPolygon in polygons) 549 | { 550 | Path path = new Path(); 551 | eachPolygon.EnumeratePoints((Vector2 eachPoint) => 552 | { 553 | path.Add(new IntPoint(eachPoint.x * scale, eachPoint.y * scale)); 554 | }); 555 | paths.Add(path); 556 | } 557 | 558 | // Mode. 559 | JoinType joinType = (rounded) ? JoinType.jtRound : JoinType.jtMiter; 560 | 561 | // Clipper offset. 562 | Paths offsetPaths = new Paths(); 563 | ClipperOffset clipperOffset = new ClipperOffset(); 564 | if (rounded) { clipperOffset.ArcTolerance = 0.25 * clipperArcTolerance; } // "The default ArcTolerance is 0.25 units." from http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/Properties/ArcTolerance.htm 565 | clipperOffset.AddPaths(paths, joinType, EndType.etClosedPolygon); 566 | clipperOffset.Execute(ref offsetPaths, (double)offset * scale); 567 | 568 | // Remove self intersections (if requested). 569 | if (simplify) 570 | { offsetPaths = Clipper.SimplifyPolygons(offsetPaths); } 571 | 572 | // Convert from Clipper. 573 | Polygon offsetPolygon = null; 574 | for (int index = 0; index < offsetPaths.Count; index++) 575 | { 576 | Path eachSolutionPath = offsetPaths[index]; 577 | Polygon eachSolutionPolygon = PolygonFromClipperPath(eachSolutionPath, scale); 578 | 579 | if (index == 0) 580 | { 581 | offsetPolygon = Polygon.PolygonWithPoints(eachSolutionPolygon.points); // Copy 582 | } 583 | else 584 | { 585 | offsetPolygon.AddPolygon(eachSolutionPolygon); 586 | } 587 | } 588 | 589 | // Back to Polygon. 590 | return offsetPolygon; 591 | } 592 | 593 | public Polygon UnionPolygon() 594 | { 595 | // Calculate Polygon-Clipper scale. 596 | float maximum = Mathf.Max(bounds.width, bounds.height); 597 | float maximumScale = (float)Int32.MaxValue / maximum; 598 | float scale = Mathf.Min(clipperScale, maximumScale); 599 | 600 | // Convert to Clipper. 601 | Paths subjectPaths = new Paths(); 602 | Paths clipPaths = new Paths(); 603 | { 604 | Path path = new Path(); 605 | EnumeratePoints((Vector2 eachPoint) => 606 | { 607 | path.Add(new IntPoint(eachPoint.x * scale, eachPoint.y * scale)); 608 | }); 609 | subjectPaths.Add(path); 610 | } 611 | foreach (Polygon eachPolygon in polygons) 612 | { 613 | Path path = new Path(); 614 | eachPolygon.EnumeratePoints((Vector2 eachPoint) => 615 | { 616 | path.Add(new IntPoint(eachPoint.x * scale, eachPoint.y * scale)); 617 | }); 618 | clipPaths.Add(path); 619 | } 620 | 621 | // Clipper union. 622 | Paths unionPaths = new Paths(); 623 | Clipper clipper = new Clipper(); 624 | clipper.AddPaths(subjectPaths, PolyType.ptSubject, true); 625 | clipper.AddPaths(clipPaths, PolyType.ptClip, true); 626 | clipper.Execute(ClipType.ctUnion, unionPaths); 627 | 628 | // Remove self intersections. 629 | Paths simplifiedUnionPaths = new Paths(); 630 | simplifiedUnionPaths = Clipper.SimplifyPolygons(unionPaths); 631 | 632 | // Convert from Cipper. 633 | Polygon simplifiedUnionPolygon = null; 634 | for (int index = 0; index < simplifiedUnionPaths.Count; index++) 635 | { 636 | Path eachSolutionPath = simplifiedUnionPaths[index]; 637 | Polygon eachSolutionPolygon = PolygonFromClipperPath(eachSolutionPath, scale); 638 | 639 | if (index == 0) 640 | { 641 | simplifiedUnionPolygon = Polygon.PolygonWithPoints(eachSolutionPolygon.points); // Copy 642 | } 643 | else 644 | { 645 | simplifiedUnionPolygon.AddPolygon(eachSolutionPolygon); 646 | } 647 | } 648 | 649 | // Back to Polygon. 650 | return simplifiedUnionPolygon; 651 | } 652 | 653 | private Polygon PolygonFromClipperPath(Path path, float scale) 654 | { 655 | List points = new List(); 656 | for (int index = path.Count - 1; index >= 0; index--) // Reverse enumeration (to flip normals) 657 | { 658 | IntPoint eachPoint = path[index]; 659 | points.Add(new Vector2(eachPoint.X / scale, eachPoint.Y / scale)); 660 | } 661 | return Polygon.PolygonWithPointList(points); 662 | } 663 | 664 | #endregion 665 | 666 | 667 | #region Geometry features (Transformations) 668 | 669 | public void Reverse() 670 | { 671 | // May be a feature later on (reverse `_points` using `System.Array.Copy()`. 672 | } 673 | 674 | public void AlignCentered() 675 | { 676 | Vector2 originalCenter = bounds.center; 677 | Vector2 offset = -originalCenter; 678 | Translate(offset); 679 | } 680 | 681 | public void Translate(Vector2 translation) 682 | { 683 | // Apply to each point. 684 | for (int index = 0; index < _points.Length; index++) 685 | { 686 | _points[index] += translation; 687 | } 688 | 689 | // Apply to each sub-polygon. 690 | foreach (Polygon eachPolygon in polygons) 691 | { 692 | eachPolygon.Translate(translation); 693 | } 694 | 695 | // Polygon calculations. 696 | Calculate(); 697 | 698 | // Update (bounds). 699 | // _bounds.position += translation; 700 | } 701 | 702 | public void Scale(Vector2 scale) 703 | { 704 | if (scale == Vector2.one) return; // Only if any 705 | 706 | // Apply to each point. 707 | for (int index = 0; index < _points.Length; index++) 708 | { 709 | _points[index].x *= scale.x; 710 | _points[index].y *= scale.y; 711 | } 712 | 713 | // Apply to each sub-polygon. 714 | foreach (Polygon eachPolygon in polygons) 715 | { 716 | eachPolygon.Scale(scale); 717 | } 718 | 719 | // Polygon calculations. 720 | Calculate(); 721 | } 722 | 723 | #endregion 724 | 725 | 726 | } 727 | } 728 | --------------------------------------------------------------------------------