├── README.md
├── UnityGeometryHelper
├── Test
│ ├── App.config
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── Test.csproj
├── UnityGeometryHelper
│ ├── QuaternionUtility.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── UnityGeometryHelper.csproj
│ ├── ConvexAogrithm.cs
│ ├── DuKeyMap.cs
│ ├── Geometric3D.cs
│ └── Geometric.cs
└── UnityGeometryHelper.sln
├── .gitattributes
└── .gitignore
/README.md:
--------------------------------------------------------------------------------
1 | # UnityGeometryHelper
2 | Unity几何综合运算
3 |
4 | #Doc
5 | https://www.showdoc.cc/web/#/109109980843671
6 |
--------------------------------------------------------------------------------
/UnityGeometryHelper/Test/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/UnityGeometryHelper/Test/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using UnityGeometryHelper;
5 |
6 | namespace Test
7 | {
8 | class Program
9 | {
10 | static void Main(string[] args)
11 | {
12 | List points = new List()
13 | {
14 | new Vector3(-8623,0,-11289),
15 | new Vector3(11808,0,-11289),
16 | new Vector3(11808,0,5688),
17 | new Vector3(-8623,0,5688),
18 | new Vector3(-8623,0,5688),
19 | };
20 |
21 | Vector3 checkP = new Vector3(-5836,600,1031);
22 |
23 | Console.WriteLine(Geometric.IsPointInArea(points.ToArray(), checkP));
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/UnityGeometryHelper/UnityGeometryHelper/QuaternionUtility.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace UnityGeometryHelper
4 | {
5 | public class QuaternionUtility
6 | {
7 | public static Quaternion Euler(float x, float y, float z)
8 | {
9 | Quaternion res = new Quaternion()
10 | {
11 | w = cos(x / 2f) * cos(y / 2f) * cos(z / 2f) + sin(x / 2f) * sin(y / 2f) * sin(z / 2f),
12 | x = sin(x / 2f) * cos(y / 2f) * cos(z / 2f) - cos(x / 2f) * sin(y / 2f) * sin(z / 2f),
13 | y = cos(x / 2f) * sin(y / 2f) * cos(z / 2f) + sin(x / 2f) * cos(y / 2f) * sin(z / 2f),
14 | z = cos(x / 2f) * cos(y / 2f) * sin(z / 2f) - sin(x / 2f) * sin(y / 2f) * cos(z / 2f),
15 | };
16 |
17 | return res;
18 | }
19 |
20 | public static Quaternion Axis(Vector3 axis, float angle)
21 | {
22 | var s = sin(angle / 2f);
23 | var c = cos(angle / 2f);
24 |
25 | Quaternion res = new Quaternion()
26 | {
27 | w = c,
28 | x = axis.x * s,
29 | y = axis.y * s,
30 | z = axis.z * s,
31 | };
32 |
33 | return res;
34 | }
35 |
36 | private static float cos(float a)
37 | {
38 | return Mathf.Cos((a / 180) * Mathf.PI);
39 | }
40 |
41 | private static float sin(float a)
42 | {
43 | return Mathf.Sin((a / 180) * Mathf.PI);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/UnityGeometryHelper/Test/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Test")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Test")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("8ab2080f-9b8b-4181-ae3b-51e58a88bf3a")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/UnityGeometryHelper/UnityGeometryHelper.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityGeometryHelper", "UnityGeometryHelper\UnityGeometryHelper.csproj", "{3C633A68-E6A0-4CA5-B423-9C616E34D93A}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{8AB2080F-9B8B-4181-AE3B-51E58A88BF3A}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {3C633A68-E6A0-4CA5-B423-9C616E34D93A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {3C633A68-E6A0-4CA5-B423-9C616E34D93A}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {3C633A68-E6A0-4CA5-B423-9C616E34D93A}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {3C633A68-E6A0-4CA5-B423-9C616E34D93A}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {8AB2080F-9B8B-4181-AE3B-51E58A88BF3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {8AB2080F-9B8B-4181-AE3B-51E58A88BF3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {8AB2080F-9B8B-4181-AE3B-51E58A88BF3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {8AB2080F-9B8B-4181-AE3B-51E58A88BF3A}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/UnityGeometryHelper/UnityGeometryHelper/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("UnityGeometryHelper")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("UnityGeometryHelper")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("3c633a68-e6a0-4ca5-b423-9c616e34d93a")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/UnityGeometryHelper/UnityGeometryHelper/UnityGeometryHelper.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {3C633A68-E6A0-4CA5-B423-9C616E34D93A}
8 | Library
9 | Properties
10 | UnityGeometryHelper
11 | UnityGeometryHelper
12 | v3.5
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | false
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 | false
34 |
35 |
36 |
37 | ..\..\..\ZCN_WiringAlgo_1_0\WiringAlgo_Console\LitJson.dll
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | ..\..\..\ZCN_WiringAlgo_1_0\WiringAlgo_Console\UnityEngine.dll
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
67 |
--------------------------------------------------------------------------------
/UnityGeometryHelper/Test/Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {8AB2080F-9B8B-4181-AE3B-51E58A88BF3A}
8 | Exe
9 | Properties
10 | Test
11 | Test
12 | v4.5.2
13 | 512
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 | ..\..\..\ZCN_WiringAlgo_1_0\WiringAlgo_Console\LitJson.dll
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | ..\..\..\ZCN_WiringAlgo_1_0\WiringAlgo_Console\UnityEngine.dll
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | {3c633a68-e6a0-4ca5-b423-9c616e34d93a}
61 | UnityGeometryHelper
62 |
63 |
64 |
65 |
72 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Microsoft Azure ApplicationInsights config file
170 | ApplicationInsights.config
171 |
172 | # Windows Store app package directory
173 | AppPackages/
174 | BundleArtifacts/
175 |
176 | # Visual Studio cache files
177 | # files ending in .cache can be ignored
178 | *.[Cc]ache
179 | # but keep track of directories ending in .cache
180 | !*.[Cc]ache/
181 |
182 | # Others
183 | ClientBin/
184 | [Ss]tyle[Cc]op.*
185 | ~$*
186 | *~
187 | *.dbmdl
188 | *.dbproj.schemaview
189 | *.pfx
190 | *.publishsettings
191 | node_modules/
192 | orleans.codegen.cs
193 |
194 | # RIA/Silverlight projects
195 | Generated_Code/
196 |
197 | # Backup & report files from converting an old project file
198 | # to a newer Visual Studio version. Backup files are not needed,
199 | # because we have git ;-)
200 | _UpgradeReport_Files/
201 | Backup*/
202 | UpgradeLog*.XML
203 | UpgradeLog*.htm
204 |
205 | # SQL Server files
206 | *.mdf
207 | *.ldf
208 |
209 | # Business Intelligence projects
210 | *.rdl.data
211 | *.bim.layout
212 | *.bim_*.settings
213 |
214 | # Microsoft Fakes
215 | FakesAssemblies/
216 |
217 | # GhostDoc plugin setting file
218 | *.GhostDoc.xml
219 |
220 | # Node.js Tools for Visual Studio
221 | .ntvs_analysis.dat
222 |
223 | # Visual Studio 6 build log
224 | *.plg
225 |
226 | # Visual Studio 6 workspace options file
227 | *.opt
228 |
229 | # Visual Studio LightSwitch build output
230 | **/*.HTMLClient/GeneratedArtifacts
231 | **/*.DesktopClient/GeneratedArtifacts
232 | **/*.DesktopClient/ModelManifest.xml
233 | **/*.Server/GeneratedArtifacts
234 | **/*.Server/ModelManifest.xml
235 | _Pvt_Extensions
236 |
237 | # LightSwitch generated files
238 | GeneratedArtifacts/
239 | ModelManifest.xml
240 |
241 | # Paket dependency manager
242 | .paket/paket.exe
243 |
244 | # FAKE - F# Make
245 | .fake/
--------------------------------------------------------------------------------
/UnityGeometryHelper/UnityGeometryHelper/ConvexAogrithm.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using UnityEngine;
4 |
5 | namespace UnityGeometryHelper
6 | {
7 |
8 | internal class ConvexAogrithm
9 | {
10 | private List nodes;
11 | private Stack sortedNodes;
12 | public Vector3[] sor_nodes;
13 |
14 | public ConvexAogrithm(List points)
15 | {
16 | nodes = points;
17 | }
18 |
19 | private double DistanceOfNodes(Vector3 p0, Vector3 p1)
20 | {
21 | return Vector3.Distance(p0, p1);
22 | }
23 |
24 | public void GetNodesByAngle()
25 | {
26 | Vector3 a;
27 | GetNodesByAngle(out a);
28 | }
29 |
30 | public void GetNodesByAngle(out Vector3 p0)
31 | {
32 | LinkedList list_node = new LinkedList();
33 | p0 = GetMinYPoint();
34 | LinkedListNode node = new LinkedListNode(nodes[0]);
35 | list_node.AddFirst(node);
36 | for (int i = 1; i < nodes.Count; i++)
37 | {
38 | int direct = IsClockDirection(p0, node.Value, nodes[i]);
39 | if (direct == 1)
40 | {
41 | list_node.AddLast(nodes[i]);
42 | node = list_node.Last;
43 | //node.Value = nodes[i];
44 |
45 | }
46 | else if (direct == -10)
47 | {
48 | list_node.Last.Value = nodes[i];
49 | //node = list_node.Last
50 | //node.Value = nodes[i];
51 | }
52 | else if (direct == 10)
53 | continue;
54 | else if (direct == -1)
55 | {
56 | LinkedListNode temp = node.Previous;
57 | while (temp != null && IsClockDirection(p0, temp.Value, nodes[i]) == -1)
58 | {
59 | temp = temp.Previous;
60 | }
61 | if (temp == null)
62 | {
63 | list_node.AddFirst(nodes[i]);
64 | continue;
65 | }
66 | if (IsClockDirection(p0, temp.Value, nodes[i]) == -10)
67 | temp.Value = nodes[i];
68 | else if (IsClockDirection(p0, temp.Value, nodes[i]) == 10)
69 | continue;
70 | else
71 | list_node.AddAfter(temp, nodes[i]);
72 | }
73 | }
74 | sor_nodes = list_node.ToArray();
75 | sortedNodes = new Stack();
76 | sortedNodes.Push(p0);
77 | sortedNodes.Push(sor_nodes[0]);
78 | sortedNodes.Push(sor_nodes[1]);
79 | for (int i = 2; i < sor_nodes.Length; i++)
80 | {
81 |
82 | Vector3 p2 = sor_nodes[i];
83 | Vector3 p1 = sortedNodes.Pop();
84 | Vector3 p0_sec = sortedNodes.Pop();
85 | sortedNodes.Push(p0_sec);
86 | sortedNodes.Push(p1);
87 |
88 | if (IsClockDirection1(p0_sec, p1, p2) == 1)
89 | {
90 | sortedNodes.Push(p2);
91 | continue;
92 | }
93 | while (IsClockDirection1(p0_sec, p1, p2) != 1)
94 | {
95 | sortedNodes.Pop();
96 | p1 = sortedNodes.Pop();
97 | p0_sec = sortedNodes.Pop();
98 | sortedNodes.Push(p0_sec);
99 | sortedNodes.Push(p1);
100 | }
101 | sortedNodes.Push(p2);
102 | }
103 |
104 |
105 | }
106 |
107 | private int IsClockDirection1(Vector3 p0, Vector3 p1, Vector3 p2)
108 | {
109 | //Vector3 p0_p1 = new Vector3(p1.x - p0.x, p1.z - p0.z);
110 | Vector3 p0_p1 = new Vector3(p1.x - p0.x, 0, p1.z - p0.z);
111 | Vector3 p0_p2 = new Vector3(p2.x - p0.x, 0, p2.z - p0.z);
112 | return (p0_p1.x * p0_p2.z - p0_p2.x * p0_p1.z) > 0 ? 1 : -1;
113 | }
114 |
115 | private Vector3 GetMinYPoint()
116 | {
117 | Vector3 succNode;
118 | float miny = nodes.Min(r => r.z);
119 | IEnumerable pminYs = nodes.Where(r => r.z == miny);
120 | Vector3[] ps = pminYs.ToArray();
121 | if (pminYs.Count() > 1)
122 | {
123 | //succNode = pminYs.Single(r => r.x == pminYs.Min(t => t.x));//TODO:Linq换一下
124 | succNode = pminYs.First(r => r.x == pminYs.Min(t => t.x));
125 | nodes.Remove(succNode);
126 | return succNode;
127 | }
128 | else
129 | {
130 | nodes.Remove(ps[0]);
131 | return ps[0];
132 | }
133 |
134 | }
135 |
136 | private int IsClockDirection(Vector3 p0, Vector3 p1, Vector3 p2)
137 | {
138 | Vector3 p0_p1 = new Vector3(p1.x - p0.x, 0, p1.z - p0.z);
139 | Vector3 p0_p2 = new Vector3(p2.x - p0.x, 0, p2.z - p0.z);
140 | if ((p0_p1.x * p0_p2.z - p0_p2.x * p0_p1.z) != 0)
141 | return (p0_p1.x * p0_p2.z - p0_p2.x * p0_p1.z) > 0 ? 1 : -1;
142 | else
143 | return DistanceOfNodes(p0, p1) > DistanceOfNodes(p0, p2) ? 10 : -10;
144 |
145 | }
146 |
147 | public Stack SortedNodes
148 | {
149 | get { return sortedNodes; }
150 | }
151 |
152 | }
153 | }
--------------------------------------------------------------------------------
/UnityGeometryHelper/UnityGeometryHelper/DuKeyMap.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace UnityGeometryHelper
6 | {
7 | public class Tuple
8 | {
9 | public TKey Key;
10 | public TValue Value;
11 | public Tuple()
12 | {
13 |
14 | }
15 |
16 | public Tuple(TKey key, TValue value)
17 | {
18 | this.Key = key;
19 | this.Value = value;
20 | }
21 | }
22 |
23 | public class DupKeyMap
24 | {
25 | public List> StorageList =
26 | new List>();
27 |
28 | public TValue GetFirst(TKey key)
29 | {
30 | for (int i = 0; i < StorageList.Count; i++)
31 | {
32 | if (StorageList[i].Key.Equals(key))
33 | {
34 | return StorageList[i].Value;
35 | }
36 | }
37 |
38 | throw new System.Exception(string.Format("{0} Not found in DupkeyMap",
39 | key.ToString()));
40 | }
41 |
42 | public List GetAll(TKey key)
43 | {
44 | List res = new List();
45 |
46 | for (int i = 0; i < StorageList.Count; i++)
47 | {
48 | if (StorageList[i].Key.Equals(key))
49 | {
50 | res.Add(StorageList[i].Value);
51 | }
52 | }
53 |
54 | return res;
55 | }
56 |
57 | public bool ContainKey(TKey key)
58 | {
59 | for (int i = 0; i < StorageList.Count; i++)
60 | {
61 | if (StorageList[i].Key.Equals(key))
62 | {
63 | return true;
64 | }
65 | }
66 |
67 | return false;
68 | }
69 |
70 | public void Add(TKey key, TValue value)
71 | {
72 | StorageList.Add(new Tuple(key, value));
73 | }
74 |
75 | public void RemoveFirst(TKey key)
76 | {
77 | for (int i = 0; i < StorageList.Count; i++)
78 | {
79 | if (StorageList[i].Key.Equals(key))
80 | {
81 | StorageList.RemoveAt(i);
82 | return;
83 | }
84 | }
85 | }
86 |
87 | public void RemoveAll(TKey key)
88 | {
89 | for (int i = 0; i < StorageList.Count; i++)
90 | {
91 | if (StorageList[i].Key.Equals(key))
92 | {
93 | StorageList.RemoveAt(i);
94 | i--;
95 | }
96 | }
97 | }
98 |
99 | public void ChangeFirstKeyTo(TKey oldKey, TKey newKey)
100 | {
101 | for (int i = 0; i < StorageList.Count; i++)
102 | {
103 | if (StorageList[i].Key.Equals(oldKey))
104 | {
105 | StorageList[i].Key = newKey;
106 | return;
107 | }
108 | }
109 | }
110 |
111 | public void ChangeAllKeyTo(TKey oldKey, TKey newKey)
112 | {
113 | for (int i = 0; i < StorageList.Count; i++)
114 | {
115 | if (StorageList[i].Key.Equals(oldKey))
116 | {
117 | StorageList[i].Key = newKey;
118 | }
119 | }
120 | }
121 |
122 | // a>b:true
123 | // 就会从小到大排列
124 | public delegate bool ISBIGGER(TKey a, TKey b);
125 | public void SortedByKey(ISBIGGER isBigger)
126 | {
127 | for (int i = 0; i < StorageList.Count; i++)
128 | {
129 | for (int j = i + 1; j < StorageList.Count; j++)
130 | {
131 | if (isBigger(StorageList[i].Key, StorageList[j].Key))
132 | {
133 | Tuple swap = StorageList[i];
134 | StorageList[i] = StorageList[j];
135 | StorageList[j] = swap;
136 | }
137 | }
138 | }
139 | }
140 |
141 | public List FindByValues(TValue value)
142 | {
143 | List keys = new List();
144 |
145 | for (int i = 0; i < StorageList.Count; i++)
146 | {
147 | if (StorageList[i].Value.Equals(value))
148 | {
149 | keys.Add(StorageList[i].Key);
150 | }
151 | }
152 |
153 | return keys;
154 | }
155 |
156 | public List AllKey
157 | {
158 | get
159 | {
160 | List keys = new List();
161 |
162 | for (int i = 0; i < StorageList.Count; i++)
163 | {
164 | keys.Add(StorageList[i].Key);
165 | }
166 |
167 | return keys;
168 | }
169 | }
170 |
171 | public List AllValue
172 | {
173 | get
174 | {
175 | List values = new List();
176 |
177 | for (int i = 0; i < StorageList.Count; i++)
178 | {
179 | values.Add(StorageList[i].Value);
180 | }
181 |
182 | return values;
183 | }
184 | }
185 |
186 | public List GetNonDupKeys()
187 | {
188 | List keys = AllKey;
189 | List res = new List();
190 | for (int i = 0; i < keys.Count; i++)
191 | {
192 | if (!res.Contains(keys[i]))
193 | {
194 | res.Add(keys[i]);
195 | }
196 | }
197 |
198 | return res;
199 | }
200 |
201 | public TValue this[TKey key]
202 | {
203 | get { return GetFirst(key); }
204 | set
205 | {
206 | if (this.ContainKey(key))
207 | {
208 | for (int i = 0; i < StorageList.Count; i++)
209 | {
210 | if (StorageList[i].Key.Equals(key))
211 | {
212 | StorageList[i].Value = value;
213 | return;
214 | }
215 | }
216 | }
217 | else
218 | {
219 | this.Add(key, value);
220 | }
221 | }
222 | }
223 |
224 | public int Count
225 | {
226 | get { return StorageList.Count; }
227 | }
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/UnityGeometryHelper/UnityGeometryHelper/Geometric3D.cs:
--------------------------------------------------------------------------------
1 | //using System.Collections.Generic;
2 | //using g3;
3 | //using UnityEngine;
4 |
5 | //namespace UnityGeometryHelper
6 | //{
7 | // public static class Geometric3D
8 | // {
9 | // ///
10 | // /// 求过lp1,lp2与三角形pp1,pp2,pp3所在平面的交点
11 | // ///
12 | // /// 平面三角形1
13 | // /// 平面三角形2
14 | // /// 平面三角形3
15 | // /// 直线1
16 | // /// 直线2
17 | // ///
18 | // public static Vector3 GetCrossPointOfPlaneAndLine(Vector3 planeP1, Vector3 planeP2, Vector3 planeP3,
19 | // Vector3 lineP1, Vector3 lineP2)
20 | // {
21 | // Vector3 planeNor = (Vector3.Cross((planeP1 - planeP2), (planeP3 - planeP2))).normalized;
22 |
23 | // Vector3 planeP = planeP2;
24 |
25 | // float x1 = lineP1.x;
26 | // float x2 = lineP2.x;
27 | // float y1 = lineP1.y;
28 | // float y2 = lineP2.y;
29 | // float z1 = lineP1.z;
30 | // float z2 = lineP2.z;
31 |
32 | // float v1 = x2 - x1;
33 | // float m1 = x1;
34 | // float v2 = y2 - y1;
35 | // float m2 = y1;
36 | // float v3 = z2 - z1;
37 | // float m3 = z1;
38 |
39 | // float n1 = planeP.x;
40 | // float n2 = planeP.y;
41 | // float n3 = planeP.z;
42 |
43 | // float vp1 = planeNor.x;
44 | // float vp2 = planeNor.y;
45 | // float vp3 = planeNor.z;
46 |
47 | // float under = vp1 * v1 + vp2 * v2 + vp3 * v3;
48 | // if (under.Equals(0f))
49 | // {
50 | // return default(Vector3);
51 | // }
52 |
53 | // float up = (n1 - m1) * vp1 + (n2 - m2) * vp2 + (n3 - m3) * vp3;
54 |
55 | // float resX = (((x2 - x1) * up) / under) + x1;
56 | // float resY = (((y2 - y1) * up) / under) + y1;
57 | // float resZ = (((z2 - z1) * up) / under) + z1;
58 | // return new Vector3(resX, resY, resZ);
59 | // }
60 |
61 | // ///
62 | // /// 直线是否与空间中的体相交
63 | // ///
64 | // /// 直线线点1
65 | // /// 直线线点2
66 | // /// mesh顶点
67 | // /// mesh三角
68 | // ///
69 | // public static bool IsLineCrossSpace(Vector3 lineP1, Vector3 lineP2, Vector3[] verts, int[] tris)
70 | // {
71 | // List vertfs = new List();
72 | // for (int i = 0; i < verts.Length; i++)
73 | // {
74 | // vertfs.Add(new Vector3f(verts[i].x, verts[i].y, verts[i].z));
75 | // }
76 |
77 | // DMesh3 mesh = DMesh3Builder.Build(vertfs, tris);
78 |
79 | // DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh);
80 | // spatial.Build();
81 |
82 | // Vector3 l12 = lineP2 - lineP1;
83 |
84 | // Vector3f origin1 = new Vector3f(lineP1.x, lineP1.y, lineP1.z);
85 | // Vector3f origin2 = new Vector3f(lineP2.x, lineP2.y, lineP2.z);
86 | // Vector3f direction = new Vector3f(l12.x, l12.y, l12.z);
87 | // Ray3d ray = new Ray3d(origin1, direction);
88 |
89 | // int hit_tid = spatial.FindNearestHitTriangle(ray);
90 | // bool isHit1 = hit_tid != DMesh3.InvalidID;
91 |
92 | // Ray3d ray2 = new Ray3d(origin2, -direction);
93 | // hit_tid = spatial.FindNearestHitTriangle(ray2);
94 | // bool isHit2 = hit_tid != DMesh3.InvalidID;
95 |
96 | // return isHit1 || isHit2;
97 | // }
98 |
99 | // ///
100 | // /// 射线是否和空间中的体相交
101 | // ///
102 | // ///
103 | // ///
104 | // ///
105 | // ///
106 | // ///
107 | // public static bool IsRayCrossSpace(Vector3 origin, Vector3 direction, Vector3[] verts, int[] tris)
108 | // {
109 | // List vertfs = new List();
110 | // for (int i = 0; i < verts.Length; i++)
111 | // {
112 | // vertfs.Add(new Vector3f(verts[i].x, verts[i].y, verts[i].z));
113 | // }
114 |
115 | // DMesh3 mesh = DMesh3Builder.Build(vertfs, tris);
116 |
117 | // DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh);
118 | // spatial.Build();
119 |
120 | // Vector3f originf = new Vector3f(origin.x, origin.y, origin.z);
121 | // Vector3f directionf = new Vector3f(direction.x, direction.y, direction.z);
122 | // Ray3d ray = new Ray3d(originf, directionf);
123 |
124 | // int hit_tid = spatial.FindNearestHitTriangle(ray);
125 | // bool isHit1 = hit_tid != DMesh3.InvalidID;
126 |
127 | // return isHit1;
128 | // }
129 |
130 | // public static bool IsSegmentCrossSpace(Vector3 segmentStart, Vector3 segmentEnd,
131 | // Vector3[] verts, int[] tris)
132 | // {
133 | // List vertfs = new List();
134 | // for (int i = 0; i < verts.Length; i++)
135 | // {
136 | // vertfs.Add(new Vector3f(verts[i].x, verts[i].y, verts[i].z));
137 | // }
138 |
139 | // DMesh3 mesh = DMesh3Builder.Build(vertfs, tris);
140 |
141 | // DMeshAABBTree3 spatial = new DMeshAABBTree3(mesh);
142 | // spatial.Build();
143 |
144 | // Vector3 l12 = segmentStart - segmentEnd;
145 |
146 | // Vector3f origin1 = new Vector3f(segmentStart.x, segmentStart.y, segmentStart.z);
147 | // Vector3f origin2 = new Vector3f(segmentEnd.x, segmentEnd.y, segmentEnd.z);
148 | // Vector3f direction = new Vector3f(l12.x, l12.y, l12.z);
149 | // Ray3d ray = new Ray3d(origin1, direction);
150 | // Ray3d ray2 = new Ray3d(origin2, -direction);
151 | // int hit_tid1 = spatial.FindNearestHitTriangle(ray);
152 | // int hit_tid2 = spatial.FindNearestHitTriangle(ray2);
153 |
154 | // if (hit_tid1 == DMesh3.InvalidID && hit_tid1 == DMesh3.InvalidID)
155 | // {
156 | // return false;
157 | // }
158 |
159 | // if (hit_tid1 != DMesh3.InvalidID)
160 | // {
161 | // Vector3 hitPoint = GetCrossPointOfTri(verts, tris, hit_tid1, segmentStart, segmentEnd);
162 | // if (Vector3.Distance(hitPoint, segmentStart) + Vector3.Distance(hitPoint, segmentEnd) >
163 | // Vector3.Distance(segmentEnd, segmentStart))
164 | // {
165 | // return false;
166 | // }
167 | // }
168 |
169 | // if (hit_tid2 != DMesh3.InvalidID)
170 | // {
171 | // Vector3 hitPoint = GetCrossPointOfTri(verts, tris, hit_tid2, segmentStart, segmentEnd);
172 | // if (Vector3.Distance(hitPoint, segmentStart) + Vector3.Distance(hitPoint, segmentEnd) >
173 | // Vector3.Distance(segmentEnd, segmentStart))
174 | // {
175 | // return false;
176 | // }
177 | // }
178 |
179 | // return true;
180 | // }
181 |
182 | // public static Vector3 GetCrossPointOfTri(Vector3[] verts, int[] tris, int triId, Vector3 a, Vector3 b)
183 | // {
184 | // List triHit = new List()
185 | // {
186 | // verts[tris[triId]],
187 | // verts[tris[triId + 1]],
188 | // verts[tris[triId + 2]],
189 | // };
190 |
191 | // return GetCrossPointOfPlaneAndLine(triHit[0], triHit[1], triHit[2], a, b);
192 | // }
193 | // }
194 | //}
195 |
--------------------------------------------------------------------------------
/UnityGeometryHelper/UnityGeometryHelper/Geometric.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using UnityEngine;
5 |
6 | namespace UnityGeometryHelper
7 | {
8 | public static class Geometric
9 | {
10 | #region 基础面积计算
11 | ///
12 | /// AB X AC
13 | ///
14 | /// 点A
15 | /// 点B
16 | /// 点C
17 | ///
18 | private static float cross(Vector3 A, Vector3 B, Vector3 C)
19 | {
20 | return (B.x - A.x) * (C.z - A.z) - (B.z - A.z) * (C.x - A.x);
21 | }
22 |
23 | ///
24 | /// 使用向量叉乘来计算任意多边形面积
25 | ///
26 | /// 顺序描述的点集
27 | /// 面积
28 | public static float GetArea(params Vector3[] points)
29 | {
30 | //去重
31 | List toCalcualte = new List(points);
32 | for (int i = 0; i < toCalcualte.Count; i++)
33 | {
34 | for (int j = 0; j < toCalcualte.Count; j++)
35 | {
36 | if (j != i && toCalcualte[i] == toCalcualte[j])
37 | {
38 | toCalcualte.RemoveAt(j);
39 | j--;
40 | }
41 | }
42 | }
43 |
44 | int n = toCalcualte.Count;
45 | for (int i = 0; i < n; i++)
46 | {
47 | if (Geometric.Meet(toCalcualte[i], toCalcualte[(i + 1) % n], toCalcualte[(i + 2) % n], toCalcualte[(i + 3) % n]))
48 | {
49 | var temp = toCalcualte[(i + 2) % n];
50 | toCalcualte[(i + 2) % n] = toCalcualte[(i + 1) % n];
51 | toCalcualte[(i + 1) % n] = temp;
52 | }
53 | }
54 |
55 | points = toCalcualte.ToArray();
56 |
57 | float area = 0f;
58 | Vector3 ANXI = toCalcualte[0] + Vector3.one * 100;//要尽量远来补平舍入误差
59 | for (int i = 0; i < points.Length; i++)
60 | {
61 | area += cross(ANXI, points[i], points[(i + 1) % points.Length]);
62 | }
63 | area /= 2f;
64 | return Mathf.Abs(area);
65 | }
66 |
67 | #endregion
68 |
69 | #region 点面关系
70 |
71 | ///
72 | /// 检测点是否在区域内
73 | ///
74 | /// 顺序描述的区域定点
75 | /// 检查点
76 | ///
77 | public static bool IsPointInArea(Vector3[] RegionVertexes, Vector3 toCheck)
78 | {
79 | float minX = Single.MaxValue;
80 | float minZ = Single.MaxValue;
81 | float maxX = Single.MinValue;
82 | float maxZ = Single.MinValue;
83 | foreach (var vertex in RegionVertexes)
84 | {
85 | if (vertex.x < minX)
86 | {
87 | minX = vertex.x;
88 | }
89 |
90 | if (vertex.x > maxX)
91 | {
92 | maxX = vertex.x;
93 | }
94 |
95 | if (vertex.z < minZ)
96 | {
97 | minZ = vertex.z;
98 | }
99 |
100 | if (vertex.z > maxZ)
101 | {
102 | maxZ = vertex.z;
103 | }
104 | }
105 |
106 | if (toCheck.x < minX || toCheck.x > maxX || toCheck.z < minZ || toCheck.z > maxZ)
107 | {
108 | //Console.WriteLine(minX+ " ! " + minZ);
109 | return false;
110 | }//长方形校验不通过直接可以返回flase的
111 |
112 | return Pnpoly(RegionVertexes.Length, RegionVertexes, toCheck.x, toCheck.z);
113 | }
114 |
115 |
116 | public static bool IsPointAlmostInArea(Vector3[] rvs, Vector3 toCheck, float offset = 0.1f)
117 | {
118 | if (IsPointInArea(rvs, toCheck))
119 | {
120 | return true;
121 | }
122 |
123 | return IsPointOnAreaSide(rvs, toCheck, offset);
124 | }
125 |
126 | public static bool IsPointOnAreaSide(Vector3[] rvs, Vector3 toCheck, float offset = 0.1f)
127 | {
128 | for (int i = 0; i < rvs.Length; i++)
129 | {
130 | var thisStart = rvs[i];
131 | var thisEnd = rvs[(i + 1) % rvs.Length];
132 | if (IsPointAlmostOnSegment(thisStart, thisEnd, offset * 2,
133 | toCheck))
134 | {
135 | return true;
136 | }
137 | }
138 | return false;
139 | }
140 |
141 | public static bool IsAreaFullyInAnotherArea(Vector3[] area1, Vector3[] area2)
142 | {
143 | int n1 = area1.Length;
144 | int n2 = area2.Length;
145 | for (int i = 0; i < n1; i++)
146 | {
147 | for (int j = 0; j < n2; j++)
148 | {
149 | Vector3 point11 = area1[i];
150 | Vector3 point12 = area1[(i + 1) % n1];
151 | Vector3 point21 = area2[j];
152 | Vector3 point22 = area2[(j + 1) % n2];
153 |
154 | if (Meet(point11, point12, point21, point22))
155 | {
156 | return false;
157 | }
158 | }
159 | }//首先保证边界没有交点
160 |
161 | bool res1 = true;
162 | bool res2 = true;
163 | foreach (var point in area1)
164 | {
165 | if (!IsPointInArea(area2, point))
166 | {
167 | res1 = false;
168 | break;
169 | }
170 | }
171 |
172 | foreach (var point in area2)
173 | {
174 | if (!IsPointInArea(area1, point))
175 | {
176 | res2 = false;
177 | break;
178 | }
179 | }
180 |
181 | return res1 ^ res2;//必然有一个全部在内,另一个全部在外
182 | }
183 |
184 | public static bool IsAreaPartlyInAnotherArea(Vector3[] area1, Vector3[] area2)
185 | {
186 | int n1 = area1.Length;
187 | int n2 = area2.Length;
188 | for (int i = 0; i < n1; i++)
189 | {
190 | for (int j = 0; j < n2; j++)
191 | {
192 | Vector3 point11 = area1[i];
193 | Vector3 point12 = area1[(i + 1) % n1];
194 | Vector3 point21 = area2[j];
195 | Vector3 point22 = area2[(j + 1) % n2];
196 |
197 | if (Meet(point11, point12, point21, point22))
198 | {
199 | return true;
200 | }
201 | }
202 | }//边界相交必然部分在内
203 |
204 | bool res1 = false;
205 | bool res2 = false;
206 | foreach (var point in area1)
207 | {
208 | if (IsPointInArea(area2, point))
209 | {
210 | res1 = true;
211 | break;
212 | }
213 | }
214 |
215 | foreach (var point in area2)
216 | {
217 | if (IsPointInArea(area1, point))
218 | {
219 | res2 = true;
220 | break;
221 | }
222 | }
223 |
224 | return res1 || res2;//边界没有相交的情况,除了完全分离的情况都是包含
225 | }
226 |
227 | ///
228 | /// Pnpoly内点检测算法
229 | ///
230 | /// 边树
231 | /// 顺序描述的区域点集
232 | /// x坐标
233 | /// z坐标
234 | ///
235 | private static bool Pnpoly(int polySides, Vector3[] RegionVertexes, float x, float z)
236 | {
237 | float maxX = float.MinValue;
238 | float minX = float.MaxValue;
239 | float maxz = float.MinValue;
240 | float minz = float.MaxValue;
241 |
242 | foreach (var thisP in RegionVertexes)
243 | {
244 | if (thisP.x > maxX)
245 | {
246 | maxX = thisP.x;
247 | }
248 |
249 | if (thisP.x < minX)
250 | {
251 | minX = thisP.x;
252 | }
253 |
254 | if (thisP.z > maxz)
255 | {
256 | maxz = thisP.z;
257 | }
258 |
259 | if (thisP.z < minz)
260 | {
261 | minz = thisP.z;
262 | }
263 | }
264 |
265 | float xOffset = maxX - minX;
266 | float zOffset = maxz - minz;
267 |
268 | return PNpoly_X(polySides, RegionVertexes, x, z, xOffset) || PNpoly_Y(polySides, RegionVertexes, x, z, zOffset);
269 | }
270 |
271 | private static bool PNpoly_Y(int polySides, Vector3[] RegionVertexes, float x, float z, float maxOffset)
272 | {
273 | Vector3 pointLeft = new Vector3(x, 0, z - maxOffset);
274 | Vector3 pointRight = new Vector3(x, 0, z + maxOffset);
275 | Vector3 pointSelf = new Vector3(x, 0, z);
276 |
277 | int left = 0;
278 | int right = 0;
279 | for (int i = 0; i < polySides; i++)
280 | {
281 | Vector3 point1 = RegionVertexes[i];
282 | Vector3 point2 = RegionVertexes[(i + 1) % polySides];
283 | if (Meet(pointLeft, pointSelf, point1, point2)/* && !Geometric.IsDirParallel(pointLeft - pointSelf, point2 - point1)*/)
284 | {
285 | left++;
286 | }
287 | else if (Meet(pointRight, pointSelf, point1, point2)/* && !Geometric.IsDirParallel(pointRight - pointSelf, point2 - point1)*/)
288 | {
289 | right++;
290 | }
291 | }
292 |
293 | if ((left % 2 == 1) && right % 2 == 1)
294 | {
295 | return true;
296 | }
297 |
298 | return false;
299 | }
300 |
301 | private static bool PNpoly_X(int polySides, Vector3[] RegionVertexes, float x, float z, float maxOffset)
302 | {
303 | Vector3 pointLeft = new Vector3(x - maxOffset, 0, z);
304 | Vector3 pointRight = new Vector3(x + maxOffset, 0, z);
305 | Vector3 pointSelf = new Vector3(x, 0, z);
306 |
307 | int left = 0;
308 | int right = 0;
309 | for (int i = 0; i < polySides; i++)
310 | {
311 | Vector3 point1 = RegionVertexes[i];
312 | Vector3 point2 = RegionVertexes[(i + 1) % polySides];
313 | if (Meet(pointLeft, pointSelf, point1, point2)/* && !Geometric.IsDirParallel(pointLeft-pointSelf, point2-point1)*/)
314 | {
315 | left++;
316 | }
317 | else if (Meet(pointRight, pointSelf, point1, point2)/* && !Geometric.IsDirParallel(pointRight - pointSelf, point2 - point1)*/)
318 | {
319 | right++;
320 | }
321 | }
322 |
323 | if ((left % 2 == 1) && right % 2 == 1)
324 | {
325 | return true;
326 | }
327 |
328 | return false;
329 | }
330 |
331 | #endregion
332 |
333 | #region 求线段交点
334 | //这一套没有问题!
335 | const float eps = (float)1e-6;
336 |
337 | const float Pi = Mathf.PI;
338 |
339 | public static bool IsDirParallel(Vector3 a, Vector3 b, float offset = 3f)
340 | {
341 | float angle = Vector3.Angle(a, b);
342 | return (angle < offset || angle > (180 - offset));
343 | }
344 | public static bool IsDirSame(Vector3 a, Vector3 b, float offset = 3f)
345 | {
346 | float angle = Vector3.Angle(a, b);
347 | return (angle < offset);
348 | }
349 | ///
350 | /// 线段12-34的交点
351 | ///
352 | ///
353 | ///
354 | ///
355 | ///
356 | ///
357 | public static Vector3 GetCorssPointOfSegment(Vector3 point1, Vector3 point2, Vector3 point3, Vector3 point4)
358 | {
359 | if (!Meet(point1, point2, point3, point4))
360 | {
361 | return default(Vector3);
362 | }
363 |
364 | if (IsDirParallel(point1 - point2, point3 - point4))
365 | {
366 | return default(Vector3);
367 | }
368 |
369 | return Inter(point1, point2, point3, point4);
370 | }
371 |
372 | public static Vector3 GetCrossPointOfLine(Vector3 point1, Vector3 point2, Vector3 point3, Vector3 point4)
373 | {
374 | Vector3 _dir12 = (point2 - point1).normalized;
375 | Vector3 _dir34 = (point4 - point3).normalized;
376 |
377 | float _angle = Vector3.Angle(_dir12, _dir34);
378 | if (_angle < 0.1f || _angle > 179.9f)
379 | {
380 | return default(Vector3);
381 | }
382 |
383 | var res = GetCorssPointOfSegment(point1 + _dir12 * 999, point2 - _dir12 * 999, point3 + _dir34 * 999,
384 | point4 - _dir34 * 999);
385 | return res;
386 | }
387 |
388 | ///
389 | /// 获取x的符号
390 | ///
391 | ///
392 | ///
393 | static int sgn(float x)
394 | {
395 | if (x < -eps)
396 | {
397 | return -1;
398 | }
399 | else
400 | {
401 | return x > eps ? 0 : 1;
402 | }
403 | }
404 |
405 | ///
406 | /// 向量叉乘
407 | ///
408 | ///
409 | ///
410 | ///
411 | ///
412 | ///
413 | static float Cross(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4)
414 | {
415 | return (p2.x - p1.x) * (p4.z - p3.z) - (p2.z - p1.z) * (p4.x - p3.x);
416 | }
417 |
418 | static float Area(Vector3 p1, Vector3 p2, Vector3 p3)
419 | {
420 | return Cross(p1, p2, p1, p3);
421 | }
422 |
423 | static float fArea(Vector3 p1, Vector3 p2, Vector3 p3)
424 | {
425 | return Mathf.Abs((float)Area(p1, p2, p3));
426 | }
427 |
428 | ///
429 | /// 线段是否相交
430 | ///
431 | ///
432 | ///
433 | ///
434 | ///
435 | ///
436 | public static bool Meet(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4)
437 | {
438 | return Mathf.Max(Mathf.Min(p1.x, p2.x), Mathf.Min(p3.x, p4.x)) <= Mathf.Min(Mathf.Max(p1.x, p2.x), Mathf.Max(p3.x, p4.x))
439 | && Mathf.Max(Mathf.Min(p1.z, p2.z), Mathf.Min(p3.z, p4.z)) <= Mathf.Min(Mathf.Max(p1.z, p2.z), Mathf.Max(p3.z, p4.z))
440 | && sgn(Cross(p3, p2, p3, p4) * Cross(p3, p4, p3, p1)) >= 0
441 | && sgn(Cross(p1, p4, p1, p2) * Cross(p1, p2, p1, p3)) >= 0;
442 | }
443 |
444 | public static bool Meet_crossWay(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4)
445 | {
446 | Vector3 crossP = GetCrossPointOfLine(p1, p2, p3, p4);
447 | return Geometric.IsPointOnSegment(p1, p2, crossP) && Geometric.IsPointOnSegment(p3, p4, crossP);
448 | }
449 |
450 | public static bool IsTwoLinePointPartCover(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float offset = 0.03f)
451 | {
452 | return Geometric.IsPointAlmostOnSegment(a, b, offset, c) || Geometric.IsPointAlmostOnSegment(a, b, offset, d) ||
453 | Geometric.IsPointAlmostOnSegment(c, d, offset, a) || Geometric.IsPointAlmostOnSegment(c, d, offset, b);
454 | }
455 |
456 | static Vector3 Inter(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4)
457 | {
458 | //特判:某顶点在另外一条直线上时
459 | if (IsPointOnLine(p1, p2, p3))
460 | {
461 | return p3;
462 | }
463 | if (IsPointOnLine(p1, p2, p4))
464 | {
465 | return p4;
466 | }
467 | if (IsPointOnLine(p3, p4, p1))
468 | {
469 | return p1;
470 | }
471 | if (IsPointOnLine(p3, p4, p2))
472 | {
473 | return p2;
474 | }
475 | float k = fArea(p1, p2, p3) / fArea(p1, p2, p4);
476 | return new Vector3((float)(p3.x + k * p4.x) / (float)(1 + k), 0, (float)(p3.z + k * p4.z) / (float)(1 + k));
477 | }
478 |
479 | #endregion
480 |
481 | #region 点线关系
482 |
483 | public static bool IsPointAlmostOnSegment(Vector3 lineP1, Vector3 lineP2, float width, Vector3 toCheck)
484 | {
485 | Vector3 _lineDir = (lineP2 - lineP1).normalized;
486 | Quaternion q = QuaternionUtility.Euler(0, 90, 0);
487 | Vector3 _rightDir = (q * _lineDir).normalized;
488 |
489 | Vector3 diff = _rightDir * width - _lineDir * width;
490 |
491 | Vector3 lp1Right = lineP1 + diff;
492 | Vector3 lp1Left = lineP1 - diff;
493 |
494 | Vector3 lp2Right = lineP2 + diff;
495 | Vector3 lp2Left = lineP2 - diff;
496 |
497 | var res = Geometric.IsPointInArea(new[] { lp1Right, lp2Right, lp2Left, lp1Left }, toCheck);
498 | return res;
499 | }
500 |
501 |
502 | ///
503 | /// 点到线距离
504 | ///
505 | /// 点
506 | /// 线点1
507 | /// 线点2
508 | ///
509 | public static float GetDistanceFromPointToLine(Vector3 point, Vector3 a, Vector3 b)
510 | {
511 | if (Mathf.Abs(a.x - b.x) < 1e-6)
512 | {
513 | return Mathf.Abs(point.x - a.x);
514 | }
515 | if (Mathf.Abs(a.z - b.z) < 1e-6)
516 | {
517 | return Mathf.Abs(point.z - a.z);
518 | }
519 |
520 | float area = GetArea(point, a, b);
521 | return (2 * area) / Vector3.Distance(a, b);
522 | }
523 |
524 | ///
525 | /// 点是否在线上
526 | ///
527 | /// 线段点1
528 | /// 线段点2
529 | /// 检查点
530 | ///
531 | public static bool IsPointOnLine(Vector3 line1, Vector3 line2, Vector3 p)
532 | {
533 | float k = (line2.z - line1.z) / (line2.x - line1.x);
534 | float b = (line2.z * line1.x - line1.z * line2.x) / (line1.x - line2.x);
535 |
536 | if (Mathf.Abs(line1.x - line2.x) <= eps && Mathf.Abs(line1.x - p.x) <= eps)
537 | {
538 | return true;
539 | }
540 |
541 | if (Mathf.Abs((p.x * k + b) - p.z) < eps)
542 | {
543 | return true;
544 | }
545 | return false;
546 | }
547 |
548 | ///
549 | /// 是否在线段上
550 | ///
551 | /// 线段点1
552 | /// 线段点2
553 | /// 检查点
554 | ///
555 | public static bool IsPointOnSegment(Vector3 line1, Vector3 line2, Vector3 p)
556 | {
557 |
558 | if (Mathf.Abs(line1.x - line2.x) <= eps && Mathf.Abs(line1.x - p.x) <= eps)
559 | {
560 | float bigZ = line1.z > line2.z ? line1.z : line2.z;
561 | float smallZ = line1.z < line2.z ? line1.z : line2.z;
562 | if (p.z <= bigZ && p.z >= smallZ)
563 | {
564 | return true;
565 | }
566 | }
567 |
568 | float k = (line2.z - line1.z) / (line2.x - line1.x);
569 | float b = (line2.z * line1.x - line1.z * line2.x) / (line1.x - line2.x);
570 | if (Mathf.Abs((p.x * k + b) - p.z) < eps)
571 | {
572 | float maxX = line1.x > line2.x ? line1.x : line2.x;
573 | float minX = line1.x < line2.x ? line1.x : line2.x;
574 | float maxZ = line1.z > line2.z ? line1.z : line2.z;
575 | float minZ = line1.z < line2.z ? line1.z : line2.z;
576 | if (p.x <= maxX && p.x >= minX && p.z <= maxZ && p.z >= minZ)
577 | {
578 | return true;
579 | }
580 | }
581 | return false;
582 | }
583 |
584 | #endregion
585 |
586 | #region 点群
587 |
588 | public static List SortPointsByAngle(List points)
589 | {
590 | DupKeyMap map = new DupKeyMap();
591 | Vector3 midP = new Vector3();
592 | foreach (var p in points)
593 | {
594 | midP += p;
595 | }
596 | midP /= points.Count;
597 | foreach (var p in points)
598 | {
599 | map.Add(AbsYAngle(midP, p), p);
600 | }
601 |
602 | map.SortedByKey((a, b) => { return a > b; });
603 | return map.AllValue;
604 | }
605 |
606 | ///
607 | /// 找出allP中离toCheck最近的点
608 | ///
609 | ///
610 | ///
611 | ///
612 | public static Vector3 GetCloestPoint(Vector3 toCheck, List allP)
613 | {
614 | if (allP == null || allP.Count == 0)
615 | {
616 | return default(Vector3);
617 | }
618 |
619 | Vector3 res = allP[0];
620 | float minDis = Vector3.Distance(res, toCheck);
621 | for (int i = 0; i < allP.Count; i++)
622 | {
623 | float thisDis = Vector3.Distance(toCheck, allP[i]);
624 | if (thisDis < minDis)
625 | {
626 | minDis = thisDis;
627 | res = allP[i];
628 | }
629 | }
630 |
631 | return res;
632 | }
633 |
634 | ///
635 | /// 获取点群的凸包
636 | ///
637 | /// 点群集合
638 | /// 凸包点群集合(不保证点序),最后一点重复第一点
639 | public static List GetBoundary(List allPoints)
640 | {
641 | //Drawer.Points(allPoints.ToArray(), Color.blue);
642 | ConvexAogrithm ca = new ConvexAogrithm(allPoints);
643 | ca.GetNodesByAngle();
644 |
645 | var res = ca.SortedNodes.ToList();
646 | res.Add(res[0]);
647 | return res;
648 | }
649 |
650 | ///
651 | /// 获取点群的最大闭包矩形
652 | ///
653 | /// 点群集合
654 | /// 最大闭包矩形五点(保证点序,最后一点重复第一点)
655 | public static List GetMaxClosureRect(List allPoints)
656 | {
657 | List res = new List();
658 |
659 | float maxX = Single.MinValue;
660 | float maxZ = Single.MinValue;
661 | float minX = Single.MaxValue;
662 | float minZ = Single.MaxValue;
663 |
664 | for (int i = 0; i < allPoints.Count; i++)
665 | {
666 | if (allPoints[i].x > maxX)
667 | {
668 | maxX = allPoints[i].x;
669 | }
670 |
671 | if (allPoints[i].z > maxZ)
672 | {
673 | maxZ = allPoints[i].z;
674 | }
675 |
676 | if (allPoints[i].x < minX)
677 | {
678 | minX = allPoints[i].x;
679 | }
680 |
681 | if (allPoints[i].z < minZ)
682 | {
683 | minZ = allPoints[i].z;
684 | }
685 | }
686 |
687 | Vector3 leftUp = new Vector3(minX, 0, maxZ);
688 | Vector3 leftDown = new Vector3(minX, 0, minZ);
689 | Vector3 rightDown = new Vector3(maxX, 0, minZ);
690 | Vector3 rightUp = new Vector3(maxX, 0, maxZ);
691 |
692 | res.Add(leftUp);
693 | res.Add(leftDown);
694 | res.Add(rightDown);
695 | res.Add(rightUp);
696 |
697 | res.Add(leftUp);
698 |
699 | return res;
700 | }
701 |
702 | ///
703 | /// 点群线分
704 | ///
705 | /// 线点1
706 | /// 线点2
707 | /// 点群
708 | ///
709 | public static List> DividePointsByLine(Vector3 a, Vector3 b,
710 | List points)
711 | {
712 | Vector3 abDir = (b - a).normalized;// 线方向
713 |
714 | Dictionary> isOnRightMap =
715 | new Dictionary>();
716 | isOnRightMap.Add(false, new List());
717 | isOnRightMap.Add(true, new List());
718 | for (int i = 0; i < points.Count; i++)
719 | {
720 | bool key = IsOnRight(a, b, points[i]);
721 | if (isOnRightMap.ContainsKey(key))
722 | {
723 | isOnRightMap[key].Add(points[i]);
724 | }
725 | else
726 | {
727 | isOnRightMap.Add(key, new List() { points[i] });
728 | }
729 | }
730 |
731 | return isOnRightMap.Values.ToList();
732 | }
733 |
734 | public static bool IsOnRight(Vector3 a, Vector3 b, Vector3 p)
735 | {
736 | Vector3 abDir = (b - a).normalized;// 线方向
737 | Vector3 apDir = (p - a).normalized;// 点方向
738 |
739 | return ClockYAngle(abDir, apDir) < 180;
740 | }
741 |
742 | public delegate Vector3 GetVector3(T toGet);
743 |
744 | public static List> DividePointsByLine(Vector3 a, Vector3 b,
745 | List points, GetVector3 getter)
746 | {
747 | Dictionary> pointTMap = new Dictionary>();
748 | List allP = new List();
749 | for (int i = 0; i < points.Count; i++)
750 | {
751 | var key = getter(points[i]);
752 | if (pointTMap.ContainsKey(key))
753 | {
754 | pointTMap[key].Add(points[i]);
755 | }
756 | else
757 | {
758 | pointTMap.Add(key, new List() { points[i] });
759 | }
760 | allP.Add(getter(points[i]));
761 | }
762 |
763 | List> pRes = DividePointsByLine(a, b, allP);
764 | List> res = new List>();
765 | for (int i = 0; i < pRes.Count; i++)
766 | {
767 | List row = new List();
768 | for (int j = 0; j < pRes[i].Count; j++)
769 | {
770 | for (int k = 0; k < pointTMap[pRes[i][j]].Count; k++)
771 | {
772 | row.Add(pointTMap[pRes[i][j]][k]);
773 | }
774 | }
775 | res.Add(row);
776 | }
777 |
778 | return res;
779 | }
780 |
781 | #endregion
782 |
783 | #region V3操作
784 |
785 |
786 | public delegate float distanceCalc(Vector3 a, Vector3 b);
787 | ///
788 | /// 比较checker是不是比pin要离target更远
789 | ///
790 | ///
791 | ///
792 | ///
793 | ///
794 | public static bool IsFarFrom(Vector3 target, Vector3 check, Vector3 pin, distanceCalc calc)
795 | {
796 | return calc(target, check) > calc(target, pin);
797 | }
798 |
799 | public static bool IsOnLeft(Vector3 forward, Vector3 toCheck)
800 | {
801 | return Vector3.Cross(forward, toCheck).y < 0;
802 | }
803 |
804 | ///
805 | /// 求y平面A-B的顺时针角度,
806 | ///
807 | ///
808 | ///
809 | ///
810 | public static float ClockAngle(Vector3 a, Vector3 b)
811 | {
812 | float angle = Vector3.Angle(a, b);
813 | if (angle.Equals(0))
814 | {
815 | return angle;
816 | }
817 |
818 | if (Vector3.Cross(a, b).y >= 0)
819 | {
820 | return angle;
821 | }
822 | else
823 | {
824 | return 360 - angle;
825 | }
826 | }
827 |
828 | ///
829 | /// 求y平面A-B的顺时针角度,
830 | ///
831 | ///
832 | ///
833 | ///
834 | public static float ClockYAngle(Vector3 dirA, Vector3 dirB)
835 | {
836 | float angle = Vector3.Angle(new Vector3(dirA.x, 0, dirA.z), new Vector3(dirB.x, 0, dirB.z));
837 | if (angle.Equals(0))
838 | {
839 | return angle;
840 | }
841 |
842 | if (Vector3.Cross(dirA, dirB).y >= 0)
843 | {
844 | return angle;
845 | }
846 | else
847 | {
848 | return 360 - angle;
849 | }
850 | }
851 |
852 | public static float AbsYAngle(Vector3 pointA, Vector3 pointB, Vector3 checkDir)
853 | {
854 | Vector3 ab = pointB - pointA;
855 | ab.y = 0;
856 | Vector3 anx = checkDir;
857 | if (Vector3.Cross(anx, ab).y <= 0)
858 | {
859 | return Vector3.Angle(anx, ab);
860 | }
861 | else
862 | {
863 | return 360 - Vector3.Angle(anx, ab);
864 | }
865 | }
866 |
867 | public static float AbsYAngle(Vector3 pointA, Vector3 pointB)
868 | {
869 | Vector3 ab = pointB - pointA;
870 | ab.y = 0;
871 | Vector3 anx = new Vector3(0, 0, 1);
872 | if (Vector3.Cross(anx, ab).y <= 0)
873 | {
874 | return Vector3.Angle(anx, ab);
875 | }
876 | else
877 | {
878 | return 360 - Vector3.Angle(anx, ab);
879 | }
880 | }
881 |
882 | ///
883 | /// 求y平面A-B的逆时针角度,
884 | ///
885 | ///
886 | ///
887 | ///
888 | public static float DeclockAngle(Vector3 a, Vector3 b)
889 | {
890 | float angle = Vector3.Angle(a, b);
891 | if (angle.Equals(0))
892 | {
893 | return angle;
894 | }
895 |
896 | if (Vector3.Cross(a, b).y >= 0)
897 | {
898 | return 360 - angle;
899 | }
900 | else
901 | {
902 | return angle;
903 | }
904 | }
905 |
906 | public static bool IsClose(Vector3 a, Vector3 b, float offset = 0.1f)
907 | {
908 | return Vector3.Distance(a, b) < offset;
909 | }
910 |
911 | public static bool Contain(List list, Vector3 toCheck, float offset = 0.1f)
912 | {
913 | for (int i = 0; i < list.Count; i++)
914 | {
915 | if (IsClose(list[i], toCheck, offset))
916 | {
917 | return true;
918 | }
919 | }
920 |
921 | return false;
922 | }
923 |
924 | #endregion
925 |
926 | #region LineRelated
927 |
928 | public static bool AlmostOnLine(Vector3 lineP1, Vector3 lineP2, float width, Vector3 toCheck)
929 | {
930 | Vector3 _lineDir = (lineP2 - lineP1).normalized;
931 |
932 | lineP1 += _lineDir*99;
933 | lineP2 -= _lineDir*99;
934 |
935 | Quaternion q = QuaternionUtility.Euler(0, 90, 0);
936 | Vector3 _rightDir = (q * _lineDir).normalized;
937 |
938 | Vector3 lp1Right = lineP1 + _rightDir * 0.5f * width - _lineDir * 0.5f * width;
939 | Vector3 lp1Left = lineP1 - _rightDir * 0.5f * width - _lineDir * 0.5f * width;
940 |
941 | Vector3 lp2Right = lineP2 + _rightDir * 0.5f * width + _lineDir * 0.5f * width;
942 | Vector3 lp2Left = lineP2 - _rightDir * 0.5f * width + _lineDir * 0.5f * width;
943 |
944 | return Geometric.IsPointInArea(new[] { lp1Right, lp2Right, lp2Left, lp1Left }, toCheck);
945 | }
946 |
947 | public static Vector3 GetHoverPoint(Vector3 lp1, Vector3 lp2, Vector3 modelP, float attachR)
948 | {
949 | var _area = Geometric.GetArea(lp1, lp2, modelP);//三角形面积
950 | var _lLength = Vector3.Distance(lp1, lp2);//lp1,lp2长度
951 | var dis = _lLength < 1e-3 ? attachR + 1 : 2 * _area / _lLength;//modelP到lp1,lp2的距离
952 | if (dis > attachR)//太远
953 | {
954 | return default(Vector3);
955 | }
956 |
957 | Vector3 lDir = lp1 - lp2;//直线方向
958 | Vector3 mDir = QuaternionUtility.Euler(0, 90, 0) * lDir;//xz平面上垂直直线方向
959 | Vector3 __S = modelP - mDir * 999;
960 | Vector3 __E = modelP + mDir * 999;//临时的两个线点
961 |
962 | if (!Geometric.Meet(__S, __E, lp1, lp2))//不相交
963 | {
964 | return default(Vector3);
965 | }
966 |
967 | //到这里还能执行的话是相交且接近, 就要计算点
968 | Vector3 res = Geometric.GetCorssPointOfSegment(__E, __S, lp1, lp2);
969 | return res;
970 | }
971 |
972 | public static float GetHoverDis(Vector3 lp1, Vector3 lp2, Vector3 modelP)
973 | {
974 | var _lp1 = new Vector3(lp1.x, 0, lp1.z);
975 | var _lp2 = new Vector3(lp2.x, 0, lp2.z);
976 | var _modelP = new Vector3(modelP.x, 0, modelP.z);
977 |
978 | var _area = Geometric.GetArea(_lp1, _lp2, _modelP);//三角形面积
979 | var _lLength = Vector3.Distance(_lp1, _lp2);//lp1,lp2长度
980 | var dis = 2 * _area / _lLength;//modelP到lp1,lp2的距离
981 | return dis;
982 | }
983 |
984 | public static bool IsHover(Vector3 lp1, Vector3 lp2, Vector3 modelP)
985 | {
986 | return !GetHoverPoint(lp1, lp2, modelP, 999).Equals(default(Vector3));
987 | }
988 |
989 | public static Vector3 GetHoverPointOfLine(Vector3 lp1, Vector3 lp2, Vector3 modelP, float attachR)
990 | {
991 | var _area = Geometric.GetArea(lp1, lp2, modelP);//三角形面积
992 | var _lLength = Vector3.Distance(lp1, lp2);//lp1,lp2长度
993 | var dis = _lLength < 1e-3 ? attachR + 1 : 2 * _area / _lLength;//modelP到lp1,lp2的距离
994 | if (dis > attachR)//太远
995 | {
996 | return default(Vector3);
997 | }
998 |
999 | Vector3 lDir = lp1 - lp2;//直线方向
1000 | Vector3 mDir = QuaternionUtility.Euler(0, 90, 0) * lDir;//xz平面上垂直直线方向
1001 | Vector3 __S = modelP - mDir * 99;
1002 | Vector3 __E = modelP + mDir * 99;//临时的两个线点
1003 |
1004 | //if (!Geometric.Meet(__S, __E, lp1, lp2))//不相交
1005 | //{
1006 | // return default(Vector3);
1007 | //}
1008 |
1009 | //到这里还能执行的话是相交且接近, 就要计算点
1010 | Vector3 res = Geometric.GetCrossPointOfLine(__E, __S, lp1, lp2);
1011 |
1012 | if ((Mathf.Abs(res.x - modelP.x) < 0.01f))
1013 | {
1014 | res.x = modelP.x;
1015 | }
1016 |
1017 | if ((Mathf.Abs(res.z - modelP.z) < 0.01f))
1018 | {
1019 | res.z = modelP.z;
1020 | }
1021 |
1022 | return res;
1023 | }
1024 |
1025 | public static Vector3 GetHoverPointOf3DLine(Vector3 lp1, Vector3 lp2, Vector3 modelP)
1026 | {
1027 | float y = Vector3.Distance(lp2, modelP);
1028 | float z = Vector3.Distance(lp1, modelP);
1029 | float x = Vector3.Distance(lp1, lp2);
1030 | float q = (x + y + z) * 0.5f;
1031 | float area = Mathf.Sqrt(q * (q - x) * (q - y) * (q - z));
1032 |
1033 | float hoverDis = area / x;
1034 | float fromyP = Mathf.Sqrt(y * y - hoverDis * hoverDis);
1035 |
1036 | return lp2 + (lp1 - lp2).normalized * fromyP;
1037 | }
1038 | #endregion
1039 |
1040 | ///
1041 | /// 特殊的舍入进位算法
1042 | ///
1043 | /// 需要变化的数值
1044 | /// 保留到10^atIndex位
1045 | /// 位移步长,res=0+(i*step*2)
1046 | ///
1047 | public static double Round(double value, int atIndex = 0, float step = 0)
1048 | {
1049 | bool isNegative = false;
1050 | //如果是负数
1051 | if (value < 0)
1052 | {
1053 | isNegative = true;
1054 | value = -value;
1055 | }
1056 | double absValue = Math.Abs(value);
1057 |
1058 | double iValue = Math.Pow(10, atIndex);// 扩张值
1059 |
1060 | double thisBigInt = Math.Round(value * iValue, 0);// 取出扩张后的整数位
1061 |
1062 | if (thisBigInt % 2 != 0)
1063 | {
1064 | if (thisBigInt < absValue * iValue)
1065 | {
1066 | // 向下位移
1067 | thisBigInt -= step;
1068 | }
1069 | else
1070 | {
1071 | // 向上位移
1072 | thisBigInt += step;
1073 | }
1074 | }
1075 |
1076 | double res = thisBigInt / iValue;
1077 |
1078 | if (isNegative)
1079 | {
1080 | res = -res;
1081 | }
1082 |
1083 | return res;
1084 | }
1085 | }
1086 | }
1087 |
--------------------------------------------------------------------------------