diff --git a/FishROV/Assets/Scripts/Benchmark/FrameworkAdapters/Rvo2Adapter.cs b/FishROV/Assets/Scripts/Benchmark/FrameworkAdapters/Rvo2Adapter.cs
index 119018c..0945e67 100644
--- a/FishROV/Assets/Scripts/Benchmark/FrameworkAdapters/Rvo2Adapter.cs
+++ b/FishROV/Assets/Scripts/Benchmark/FrameworkAdapters/Rvo2Adapter.cs
@@ -12,7 +12,7 @@ namespace FishROV.AvoidanceBenchmark
private AvoidanceBenchmarkConfig config;
private bool initialized;
- public string Name => "RVO2 / RVO2-3D 本地避障";
+ public string Name => "RVO2 本地避障";
public bool IsAvailable => bridge != null && bridge.IsAvailable;
public string Status => bridge != null
? bridge.Status
@@ -52,6 +52,7 @@ namespace FishROV.AvoidanceBenchmark
return;
}
+ bridge.SetAgentPosition(id, agent.transform.position);
bridge.SetPreferredVelocity(id, preferredVelocity);
}
@@ -104,6 +105,7 @@ namespace FishROV.AvoidanceBenchmark
private readonly string status;
private readonly MethodInfo addAgent;
private readonly MethodInfo setAgentPrefVelocity;
+ private readonly MethodInfo setAgentPosition;
private readonly MethodInfo doStep;
private readonly MethodInfo getAgentVelocity;
private readonly MethodInfo setTimeStep;
@@ -119,6 +121,7 @@ namespace FishROV.AvoidanceBenchmark
string status,
MethodInfo addAgent,
MethodInfo setAgentPrefVelocity,
+ MethodInfo setAgentPosition,
MethodInfo doStep,
MethodInfo getAgentVelocity,
MethodInfo setTimeStep,
@@ -133,6 +136,7 @@ namespace FishROV.AvoidanceBenchmark
this.status = status;
this.addAgent = addAgent;
this.setAgentPrefVelocity = setAgentPrefVelocity;
+ this.setAgentPosition = setAgentPosition;
this.doStep = doStep;
this.getAgentVelocity = getAgentVelocity;
this.setTimeStep = setTimeStep;
@@ -168,6 +172,7 @@ namespace FishROV.AvoidanceBenchmark
var addAgent = FindMethod(simulatorType, "addAgent", "AddAgent", new[] { agentVectorType });
var setAgentPrefVelocity = FindMethod(simulatorType, "setAgentPrefVelocity", "SetAgentPrefVelocity", new[] { typeof(int), agentVectorType });
+ var setAgentPosition = FindMethod(simulatorType, "setAgentPosition", "SetAgentPosition", new[] { typeof(int), agentVectorType });
var getAgentVelocity = FindMethod(simulatorType, "getAgentVelocity", "GetAgentVelocity", new[] { typeof(int) });
var doStep = FindMethod(simulatorType, "doStep", "DoStep", Type.EmptyTypes);
var setTimeStep = FindMethod(simulatorType, "setTimeStep", "SetTimeStep", new[] { typeof(float) });
@@ -188,6 +193,7 @@ namespace FishROV.AvoidanceBenchmark
use3D ? "RVO2-3D 已通过反射接入。" : "RVO2 已通过反射接入。",
addAgent,
setAgentPrefVelocity,
+ setAgentPosition,
doStep,
getAgentVelocity,
setTimeStep,
@@ -212,6 +218,23 @@ namespace FishROV.AvoidanceBenchmark
}
}
+ public void SetAgentPosition(int id, Vector3 position)
+ {
+ if (setAgentPosition == null)
+ {
+ return;
+ }
+
+ try
+ {
+ setAgentPosition.Invoke(simulator, new[] { id, ToRvoVector(position) });
+ }
+ catch (Exception exception)
+ {
+ Debug.LogWarning($"RVO2 同步 Agent 位置失败:{exception.Message}");
+ }
+ }
+
public void SetPreferredVelocity(int id, Vector3 preferredVelocity)
{
try
@@ -435,7 +458,7 @@ namespace FishROV.AvoidanceBenchmark
private static Rvo2ReflectionBridge Unavailable(string status = MissingPackageStatus)
{
- return new Rvo2ReflectionBridge(null, null, null, null, false, status, null, null, null, null, null, null, null);
+ return new Rvo2ReflectionBridge(null, null, null, null, false, status, null, null, null, null, null, null, null, null);
}
private static object CreateOrGetSimulator(Type type)
diff --git a/FishROV/Assets/ThirdParty.meta b/FishROV/Assets/ThirdParty.meta
new file mode 100644
index 0000000..a0c4a41
--- /dev/null
+++ b/FishROV/Assets/ThirdParty.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 08562b8a001a1ee459ff33a1ad143d23
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS.meta b/FishROV/Assets/ThirdParty/RVO2-CS.meta
new file mode 100644
index 0000000..d111da2
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3d0866b55235ff948be97fbeb160eb12
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/LICENSE b/FishROV/Assets/ThirdParty/RVO2-CS/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/LICENSE.meta b/FishROV/Assets/ThirdParty/RVO2-CS/LICENSE.meta
new file mode 100644
index 0000000..d61cc4c
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/LICENSE.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 2e6d028a17551e240ae4528dcafd0158
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/LICENSES.meta b/FishROV/Assets/ThirdParty/RVO2-CS/LICENSES.meta
new file mode 100644
index 0000000..df242a2
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/LICENSES.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: cb86a7b56767e3b4e9c9b2614f8dfaf0
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/LICENSES/Apache-2.0.txt b/FishROV/Assets/ThirdParty/RVO2-CS/LICENSES/Apache-2.0.txt
new file mode 100644
index 0000000..0605966
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/LICENSES/Apache-2.0.txt
@@ -0,0 +1,190 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction, and
+ distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by the
+ copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all other
+ entities that control, are controlled by, or are under common control with
+ that entity. For the purposes of this definition, "control" means (i) the
+ power, direct or indirect, to cause the direction or management of such
+ entity, whether by contract or otherwise, or (ii) ownership of fifty percent
+ (50%) or more of the outstanding shares, or (iii) beneficial ownership of
+ such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity exercising
+ permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation source, and
+ configuration files.
+
+ "Object" form shall mean any form resulting from mechanical transformation
+ or translation of a Source form, including but not limited to compiled
+ object code, generated documentation, and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or Object form,
+ made available under the License, as indicated by a copyright notice that is
+ included in or attached to the work (an example is provided in the Appendix
+ below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object form,
+ that is based on (or derived from) the Work and for which the editorial
+ revisions, annotations, elaborations, or other modifications represent, as a
+ whole, an original work of authorship. For the purposes of this License,
+ Derivative Works shall not include works that remain separable from, or
+ merely link (or bind by name) to the interfaces of, the Work and Derivative
+ Works thereof.
+
+ "Contribution" shall mean any work of authorship, including the original
+ version of the Work and any modifications or additions to that Work or
+ Derivative Works thereof, that is intentionally submitted to Licensor for
+ inclusion in the Work by the copyright owner or by an individual or Legal
+ Entity authorized to submit on behalf of the copyright owner. For the
+ purposes of this definition, "submitted" means any form of electronic,
+ verbal, or written communication sent to the Licensor or its
+ representatives, including but not limited to communication on electronic
+ mailing lists, source code control systems, and issue tracking systems that
+ are managed by, or on behalf of, the Licensor for the purpose of discussing
+ and improving the Work, but excluding communication that is conspicuously
+ marked or otherwise designated in writing by the copyright owner as "Not a
+ Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity on
+ behalf of whom a Contribution has been received by Licensor and subsequently
+ incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this
+ License, each Contributor hereby grants to You a perpetual, worldwide,
+ non-exclusive, no-charge, royalty-free, irrevocable copyright license to
+ reproduce, prepare Derivative Works of, publicly display, publicly perform,
+ sublicense, and distribute the Work and such Derivative Works in Source or
+ Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this
+ License, each Contributor hereby grants to You a perpetual, worldwide,
+ non-exclusive, no-charge, royalty-free, irrevocable (except as stated in
+ this section) patent license to make, have made, use, offer to sell, sell,
+ import, and otherwise transfer the Work, where such license applies only to
+ those patent claims licensable by such Contributor that are necessarily
+ infringed by their Contribution(s) alone or by combination of their
+ Contribution(s) with the Work to which such Contribution(s) was submitted.
+ If You institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+ Contribution incorporated within the Work constitutes direct or contributory
+ patent infringement, then any patent licenses granted to You under this
+ License for that Work shall terminate as of the date such litigation is
+ filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or
+ Derivative Works thereof in any medium, with or without modifications, and
+ in Source or Object form, provided that You meet the following conditions:
+
+ (a) You must give any other recipients of the Work or Derivative Works a
+ copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices stating
+ that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works that You
+ distribute, all copyright, patent, trademark, and attribution notices
+ from the Source form of the Work, excluding those notices that do not
+ pertain to any part of the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its distribution,
+ then any Derivative Works that You distribute must include a readable
+ copy of the attribution notices contained within such NOTICE file,
+ excluding those notices that do not pertain to any part of the
+ Derivative Works, in at least one of the following places: within a
+ NOTICE text file distributed as part of the Derivative Works; within the
+ Source form or documentation, if provided along with the Derivative
+ Works; or, within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents of the
+ NOTICE file are for informational purposes only and do not modify the
+ License. You may add Your own attribution notices within Derivative
+ Works that You distribute, alongside or as an addendum to the NOTICE
+ text from the Work, provided that such additional attribution notices
+ cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may
+ provide additional or different license terms and conditions for use,
+ reproduction, or distribution of Your modifications, or for any such
+ Derivative Works as a whole, provided Your use, reproduction, and
+ distribution of the Work otherwise complies with the conditions stated in
+ this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any
+ Contribution intentionally submitted for inclusion in the Work by You to the
+ Licensor shall be under the terms and conditions of this License, without
+ any additional terms or conditions. Notwithstanding the above, nothing
+ herein shall supersede or modify the terms of any separate license agreement
+ you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names,
+ trademarks, service marks, or product names of the Licensor, except as
+ required for reasonable and customary use in describing the origin of the
+ Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in
+ writing, Licensor provides the Work (and each Contributor provides its
+ Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied, including, without limitation, any
+ warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or
+ FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining
+ the appropriateness of using or redistributing the Work and assume any risks
+ associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in
+ tort (including negligence), contract, or otherwise, unless required by
+ applicable law (such as deliberate and grossly negligent acts) or agreed to
+ in writing, shall any Contributor be liable to You for damages, including
+ any direct, indirect, special, incidental, or consequential damages of any
+ character arising as a result of this License or out of the use or inability
+ to use the Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all other
+ commercial damages or losses), even if such Contributor has been advised of
+ the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or
+ Derivative Works thereof, You may choose to offer, and charge a fee for,
+ acceptance of support, warranty, indemnity, or other liability obligations
+ and/or rights consistent with this License. However, in accepting such
+ obligations, You may act only on Your own behalf and on Your sole
+ responsibility, not on behalf of any other Contributor, and only if You
+ agree to indemnify, defend, and hold each Contributor harmless for any
+ liability incurred by, or claims asserted against, such Contributor by
+ reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following boilerplate
+ notice, with the fields enclosed by brackets "[]" replaced with your own
+ identifying information. (Don't include the brackets!) The text should be
+ enclosed in the appropriate comment syntax for the file format. We also
+ recommend that a file or class name and description of purpose be included
+ on the same "printed page" as the copyright notice for easier identification
+ within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/LICENSES/Apache-2.0.txt.meta b/FishROV/Assets/ThirdParty/RVO2-CS/LICENSES/Apache-2.0.txt.meta
new file mode 100644
index 0000000..db77208
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/LICENSES/Apache-2.0.txt.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: a6d8b6920c5e24c40ac8c3b79ef24675
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/README.md b/FishROV/Assets/ThirdParty/RVO2-CS/README.md
new file mode 100644
index 0000000..253c95e
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/README.md
@@ -0,0 +1,111 @@
+
+
+Optimal Reciprocal Collision Avoidance for C#
+=============================================
+
+
+
+[](https://zenodo.org/badge/latestdoi/45011155)
+
+We present a formal approach to reciprocal collision avoidance, where multiple
+independent mobile robots or agents need to avoid collisions with each other
+without communication among agents while moving in a common workspace. Our
+formulation, optimal reciprocal collision avoidance (ORCA), provides sufficient
+conditions for collision-free motion by letting each agent take half of the
+responsibility of avoiding pairwise collisions. Selecting the optimal action for
+each agent is reduced to solving a low-dimensional linear program, and we prove
+that the resulting motions are smooth. We test our optimal reciprocal collision
+avoidance approach on several dense and complex simulation scenarios workspaces
+involving thousands of agents, and compute collision-free actions for all of
+them in only a few milliseconds.
+
+RVO2 Library C# is an open-source C# .NET 10 implementation of our algorithm in
+two dimensions. It has a simple API for third-party applications. The user
+specifies static obstacles, agents, and the preferred velocities of the agents.
+The simulation is performed step-by-step via a simple call to the library. The
+simulation is fully accessible and manipulable during runtime.
+
+
+
+
+SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Please send all bug reports to [geom@cs.unc.edu](mailto:geom@cs.unc.edu).
+
+The authors may be contacted via:
+
+Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+Dept. of Computer Science
+201 S. Columbia St.
+Frederick P. Brooks, Jr. Computer Science Bldg.
+Chapel Hill, N.C. 27599-3175
+United States of America
+
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/README.md.meta b/FishROV/Assets/ThirdParty/RVO2-CS/README.md.meta
new file mode 100644
index 0000000..a48f417
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/README.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: d4db5e3fc23bec64cb3ea454f330224a
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS.meta b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS.meta
new file mode 100644
index 0000000..1213a8c
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 6af893cb0842767489c05c232f3c840c
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Agent.cs b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Agent.cs
new file mode 100644
index 0000000..8fc11ff
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Agent.cs
@@ -0,0 +1,719 @@
+/*
+ * Agent.cs
+ * RVO2 Library C#
+ *
+ * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to .
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+
+namespace RVO
+{
+ /// Defines an agent in the simulation.
+ internal class Agent
+ {
+ internal IList> _agentNeighbors = new List>();
+ internal IList> _obstacleNeighbors = new List>();
+ internal IList _orcaLines = new List();
+ internal Vector2 _position;
+ internal Vector2 _prefVelocity;
+ internal Vector2 _velocity;
+ internal int _id = 0;
+ internal int _maxNeighbors = 0;
+ internal float _maxSpeed = 0.0f;
+ internal float _neighborDist = 0.0f;
+ internal float _radius = 0.0f;
+ internal float _timeHorizon = 0.0f;
+ internal float _timeHorizonObst = 0.0f;
+
+ private Vector2 _newVelocity;
+
+ /// Computes the neighbors of this agent.
+ internal void ComputeNeighbors()
+ {
+ _obstacleNeighbors.Clear();
+ float range = _timeHorizonObst * _maxSpeed + _radius;
+ float rangeSq = range * range;
+ Simulator.Instance._kdTree.ComputeObstacleNeighbors(this, rangeSq);
+
+ _agentNeighbors.Clear();
+
+ if (_maxNeighbors > 0)
+ {
+ rangeSq = _neighborDist * _neighborDist;
+ Simulator.Instance._kdTree.ComputeAgentNeighbors(this, ref rangeSq);
+ }
+ }
+
+ /// Computes the new velocity of this agent.
+ internal void ComputeNewVelocity()
+ {
+ _orcaLines.Clear();
+
+ float invTimeHorizonObst = 1.0f / _timeHorizonObst;
+
+ /* Create obstacle ORCA lines. */
+ for (int i = 0; i < _obstacleNeighbors.Count; ++i)
+ {
+
+ Obstacle obstacle1 = _obstacleNeighbors[i].Value;
+ Obstacle obstacle2 = obstacle1._next;
+
+ Vector2 relativePosition1 = obstacle1._point - _position;
+ Vector2 relativePosition2 = obstacle2._point - _position;
+
+ /*
+ * Check if velocity obstacle of obstacle is already taken care
+ * of by previously constructed obstacle ORCA lines.
+ */
+ bool alreadyCovered = false;
+
+ for (int j = 0; j < _orcaLines.Count; ++j)
+ {
+ if (RVOMath.Det(invTimeHorizonObst * relativePosition1 - _orcaLines[j].Point, _orcaLines[j].Direction) - invTimeHorizonObst * _radius >= -RVOMath.RVO_EPSILON && RVOMath.Det(invTimeHorizonObst * relativePosition2 - _orcaLines[j].Point, _orcaLines[j].Direction) - invTimeHorizonObst * _radius >= -RVOMath.RVO_EPSILON)
+ {
+ alreadyCovered = true;
+
+ break;
+ }
+ }
+
+ if (alreadyCovered)
+ {
+ continue;
+ }
+
+ /* Not yet covered. Check for collisions. */
+ float distSq1 = RVOMath.AbsSq(relativePosition1);
+ float distSq2 = RVOMath.AbsSq(relativePosition2);
+
+ float radiusSq = _radius * _radius;
+
+ Vector2 obstacleVector = obstacle2._point - obstacle1._point;
+ float s = (-relativePosition1 * obstacleVector) / RVOMath.AbsSq(obstacleVector);
+ float distSqLine = RVOMath.AbsSq(-relativePosition1 - s * obstacleVector);
+
+ Line line;
+
+ if (s < 0.0f && distSq1 <= radiusSq)
+ {
+ /* Collision with left vertex. Ignore if non-convex. */
+ if (obstacle1._convex)
+ {
+ line.Point = new Vector2(0.0f, 0.0f);
+ line.Direction = RVOMath.Normalize(new Vector2(-relativePosition1.Y, relativePosition1.X));
+ _orcaLines.Add(line);
+ }
+
+ continue;
+ }
+ else if (s > 1.0f && distSq2 <= radiusSq)
+ {
+ /*
+ * Collision with right vertex. Ignore if non-convex or if
+ * it will be taken care of by neighboring obstacle.
+ */
+ if (obstacle2._convex && RVOMath.Det(relativePosition2, obstacle2._direction) >= 0.0f)
+ {
+ line.Point = new Vector2(0.0f, 0.0f);
+ line.Direction = RVOMath.Normalize(new Vector2(-relativePosition2.Y, relativePosition2.X));
+ _orcaLines.Add(line);
+ }
+
+ continue;
+ }
+ else if (s >= 0.0f && s <= 1.0f && distSqLine <= radiusSq)
+ {
+ /* Collision with obstacle segment. */
+ line.Point = new Vector2(0.0f, 0.0f);
+ line.Direction = -obstacle1._direction;
+ _orcaLines.Add(line);
+
+ continue;
+ }
+
+ /*
+ * No collision. Compute legs. When obliquely viewed, both legs
+ * can come from a single vertex. Legs extend cut-off line when
+ * non-convex vertex.
+ */
+
+ Vector2 leftLegDirection, rightLegDirection;
+
+ if (s < 0.0f && distSqLine <= radiusSq)
+ {
+ /*
+ * Obstacle viewed obliquely so that left vertex
+ * defines velocity obstacle.
+ */
+ if (!obstacle1._convex)
+ {
+ /* Ignore obstacle. */
+ continue;
+ }
+
+ obstacle2 = obstacle1;
+
+ float leg1 = MathF.Sqrt(distSq1 - radiusSq);
+ leftLegDirection = new Vector2(relativePosition1.X * leg1 - relativePosition1.Y * _radius, relativePosition1.X * _radius + relativePosition1.Y * leg1) / distSq1;
+ rightLegDirection = new Vector2(relativePosition1.X * leg1 + relativePosition1.Y * _radius, -relativePosition1.X * _radius + relativePosition1.Y * leg1) / distSq1;
+ }
+ else if (s > 1.0f && distSqLine <= radiusSq)
+ {
+ /*
+ * Obstacle viewed obliquely so that
+ * right vertex defines velocity obstacle.
+ */
+ if (!obstacle2._convex)
+ {
+ /* Ignore obstacle. */
+ continue;
+ }
+
+ obstacle1 = obstacle2;
+
+ float leg2 = MathF.Sqrt(distSq2 - radiusSq);
+ leftLegDirection = new Vector2(relativePosition2.X * leg2 - relativePosition2.Y * _radius, relativePosition2.X * _radius + relativePosition2.Y * leg2) / distSq2;
+ rightLegDirection = new Vector2(relativePosition2.X * leg2 + relativePosition2.Y * _radius, -relativePosition2.X * _radius + relativePosition2.Y * leg2) / distSq2;
+ }
+ else
+ {
+ /* Usual situation. */
+ if (obstacle1._convex)
+ {
+ float leg1 = MathF.Sqrt(distSq1 - radiusSq);
+ leftLegDirection = new Vector2(relativePosition1.X * leg1 - relativePosition1.Y * _radius, relativePosition1.X * _radius + relativePosition1.Y * leg1) / distSq1;
+ }
+ else
+ {
+ /* Left vertex non-convex; left leg extends cut-off line. */
+ leftLegDirection = -obstacle1._direction;
+ }
+
+ if (obstacle2._convex)
+ {
+ float leg2 = MathF.Sqrt(distSq2 - radiusSq);
+ rightLegDirection = new Vector2(relativePosition2.X * leg2 + relativePosition2.Y * _radius, -relativePosition2.X * _radius + relativePosition2.Y * leg2) / distSq2;
+ }
+ else
+ {
+ /* Right vertex non-convex; right leg extends cut-off line. */
+ rightLegDirection = obstacle1._direction;
+ }
+ }
+
+ /*
+ * Legs can never point into neighboring edge when convex
+ * vertex, take cutoff-line of neighboring edge instead. If
+ * velocity projected on "foreign" leg, no constraint is added.
+ */
+
+ Obstacle leftNeighbor = obstacle1._previous;
+
+ bool isLeftLegForeign = false;
+ bool isRightLegForeign = false;
+
+ if (obstacle1._convex && RVOMath.Det(leftLegDirection, -leftNeighbor._direction) >= 0.0f)
+ {
+ /* Left leg points into obstacle. */
+ leftLegDirection = -leftNeighbor._direction;
+ isLeftLegForeign = true;
+ }
+
+ if (obstacle2._convex && RVOMath.Det(rightLegDirection, obstacle2._direction) <= 0.0f)
+ {
+ /* Right leg points into obstacle. */
+ rightLegDirection = obstacle2._direction;
+ isRightLegForeign = true;
+ }
+
+ /* Compute cut-off centers. */
+ Vector2 leftCutOff = invTimeHorizonObst * (obstacle1._point - _position);
+ Vector2 rightCutOff = invTimeHorizonObst * (obstacle2._point - _position);
+ Vector2 cutOffVector = rightCutOff - leftCutOff;
+
+ /* Project current velocity on velocity obstacle. */
+
+ /* Check if current velocity is projected on cutoff circles. */
+ float t = obstacle1 == obstacle2 ? 0.5f : ((_velocity - leftCutOff) * cutOffVector) / RVOMath.AbsSq(cutOffVector);
+ float tLeft = (_velocity - leftCutOff) * leftLegDirection;
+ float tRight = (_velocity - rightCutOff) * rightLegDirection;
+
+ if ((t < 0.0f && tLeft < 0.0f) || (obstacle1 == obstacle2 && tLeft < 0.0f && tRight < 0.0f))
+ {
+ /* Project on left cut-off circle. */
+ Vector2 unitW = RVOMath.Normalize(_velocity - leftCutOff);
+
+ line.Direction = new Vector2(unitW.Y, -unitW.X);
+ line.Point = leftCutOff + _radius * invTimeHorizonObst * unitW;
+ _orcaLines.Add(line);
+
+ continue;
+ }
+ else if (t > 1.0f && tRight < 0.0f)
+ {
+ /* Project on right cut-off circle. */
+ Vector2 unitW = RVOMath.Normalize(_velocity - rightCutOff);
+
+ line.Direction = new Vector2(unitW.Y, -unitW.X);
+ line.Point = rightCutOff + _radius * invTimeHorizonObst * unitW;
+ _orcaLines.Add(line);
+
+ continue;
+ }
+
+ /*
+ * Project on left leg, right leg, or cut-off line, whichever is
+ * closest to velocity.
+ */
+ float distSqCutoff = (t < 0.0f || t > 1.0f || obstacle1 == obstacle2) ? float.PositiveInfinity : RVOMath.AbsSq(_velocity - (leftCutOff + t * cutOffVector));
+ float distSqLeft = tLeft < 0.0f ? float.PositiveInfinity : RVOMath.AbsSq(_velocity - (leftCutOff + tLeft * leftLegDirection));
+ float distSqRight = tRight < 0.0f ? float.PositiveInfinity : RVOMath.AbsSq(_velocity - (rightCutOff + tRight * rightLegDirection));
+
+ if (distSqCutoff <= distSqLeft && distSqCutoff <= distSqRight)
+ {
+ /* Project on cut-off line. */
+ line.Direction = -obstacle1._direction;
+ line.Point = leftCutOff + _radius * invTimeHorizonObst * new Vector2(-line.Direction.Y, line.Direction.X);
+ _orcaLines.Add(line);
+
+ continue;
+ }
+
+ if (distSqLeft <= distSqRight)
+ {
+ /* Project on left leg. */
+ if (isLeftLegForeign)
+ {
+ continue;
+ }
+
+ line.Direction = leftLegDirection;
+ line.Point = leftCutOff + _radius * invTimeHorizonObst * new Vector2(-line.Direction.Y, line.Direction.X);
+ _orcaLines.Add(line);
+
+ continue;
+ }
+
+ /* Project on right leg. */
+ if (isRightLegForeign)
+ {
+ continue;
+ }
+
+ line.Direction = -rightLegDirection;
+ line.Point = rightCutOff + _radius * invTimeHorizonObst * new Vector2(-line.Direction.Y, line.Direction.X);
+ _orcaLines.Add(line);
+ }
+
+ int numObstLines = _orcaLines.Count;
+
+ float invTimeHorizon = 1.0f / _timeHorizon;
+
+ /* Create agent ORCA lines. */
+ for (int i = 0; i < _agentNeighbors.Count; ++i)
+ {
+ Agent other = _agentNeighbors[i].Value;
+
+ Vector2 relativePosition = other._position - _position;
+ Vector2 relativeVelocity = _velocity - other._velocity;
+ float distSq = RVOMath.AbsSq(relativePosition);
+ float combinedRadius = _radius + other._radius;
+ float combinedRadiusSq = combinedRadius * combinedRadius;
+
+ Line line;
+ Vector2 u;
+
+ if (distSq > combinedRadiusSq)
+ {
+ /* No collision. */
+ Vector2 w = relativeVelocity - invTimeHorizon * relativePosition;
+
+ /* Vector from cutoff center to relative velocity. */
+ float wLengthSq = RVOMath.AbsSq(w);
+ float dotProduct1 = w * relativePosition;
+
+ if (dotProduct1 < 0.0f && dotProduct1 * dotProduct1 > combinedRadiusSq * wLengthSq)
+ {
+ /* Project on cut-off circle. */
+ float wLength = MathF.Sqrt(wLengthSq);
+ Vector2 unitW = w / wLength;
+
+ line.Direction = new Vector2(unitW.Y, -unitW.X);
+ u = (combinedRadius * invTimeHorizon - wLength) * unitW;
+ }
+ else
+ {
+ /* Project on legs. */
+ float leg = MathF.Sqrt(distSq - combinedRadiusSq);
+
+ if (RVOMath.Det(relativePosition, w) > 0.0f)
+ {
+ /* Project on left leg. */
+ line.Direction = new Vector2(relativePosition.X * leg - relativePosition.Y * combinedRadius, relativePosition.X * combinedRadius + relativePosition.Y * leg) / distSq;
+ }
+ else
+ {
+ /* Project on right leg. */
+ line.Direction = -new Vector2(relativePosition.X * leg + relativePosition.Y * combinedRadius, -relativePosition.X * combinedRadius + relativePosition.Y * leg) / distSq;
+ }
+
+ float dotProduct2 = relativeVelocity * line.Direction;
+ u = dotProduct2 * line.Direction - relativeVelocity;
+ }
+ }
+ else
+ {
+ /* Collision. Project on cut-off circle of time timeStep. */
+ float invTimeStep = 1.0f / Simulator.Instance.TimeStep;
+
+ /* Vector from cutoff center to relative velocity. */
+ Vector2 w = relativeVelocity - invTimeStep * relativePosition;
+
+ float wLength = RVOMath.Abs(w);
+ Vector2 unitW = w / wLength;
+
+ line.Direction = new Vector2(unitW.Y, -unitW.X);
+ u = (combinedRadius * invTimeStep - wLength) * unitW;
+ }
+
+ line.Point = _velocity + 0.5f * u;
+ _orcaLines.Add(line);
+ }
+
+ int lineFail = LinearProgram2(_orcaLines, _maxSpeed, _prefVelocity, false, out _newVelocity);
+
+ if (lineFail < _orcaLines.Count)
+ {
+ LinearProgram3(_orcaLines, numObstLines, lineFail, _maxSpeed, ref _newVelocity);
+ }
+ }
+
+ /// Inserts an agent neighbor into the set of neighbors of this
+ /// agent.
+ ///
+ /// A pointer to the agent to be inserted.
+ /// The squared range around this agent.
+ internal void InsertAgentNeighbor(Agent agent, ref float rangeSq)
+ {
+ if (this != agent)
+ {
+ float distSq = RVOMath.AbsSq(_position - agent._position);
+
+ if (distSq < rangeSq)
+ {
+ if (_agentNeighbors.Count < _maxNeighbors)
+ {
+ _agentNeighbors.Add(new KeyValuePair(distSq, agent));
+ }
+
+ int i = _agentNeighbors.Count - 1;
+
+ while (i != 0 && distSq < _agentNeighbors[i - 1].Key)
+ {
+ _agentNeighbors[i] = _agentNeighbors[i - 1];
+ --i;
+ }
+
+ _agentNeighbors[i] = new KeyValuePair(distSq, agent);
+
+ if (_agentNeighbors.Count == _maxNeighbors)
+ {
+ rangeSq = _agentNeighbors[_agentNeighbors.Count - 1].Key;
+ }
+ }
+ }
+ }
+
+ /// Inserts a static obstacle neighbor into the set of neighbors
+ /// of this agent.
+ ///
+ /// The number of the static obstacle to be
+ /// inserted.
+ /// The squared range around this agent.
+ internal void InsertObstacleNeighbor(Obstacle obstacle, float rangeSq)
+ {
+ Obstacle nextObstacle = obstacle._next;
+
+ float distSq = RVOMath.DistSqPointLineSegment(obstacle._point, nextObstacle._point, _position);
+
+ if (distSq < rangeSq)
+ {
+ _obstacleNeighbors.Add(new KeyValuePair(distSq, obstacle));
+
+ int i = _obstacleNeighbors.Count - 1;
+
+ while (i != 0 && distSq < _obstacleNeighbors[i - 1].Key)
+ {
+ _obstacleNeighbors[i] = _obstacleNeighbors[i - 1];
+ --i;
+ }
+ _obstacleNeighbors[i] = new KeyValuePair(distSq, obstacle);
+ }
+ }
+
+ /// Updates the two-dimensional position and two-dimensional
+ /// velocity of this agent.
+ internal void Update()
+ {
+ _velocity = _newVelocity;
+
+ if (RVOMath.AbsSq(_velocity) > _maxSpeed * _maxSpeed)
+ {
+ _velocity = RVOMath.Normalize(_velocity) * _maxSpeed;
+ }
+
+ _position += _velocity * Simulator.Instance.TimeStep;
+ }
+
+ /// Solves a one-dimensional linear program on a specified line
+ /// subject to linear constraints defined by lines and a circular
+ /// constraint.
+ ///
+ /// True if successful.
+ ///
+ /// Lines defining the linear constraints.
+ /// The specified line constraint.
+ /// The radius of the circular constraint.
+ /// The optimization velocity.
+ /// True if the direction should be optimized.
+ ///
+ /// A reference to the result of the linear program.
+ ///
+ private bool LinearProgram1(IList lines, int lineNo, float radius, Vector2 optVelocity, bool directionOpt, ref Vector2 result)
+ {
+ float dotProduct = lines[lineNo].Point * lines[lineNo].Direction;
+ float discriminant = dotProduct * dotProduct + radius * radius - RVOMath.AbsSq(lines[lineNo].Point);
+
+ if (discriminant < 0.0f)
+ {
+ /* Max speed circle fully invalidates line lineNo. */
+ return false;
+ }
+
+ float sqrtDiscriminant = MathF.Sqrt(discriminant);
+ float tLeft = -dotProduct - sqrtDiscriminant;
+ float tRight = -dotProduct + sqrtDiscriminant;
+
+ for (int i = 0; i < lineNo; ++i)
+ {
+ float denominator = RVOMath.Det(lines[lineNo].Direction, lines[i].Direction);
+ float numerator = RVOMath.Det(lines[i].Direction, lines[lineNo].Point - lines[i].Point);
+
+ if (MathF.Abs(denominator) <= RVOMath.RVO_EPSILON)
+ {
+ /* Lines lineNo and i are (almost) parallel. */
+ if (numerator < 0.0f)
+ {
+ return false;
+ }
+
+ continue;
+ }
+
+ float t = numerator / denominator;
+
+ if (denominator >= 0.0f)
+ {
+ /* Line i bounds line lineNo on the right. */
+ tRight = Math.Min(tRight, t);
+ }
+ else
+ {
+ /* Line i bounds line lineNo on the left. */
+ tLeft = Math.Max(tLeft, t);
+ }
+
+ if (tLeft > tRight)
+ {
+ return false;
+ }
+ }
+
+ if (directionOpt)
+ {
+ /* Optimize direction. */
+ if (optVelocity * lines[lineNo].Direction > 0.0f)
+ {
+ /* Take right extreme. */
+ result = lines[lineNo].Point + tRight * lines[lineNo].Direction;
+ }
+ else
+ {
+ /* Take left extreme. */
+ result = lines[lineNo].Point + tLeft * lines[lineNo].Direction;
+ }
+ }
+ else
+ {
+ /* Optimize closest point. */
+ float t = lines[lineNo].Direction * (optVelocity - lines[lineNo].Point);
+
+ if (t < tLeft)
+ {
+ result = lines[lineNo].Point + tLeft * lines[lineNo].Direction;
+ }
+ else if (t > tRight)
+ {
+ result = lines[lineNo].Point + tRight * lines[lineNo].Direction;
+ }
+ else
+ {
+ result = lines[lineNo].Point + t * lines[lineNo].Direction;
+ }
+ }
+
+ return true;
+ }
+
+ /// Solves a two-dimensional linear program subject to linear
+ /// constraints defined by lines and a circular constraint.
+ ///
+ /// The number of the line it fails on, and the number of lines
+ /// if successful.
+ ///
+ /// Lines defining the linear constraints.
+ /// The radius of the circular constraint.
+ /// The optimization velocity.
+ /// True if the direction should be optimized.
+ ///
+ /// A reference to the result of the linear program.
+ ///
+ private int LinearProgram2(IList lines, float radius, Vector2 optVelocity, bool directionOpt, out Vector2 result)
+ {
+ if (directionOpt)
+ {
+ /*
+ * Optimize direction. Note that the optimization velocity is of
+ * unit length in this case.
+ */
+ result = optVelocity * radius;
+ }
+ else if (RVOMath.AbsSq(optVelocity) > radius * radius)
+ {
+ /* Optimize closest point and outside circle. */
+ result = RVOMath.Normalize(optVelocity) * radius;
+ }
+ else
+ {
+ /* Optimize closest point and inside circle. */
+ result = optVelocity;
+ }
+
+ for (int i = 0; i < lines.Count; ++i)
+ {
+ if (RVOMath.Det(lines[i].Direction, lines[i].Point - result) > 0.0f)
+ {
+ /* Result does not satisfy constraint i. Compute new optimal result. */
+ Vector2 tempResult = result;
+ if (!LinearProgram1(lines, i, radius, optVelocity, directionOpt, ref result))
+ {
+ result = tempResult;
+
+ return i;
+ }
+ }
+ }
+
+ return lines.Count;
+ }
+
+ /// Solves a two-dimensional linear program subject to linear
+ /// constraints defined by lines and a circular constraint.
+ ///
+ /// Lines defining the linear constraints.
+ /// Count of obstacle lines.
+ /// The line on which the 2-d linear program
+ /// failed.
+ /// The radius of the circular constraint.
+ /// A reference to the result of the linear program.
+ ///
+ private void LinearProgram3(IList lines, int numObstLines, int beginLine, float radius, ref Vector2 result)
+ {
+ float distance = 0.0f;
+
+ for (int i = beginLine; i < lines.Count; ++i)
+ {
+ if (RVOMath.Det(lines[i].Direction, lines[i].Point - result) > distance)
+ {
+ /* Result does not satisfy constraint of line i. */
+ IList projLines = new List();
+ for (int ii = 0; ii < numObstLines; ++ii)
+ {
+ projLines.Add(lines[ii]);
+ }
+
+ for (int j = numObstLines; j < i; ++j)
+ {
+ Line line;
+
+ float determinant = RVOMath.Det(lines[i].Direction, lines[j].Direction);
+
+ if (MathF.Abs(determinant) <= RVOMath.RVO_EPSILON)
+ {
+ /* Line i and line j are parallel. */
+ if (lines[i].Direction * lines[j].Direction > 0.0f)
+ {
+ /* Line i and line j point in the same direction. */
+ continue;
+ }
+ else
+ {
+ /* Line i and line j point in opposite direction. */
+ line.Point = 0.5f * (lines[i].Point + lines[j].Point);
+ }
+ }
+ else
+ {
+ line.Point = lines[i].Point + (RVOMath.Det(lines[j].Direction, lines[i].Point - lines[j].Point) / determinant) * lines[i].Direction;
+ }
+
+ line.Direction = RVOMath.Normalize(lines[j].Direction - lines[i].Direction);
+ projLines.Add(line);
+ }
+
+ Vector2 tempResult = result;
+ if (LinearProgram2(projLines, radius, new Vector2(-lines[i].Direction.Y, lines[i].Direction.X), true, out result) < projLines.Count)
+ {
+ /*
+ * This should in principle not happen. The result is by
+ * definition already in the feasible region of this
+ * linear program. If it fails, it is due to small
+ * floating point error, and the current result is kept.
+ */
+ result = tempResult;
+ }
+
+ distance = RVOMath.Det(lines[i].Direction, lines[i].Point - result);
+ }
+ }
+ }
+ }
+}
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Agent.cs.meta b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Agent.cs.meta
new file mode 100644
index 0000000..af6681e
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Agent.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8acc64d87f8b9c14a966b32cd9aab419
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/KdTree.cs b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/KdTree.cs
new file mode 100644
index 0000000..6aab627
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/KdTree.cs
@@ -0,0 +1,590 @@
+/*
+ * KdTree.cs
+ * RVO2 Library C#
+ *
+ * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to .
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+
+namespace RVO
+{
+ /// Defines k-D trees for agents and static obstacles in the
+ /// simulation.
+ internal class KdTree
+ {
+ /// Defines a node of an agent k-D tree.
+ private struct AgentTreeNode
+ {
+ internal int _begin;
+ internal int _end;
+ internal int _left;
+ internal int _right;
+ internal float _maxX;
+ internal float _maxY;
+ internal float _minX;
+ internal float _minY;
+ }
+
+ /// Defines a pair of scalar values.
+ private struct FloatPair
+ {
+ private readonly float _a;
+ private readonly float _b;
+
+ /// Constructs and initializes a pair of scalar
+ /// values.
+ ///
+ /// The first scalar value.
+ /// The second scalar value.
+ internal FloatPair(float a, float b)
+ {
+ _a = a;
+ _b = b;
+ }
+
+ /// Returns true if the first pair of scalar values is less
+ /// than the second pair of scalar values.
+ ///
+ /// True if the first pair of scalar values is less than the
+ /// second pair of scalar values.
+ ///
+ /// The first pair of scalar values.
+ /// The second pair of scalar values.
+ public static bool operator <(FloatPair pair1, FloatPair pair2)
+ {
+ return pair1._a < pair2._a || pair1._a == pair2._a && pair1._b < pair2._b;
+ }
+
+ /// Returns true if the first pair of scalar values is less
+ /// than or equal to the second pair of scalar values.
+ ///
+ /// True if the first pair of scalar values is less than or
+ /// equal to the second pair of scalar values.
+ ///
+ /// The first pair of scalar values.
+ /// The second pair of scalar values.
+ public static bool operator <=(FloatPair pair1, FloatPair pair2)
+ {
+ return (pair1._a == pair2._a && pair1._b == pair2._b) || pair1 < pair2;
+ }
+
+ /// Returns true if the first pair of scalar values is
+ /// greater than the second pair of scalar values.
+ ///
+ /// True if the first pair of scalar values is greater than
+ /// the second pair of scalar values.
+ ///
+ /// The first pair of scalar values.
+ /// The second pair of scalar values.
+ public static bool operator >(FloatPair pair1, FloatPair pair2)
+ {
+ return !(pair1 <= pair2);
+ }
+
+ /// Returns true if the first pair of scalar values is
+ /// greater than or equal to the second pair of scalar values.
+ ///
+ ///
+ /// True if the first pair of scalar values is greater than
+ /// or equal to the second pair of scalar values.
+ ///
+ /// The first pair of scalar values.
+ /// The second pair of scalar values.
+ public static bool operator >=(FloatPair pair1, FloatPair pair2)
+ {
+ return !(pair1 < pair2);
+ }
+ }
+
+ /// Defines a node of an obstacle k-D tree.
+ private class ObstacleTreeNode
+ {
+ internal Obstacle _obstacle;
+ internal ObstacleTreeNode _left;
+ internal ObstacleTreeNode _right;
+ };
+
+ /// The maximum size of an agent k-D tree leaf.
+ /* Empirically chosen; balances tree depth against per-leaf work. */
+ private const int MAX_LEAF_SIZE = 10;
+
+ private Agent[] _agents;
+ private AgentTreeNode[] _agentTree;
+ private ObstacleTreeNode _obstacleTree;
+
+ /// Builds an agent k-D tree.
+ internal void BuildAgentTree()
+ {
+ if (_agents is null || _agents.Length != Simulator.Instance._agents.Count)
+ {
+ _agents = new Agent[Simulator.Instance._agents.Count];
+
+ for (int i = 0; i < _agents.Length; ++i)
+ {
+ _agents[i] = Simulator.Instance._agents[i];
+ }
+
+ _agentTree = new AgentTreeNode[2 * _agents.Length];
+
+ for (int i = 0; i < _agentTree.Length; ++i)
+ {
+ _agentTree[i] = new AgentTreeNode();
+ }
+ }
+
+ if (_agents.Length != 0)
+ {
+ BuildAgentTreeRecursive(0, _agents.Length, 0);
+ }
+ }
+
+ /// Builds an obstacle k-D tree.
+ internal void BuildObstacleTree()
+ {
+ _obstacleTree = new ObstacleTreeNode();
+
+ IList obstacles = new List(Simulator.Instance._obstacles.Count);
+
+ for (int i = 0; i < Simulator.Instance._obstacles.Count; ++i)
+ {
+ obstacles.Add(Simulator.Instance._obstacles[i]);
+ }
+
+ _obstacleTree = BuildObstacleTreeRecursive(obstacles);
+ }
+
+ /// Computes the agent neighbors of the specified agent.
+ ///
+ ///
+ /// The agent for which agent neighbors are to be
+ /// computed.
+ /// The squared range around the agent.
+ internal void ComputeAgentNeighbors(Agent agent, ref float rangeSq)
+ {
+ QueryAgentTreeRecursive(agent, ref rangeSq, 0);
+ }
+
+ /// Computes the obstacle neighbors of the specified agent.
+ ///
+ ///
+ /// The agent for which obstacle neighbors are to be
+ /// computed.
+ /// The squared range around the agent.
+ internal void ComputeObstacleNeighbors(Agent agent, float rangeSq)
+ {
+ QueryObstacleTreeRecursive(agent, rangeSq, _obstacleTree);
+ }
+
+ /// Queries the visibility between two points within a specified
+ /// radius.
+ ///
+ /// True if q1 and q2 are mutually visible within the radius;
+ /// false otherwise.
+ ///
+ /// The first point between which visibility is to be
+ /// tested.
+ /// The second point between which visibility is to be
+ /// tested.
+ /// The radius within which visibility is to be
+ /// tested.
+ internal bool QueryVisibility(Vector2 q1, Vector2 q2, float radius)
+ {
+ return QueryVisibilityRecursive(q1, q2, radius, _obstacleTree);
+ }
+
+ /// Recursive method for building an agent k-D tree.
+ ///
+ /// The beginning agent k-D tree node node index.
+ ///
+ /// The ending agent k-D tree node index.
+ /// The current agent k-D tree node index.
+ private void BuildAgentTreeRecursive(int begin, int end, int node)
+ {
+ _agentTree[node]._begin = begin;
+ _agentTree[node]._end = end;
+ _agentTree[node]._minX = _agentTree[node]._maxX = _agents[begin]._position._x;
+ _agentTree[node]._minY = _agentTree[node]._maxY = _agents[begin]._position._y;
+
+ for (int i = begin + 1; i < end; ++i)
+ {
+ _agentTree[node]._maxX = Math.Max(_agentTree[node]._maxX, _agents[i]._position._x);
+ _agentTree[node]._minX = Math.Min(_agentTree[node]._minX, _agents[i]._position._x);
+ _agentTree[node]._maxY = Math.Max(_agentTree[node]._maxY, _agents[i]._position._y);
+ _agentTree[node]._minY = Math.Min(_agentTree[node]._minY, _agents[i]._position._y);
+ }
+
+ if (end - begin > MAX_LEAF_SIZE)
+ {
+ /* No leaf node. */
+ bool isVertical = _agentTree[node]._maxX - _agentTree[node]._minX > _agentTree[node]._maxY - _agentTree[node]._minY;
+ float splitValue = 0.5f * (isVertical ? _agentTree[node]._maxX + _agentTree[node]._minX : _agentTree[node]._maxY + _agentTree[node]._minY);
+
+ int left = begin;
+ int right = end;
+
+ while (left < right)
+ {
+ while (left < right && (isVertical ? _agents[left]._position._x : _agents[left]._position._y) < splitValue)
+ {
+ ++left;
+ }
+
+ while (right > left && (isVertical ? _agents[right - 1]._position._x : _agents[right - 1]._position._y) >= splitValue)
+ {
+ --right;
+ }
+
+ if (left < right)
+ {
+ Agent tempAgent = _agents[left];
+ _agents[left] = _agents[right - 1];
+ _agents[right - 1] = tempAgent;
+ ++left;
+ --right;
+ }
+ }
+
+ int leftSize = left - begin;
+
+ if (leftSize == 0)
+ {
+ ++leftSize;
+ ++left;
+ }
+
+ _agentTree[node]._left = node + 1;
+ _agentTree[node]._right = node + 2 * leftSize;
+
+ BuildAgentTreeRecursive(begin, left, _agentTree[node]._left);
+ BuildAgentTreeRecursive(left, end, _agentTree[node]._right);
+ }
+ }
+
+ /// Recursive method for building an obstacle k-D tree.
+ ///
+ ///
+ /// An obstacle k-D tree node.
+ ///
+ /// A list of obstacles.
+ private ObstacleTreeNode BuildObstacleTreeRecursive(IList obstacles)
+ {
+ if (obstacles.Count == 0)
+ {
+ return null;
+ }
+
+ ObstacleTreeNode node = new();
+
+ int optimalSplit = 0;
+ int minLeft = obstacles.Count;
+ int minRight = obstacles.Count;
+
+ for (int i = 0; i < obstacles.Count; ++i)
+ {
+ int leftSize = 0;
+ int rightSize = 0;
+
+ Obstacle obstacleI1 = obstacles[i];
+ Obstacle obstacleI2 = obstacleI1._next;
+
+ /* Compute optimal split node. */
+ for (int j = 0; j < obstacles.Count; ++j)
+ {
+ if (i == j)
+ {
+ continue;
+ }
+
+ Obstacle obstacleJ1 = obstacles[j];
+ Obstacle obstacleJ2 = obstacleJ1._next;
+
+ float j1LeftOfI = RVOMath.LeftOf(obstacleI1._point, obstacleI2._point, obstacleJ1._point);
+ float j2LeftOfI = RVOMath.LeftOf(obstacleI1._point, obstacleI2._point, obstacleJ2._point);
+
+ if (j1LeftOfI >= -RVOMath.RVO_EPSILON && j2LeftOfI >= -RVOMath.RVO_EPSILON)
+ {
+ ++leftSize;
+ }
+ else if (j1LeftOfI <= RVOMath.RVO_EPSILON && j2LeftOfI <= RVOMath.RVO_EPSILON)
+ {
+ ++rightSize;
+ }
+ else
+ {
+ ++leftSize;
+ ++rightSize;
+ }
+
+ if (new FloatPair(Math.Max(leftSize, rightSize), Math.Min(leftSize, rightSize)) >= new FloatPair(Math.Max(minLeft, minRight), Math.Min(minLeft, minRight)))
+ {
+ break;
+ }
+ }
+
+ if (new FloatPair(Math.Max(leftSize, rightSize), Math.Min(leftSize, rightSize)) < new FloatPair(Math.Max(minLeft, minRight), Math.Min(minLeft, minRight)))
+ {
+ minLeft = leftSize;
+ minRight = rightSize;
+ optimalSplit = i;
+ }
+ }
+
+ {
+ /* Build split node. */
+ IList leftObstacles = new List(minLeft);
+
+ for (int n = 0; n < minLeft; ++n)
+ {
+ leftObstacles.Add(null);
+ }
+
+ IList rightObstacles = new List(minRight);
+
+ for (int n = 0; n < minRight; ++n)
+ {
+ rightObstacles.Add(null);
+ }
+
+ int leftCounter = 0;
+ int rightCounter = 0;
+ int i = optimalSplit;
+
+ Obstacle obstacleI1 = obstacles[i];
+ Obstacle obstacleI2 = obstacleI1._next;
+
+ for (int j = 0; j < obstacles.Count; ++j)
+ {
+ if (i == j)
+ {
+ continue;
+ }
+
+ Obstacle obstacleJ1 = obstacles[j];
+ Obstacle obstacleJ2 = obstacleJ1._next;
+
+ float j1LeftOfI = RVOMath.LeftOf(obstacleI1._point, obstacleI2._point, obstacleJ1._point);
+ float j2LeftOfI = RVOMath.LeftOf(obstacleI1._point, obstacleI2._point, obstacleJ2._point);
+
+ if (j1LeftOfI >= -RVOMath.RVO_EPSILON && j2LeftOfI >= -RVOMath.RVO_EPSILON)
+ {
+ leftObstacles[leftCounter++] = obstacles[j];
+ }
+ else if (j1LeftOfI <= RVOMath.RVO_EPSILON && j2LeftOfI <= RVOMath.RVO_EPSILON)
+ {
+ rightObstacles[rightCounter++] = obstacles[j];
+ }
+ else
+ {
+ /* Split obstacle j. */
+ float t = RVOMath.Det(obstacleI2._point - obstacleI1._point, obstacleJ1._point - obstacleI1._point) / RVOMath.Det(obstacleI2._point - obstacleI1._point, obstacleJ1._point - obstacleJ2._point);
+
+ Vector2 splitPoint = obstacleJ1._point + t * (obstacleJ2._point - obstacleJ1._point);
+
+ Obstacle newObstacle = new();
+ newObstacle._point = splitPoint;
+ newObstacle._previous = obstacleJ1;
+ newObstacle._next = obstacleJ2;
+ newObstacle._convex = true;
+ newObstacle._direction = obstacleJ1._direction;
+
+ newObstacle._id = Simulator.Instance._obstacles.Count;
+
+ Simulator.Instance._obstacles.Add(newObstacle);
+
+ obstacleJ1._next = newObstacle;
+ obstacleJ2._previous = newObstacle;
+
+ if (j1LeftOfI > 0.0f)
+ {
+ leftObstacles[leftCounter++] = obstacleJ1;
+ rightObstacles[rightCounter++] = newObstacle;
+ }
+ else
+ {
+ rightObstacles[rightCounter++] = obstacleJ1;
+ leftObstacles[leftCounter++] = newObstacle;
+ }
+ }
+ }
+
+ node._obstacle = obstacleI1;
+ node._left = BuildObstacleTreeRecursive(leftObstacles);
+ node._right = BuildObstacleTreeRecursive(rightObstacles);
+
+ return node;
+ }
+ }
+
+ /// Recursive method for computing the agent neighbors of the
+ /// specified agent.
+ ///
+ /// The agent for which agent neighbors are to be
+ /// computed.
+ /// The squared range around the agent.
+ /// The current agent k-D tree node index.
+ private void QueryAgentTreeRecursive(Agent agent, ref float rangeSq, int node)
+ {
+ if (_agentTree[node]._end - _agentTree[node]._begin <= MAX_LEAF_SIZE)
+ {
+ for (int i = _agentTree[node]._begin; i < _agentTree[node]._end; ++i)
+ {
+ agent.InsertAgentNeighbor(_agents[i], ref rangeSq);
+ }
+ }
+ else
+ {
+ int leftNode = _agentTree[node]._left;
+ float leftDx = Math.Max(0.0f, _agentTree[leftNode]._minX - agent._position._x) + Math.Max(0.0f, agent._position._x - _agentTree[leftNode]._maxX);
+ float leftDy = Math.Max(0.0f, _agentTree[leftNode]._minY - agent._position._y) + Math.Max(0.0f, agent._position._y - _agentTree[leftNode]._maxY);
+ float distSqLeft = leftDx * leftDx + leftDy * leftDy;
+
+ int rightNode = _agentTree[node]._right;
+ float rightDx = Math.Max(0.0f, _agentTree[rightNode]._minX - agent._position._x) + Math.Max(0.0f, agent._position._x - _agentTree[rightNode]._maxX);
+ float rightDy = Math.Max(0.0f, _agentTree[rightNode]._minY - agent._position._y) + Math.Max(0.0f, agent._position._y - _agentTree[rightNode]._maxY);
+ float distSqRight = rightDx * rightDx + rightDy * rightDy;
+
+ if (distSqLeft < distSqRight)
+ {
+ if (distSqLeft < rangeSq)
+ {
+ QueryAgentTreeRecursive(agent, ref rangeSq, leftNode);
+
+ if (distSqRight < rangeSq)
+ {
+ QueryAgentTreeRecursive(agent, ref rangeSq, rightNode);
+ }
+ }
+ }
+ else
+ {
+ if (distSqRight < rangeSq)
+ {
+ QueryAgentTreeRecursive(agent, ref rangeSq, rightNode);
+
+ if (distSqLeft < rangeSq)
+ {
+ QueryAgentTreeRecursive(agent, ref rangeSq, leftNode);
+ }
+ }
+ }
+
+ }
+ }
+
+ /// Recursive method for computing the obstacle neighbors of the
+ /// specified agent.
+ ///
+ /// The agent for which obstacle neighbors are to be
+ /// computed.
+ /// The squared range around the agent.
+ /// The current obstacle k-D node.
+ private void QueryObstacleTreeRecursive(Agent agent, float rangeSq, ObstacleTreeNode node)
+ {
+ if (node is not null)
+ {
+ Obstacle obstacle1 = node._obstacle;
+ Obstacle obstacle2 = obstacle1._next;
+
+ float agentLeftOfLine = RVOMath.LeftOf(obstacle1._point, obstacle2._point, agent._position);
+
+ QueryObstacleTreeRecursive(agent, rangeSq, agentLeftOfLine >= 0.0f ? node._left : node._right);
+
+ float distSqLine = agentLeftOfLine * agentLeftOfLine / RVOMath.AbsSq(obstacle2._point - obstacle1._point);
+
+ if (distSqLine < rangeSq)
+ {
+ if (agentLeftOfLine < 0.0f)
+ {
+ /*
+ * Try obstacle at this node only if agent is on right side of
+ * obstacle (and can see obstacle).
+ */
+ agent.InsertObstacleNeighbor(node._obstacle, rangeSq);
+ }
+
+ /* Try other side of line. */
+ QueryObstacleTreeRecursive(agent, rangeSq, agentLeftOfLine >= 0.0f ? node._right : node._left);
+ }
+ }
+ }
+
+ /// Recursive method for querying the visibility between two
+ /// points within a specified radius.
+ ///
+ /// True if q1 and q2 are mutually visible within the radius;
+ /// false otherwise.
+ ///
+ /// The first point between which visibility is to be
+ /// tested.
+ /// The second point between which visibility is to be
+ /// tested.
+ /// The radius within which visibility is to be
+ /// tested.
+ /// The current obstacle k-D node.
+ private bool QueryVisibilityRecursive(Vector2 q1, Vector2 q2, float radius, ObstacleTreeNode node)
+ {
+ if (node is null)
+ {
+ return true;
+ }
+
+ Obstacle obstacle1 = node._obstacle;
+ Obstacle obstacle2 = obstacle1._next;
+
+ float q1LeftOfI = RVOMath.LeftOf(obstacle1._point, obstacle2._point, q1);
+ float q2LeftOfI = RVOMath.LeftOf(obstacle1._point, obstacle2._point, q2);
+ float invLengthI = 1.0f / RVOMath.AbsSq(obstacle2._point - obstacle1._point);
+ float radiusSq = radius * radius;
+
+ if (q1LeftOfI >= 0.0f && q2LeftOfI >= 0.0f)
+ {
+ return QueryVisibilityRecursive(q1, q2, radius, node._left) && ((q1LeftOfI * q1LeftOfI * invLengthI >= radiusSq && q2LeftOfI * q2LeftOfI * invLengthI >= radiusSq) || QueryVisibilityRecursive(q1, q2, radius, node._right));
+ }
+
+ if (q1LeftOfI <= 0.0f && q2LeftOfI <= 0.0f)
+ {
+ return QueryVisibilityRecursive(q1, q2, radius, node._right) && ((q1LeftOfI * q1LeftOfI * invLengthI >= radiusSq && q2LeftOfI * q2LeftOfI * invLengthI >= radiusSq) || QueryVisibilityRecursive(q1, q2, radius, node._left));
+ }
+
+ if (q1LeftOfI >= 0.0f && q2LeftOfI <= 0.0f)
+ {
+ /* One can see through obstacle from left to right. */
+ return QueryVisibilityRecursive(q1, q2, radius, node._left) && QueryVisibilityRecursive(q1, q2, radius, node._right);
+ }
+
+ float point1LeftOfQ = RVOMath.LeftOf(q1, q2, obstacle1._point);
+ float point2LeftOfQ = RVOMath.LeftOf(q1, q2, obstacle2._point);
+ float invLengthQ = 1.0f / RVOMath.AbsSq(q2 - q1);
+
+ return point1LeftOfQ * point2LeftOfQ >= 0.0f && point1LeftOfQ * point1LeftOfQ * invLengthQ > radiusSq && point2LeftOfQ * point2LeftOfQ * invLengthQ > radiusSq && QueryVisibilityRecursive(q1, q2, radius, node._left) && QueryVisibilityRecursive(q1, q2, radius, node._right);
+ }
+ }
+}
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/KdTree.cs.meta b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/KdTree.cs.meta
new file mode 100644
index 0000000..6d1be7f
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/KdTree.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 41302aad673ebad45936305f3222217c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Line.cs b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Line.cs
new file mode 100644
index 0000000..11bd74f
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Line.cs
@@ -0,0 +1,42 @@
+/*
+ * Line.cs
+ * RVO2 Library C#
+ *
+ * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to .
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ *
+ */
+
+namespace RVO
+{
+ /// Defines a directed line.
+ public struct Line
+ {
+ public Vector2 Direction;
+ public Vector2 Point;
+ }
+}
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Line.cs.meta b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Line.cs.meta
new file mode 100644
index 0000000..7884ab7
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Line.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8cef7bba85dbe4647891612de7e749a2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Obstacle.cs b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Obstacle.cs
new file mode 100644
index 0000000..fb4301d
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Obstacle.cs
@@ -0,0 +1,47 @@
+/*
+ * Obstacle.cs
+ * RVO2 Library C#
+ *
+ * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to .
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ *
+ */
+
+namespace RVO
+{
+ /// Defines static obstacles in the simulation.
+ internal class Obstacle
+ {
+
+ internal Obstacle _next;
+ internal Obstacle _previous;
+ internal Vector2 _direction;
+ internal Vector2 _point;
+ internal int _id;
+ internal bool _convex;
+ }
+}
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Obstacle.cs.meta b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Obstacle.cs.meta
new file mode 100644
index 0000000..2430cb1
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Obstacle.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5b59751871022b84e88519071917ffa4
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/RVOMath.cs b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/RVOMath.cs
new file mode 100644
index 0000000..45cf69e
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/RVOMath.cs
@@ -0,0 +1,155 @@
+/*
+ * RVOMath.cs
+ * RVO2 Library C#
+ *
+ * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to .
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ *
+ */
+
+using System;
+
+namespace RVO
+{
+ /// Contains functions and constants used in multiple classes.
+ ///
+ public struct RVOMath
+ {
+ /// A sufficiently small positive number.
+ internal const float RVO_EPSILON = 0.00001f;
+
+ /// Computes the length of a specified two-dimensional vector.
+ ///
+ ///
+ /// The two-dimensional vector whose length is to be
+ /// computed.
+ /// The length of the two-dimensional vector.
+ public static float Abs(Vector2 vector)
+ {
+ return MathF.Sqrt(AbsSq(vector));
+ }
+
+ /// Computes the squared length of a specified two-dimensional
+ /// vector.
+ ///
+ /// The squared length of the two-dimensional vector.
+ ///
+ /// The two-dimensional vector whose squared length
+ /// is to be computed.
+ public static float AbsSq(Vector2 vector)
+ {
+ return vector * vector;
+ }
+
+ /// Computes the normalization of the specified two-dimensional
+ /// vector.
+ ///
+ /// The normalization of the two-dimensional vector.
+ ///
+ /// The two-dimensional vector whose normalization
+ /// is to be computed.
+ public static Vector2 Normalize(Vector2 vector)
+ {
+ float length = Abs(vector);
+
+ if (length <= RVO_EPSILON)
+ {
+ return new Vector2(0.0f, 0.0f);
+ }
+
+ return vector / length;
+ }
+
+ /// Computes the determinant of a two-dimensional square matrix
+ /// with rows consisting of the specified two-dimensional vectors.
+ ///
+ ///
+ /// The determinant of the two-dimensional square matrix.
+ ///
+ ///
+ /// The top row of the two-dimensional square
+ /// matrix.
+ /// The bottom row of the two-dimensional square
+ /// matrix.
+ internal static float Det(Vector2 vector1, Vector2 vector2)
+ {
+ return vector1._x * vector2._y - vector1._y * vector2._x;
+ }
+
+ /// Computes the squared distance from a line segment with the
+ /// specified endpoints to a specified point.
+ ///
+ /// The squared distance from the line segment to the point.
+ ///
+ ///
+ /// The first endpoint of the line segment.
+ /// The second endpoint of the line segment.
+ ///
+ /// The point to which the squared distance is to
+ /// be calculated.
+ internal static float DistSqPointLineSegment(Vector2 vector1, Vector2 vector2, Vector2 vector3)
+ {
+ float lengthSq = AbsSq(vector2 - vector1);
+
+ if (lengthSq <= RVO_EPSILON * RVO_EPSILON)
+ {
+ /* Degenerate segment: both endpoints are the same point. */
+ return AbsSq(vector3 - vector1);
+ }
+
+ float r = ((vector3 - vector1) * (vector2 - vector1)) / lengthSq;
+
+ if (r < 0.0f)
+ {
+ return AbsSq(vector3 - vector1);
+ }
+
+ if (r > 1.0f)
+ {
+ return AbsSq(vector3 - vector2);
+ }
+
+ return AbsSq(vector3 - (vector1 + r * (vector2 - vector1)));
+ }
+
+ /// Computes the signed distance from a line connecting the
+ /// specified points to a specified point.
+ ///
+ /// Positive when the point c lies to the left of the line ab.
+ ///
+ ///
+ /// The first point on the line.
+ /// The second point on the line.
+ /// The point to which the signed distance is to be
+ /// calculated.
+ internal static float LeftOf(Vector2 a, Vector2 b, Vector2 c)
+ {
+ return Det(a - c, b - a);
+ }
+
+ }
+}
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/RVOMath.cs.meta b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/RVOMath.cs.meta
new file mode 100644
index 0000000..5f62c64
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/RVOMath.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 30121b9365c39de4aad24770212c01c1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Simulator.cs b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Simulator.cs
new file mode 100644
index 0000000..197e908
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Simulator.cs
@@ -0,0 +1,1368 @@
+/*
+ * Simulator.cs
+ * RVO2 Library C#
+ *
+ * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to .
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ *
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace RVO
+{
+ /// Defines the simulation.
+ public class Simulator
+ {
+ internal IList _agents;
+ internal IList _obstacles;
+ internal KdTree _kdTree;
+ internal float _timeStep;
+
+ private static readonly Simulator _instance = new();
+
+ private Agent _defaultAgent;
+ private int _numWorkers;
+ private float _globalTime;
+ private bool _obstaclesProcessed;
+
+ public static Simulator Instance
+ {
+ get
+ {
+ return _instance;
+ }
+ }
+
+ /// Adds a new agent with default properties to the simulation.
+ ///
+ ///
+ /// The number of the agent, or -1 when the agent defaults have
+ /// not been set.
+ ///
+ /// The two-dimensional starting position of this
+ /// agent.
+ public int AddAgent(Vector2 position)
+ {
+ if (_defaultAgent is null)
+ {
+ return -1;
+ }
+
+ Agent agent = new();
+ agent._id = _agents.Count;
+ agent._maxNeighbors = _defaultAgent._maxNeighbors;
+ agent._maxSpeed = _defaultAgent._maxSpeed;
+ agent._neighborDist = _defaultAgent._neighborDist;
+ agent._position = position;
+ agent._radius = _defaultAgent._radius;
+ agent._timeHorizon = _defaultAgent._timeHorizon;
+ agent._timeHorizonObst = _defaultAgent._timeHorizonObst;
+ agent._velocity = _defaultAgent._velocity;
+ _agents.Add(agent);
+
+ return agent._id;
+ }
+
+ /// Adds a new agent with default properties to the simulation.
+ ///
+ ///
+ /// The number of the agent, or -1 when the agent defaults have
+ /// not been set.
+ ///
+ /// The two-dimensional starting position of this
+ /// agent.
+ [Obsolete("Use AddAgent instead.", false)]
+ public int addAgent(Vector2 position)
+ {
+ return AddAgent(position);
+ }
+
+ /// Adds a new agent to the simulation.
+ ///
+ /// The number of the agent.
+ ///
+ /// The two-dimensional starting position of this
+ /// agent.
+ /// The maximum distance (center point to
+ /// center point) to other agents this agent takes into account in the
+ /// navigation. The larger this number, the longer the running time of
+ /// the simulation. If the number is too low, the simulation will not be
+ /// safe. Must be non-negative.
+ /// The maximum number of other agents this
+ /// agent takes into account in the navigation. The larger this number,
+ /// the longer the running time of the simulation. If the number is too
+ /// low, the simulation will not be safe.
+ /// The minimal amount of time for which this
+ /// agent's velocities that are computed by the simulation are safe with
+ /// respect to other agents. The larger this number, the sooner this
+ /// agent will respond to the presence of other agents, but the less
+ /// freedom this agent has in choosing its velocities. Must be positive.
+ ///
+ /// The minimal amount of time for which
+ /// this agent's velocities that are computed by the simulation are safe
+ /// with respect to obstacles. The larger this number, the sooner this
+ /// agent will respond to the presence of obstacles, but the less freedom
+ /// this agent has in choosing its velocities. Must be positive.
+ /// The radius of this agent. Must be non-negative.
+ ///
+ /// The maximum speed of this agent. Must be
+ /// non-negative.
+ /// The initial two-dimensional linear velocity of
+ /// this agent.
+ public int AddAgent(Vector2 position, float neighborDist, int maxNeighbors, float timeHorizon, float timeHorizonObst, float radius, float maxSpeed, Vector2 velocity)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(maxNeighbors, nameof(maxNeighbors));
+ UnityArgumentOutOfRange.ThrowIfNegative(neighborDist, nameof(neighborDist));
+ UnityArgumentOutOfRange.ThrowIfNegativeOrZero(timeHorizon, nameof(timeHorizon));
+ UnityArgumentOutOfRange.ThrowIfNegativeOrZero(timeHorizonObst, nameof(timeHorizonObst));
+ UnityArgumentOutOfRange.ThrowIfNegative(radius, nameof(radius));
+ UnityArgumentOutOfRange.ThrowIfNegative(maxSpeed, nameof(maxSpeed));
+
+ Agent agent = new();
+ agent._id = _agents.Count;
+ agent._maxNeighbors = maxNeighbors;
+ agent._maxSpeed = maxSpeed;
+ agent._neighborDist = neighborDist;
+ agent._position = position;
+ agent._radius = radius;
+ agent._timeHorizon = timeHorizon;
+ agent._timeHorizonObst = timeHorizonObst;
+ agent._velocity = velocity;
+ _agents.Add(agent);
+
+ return agent._id;
+ }
+
+ /// Adds a new agent to the simulation.
+ ///
+ /// The number of the agent.
+ ///
+ /// The two-dimensional starting position of this
+ /// agent.
+ /// The maximum distance (center point to
+ /// center point) to other agents this agent takes into account in the
+ /// navigation. The larger this number, the longer the running time of
+ /// the simulation. If the number is too low, the simulation will not be
+ /// safe. Must be non-negative.
+ /// The maximum number of other agents this
+ /// agent takes into account in the navigation. The larger this number,
+ /// the longer the running time of the simulation. If the number is too
+ /// low, the simulation will not be safe.
+ /// The minimal amount of time for which this
+ /// agent's velocities that are computed by the simulation are safe with
+ /// respect to other agents. The larger this number, the sooner this
+ /// agent will respond to the presence of other agents, but the less
+ /// freedom this agent has in choosing its velocities. Must be positive.
+ ///
+ /// The minimal amount of time for which
+ /// this agent's velocities that are computed by the simulation are safe
+ /// with respect to obstacles. The larger this number, the sooner this
+ /// agent will respond to the presence of obstacles, but the less freedom
+ /// this agent has in choosing its velocities. Must be positive.
+ /// The radius of this agent. Must be non-negative.
+ ///
+ /// The maximum speed of this agent. Must be
+ /// non-negative.
+ /// The initial two-dimensional linear velocity of
+ /// this agent.
+ [Obsolete("Use AddAgent instead.", false)]
+ public int addAgent(Vector2 position, float neighborDist, int maxNeighbors, float timeHorizon, float timeHorizonObst, float radius, float maxSpeed, Vector2 velocity)
+ {
+ return AddAgent(position, neighborDist, maxNeighbors, timeHorizon, timeHorizonObst, radius, maxSpeed, velocity);
+ }
+
+ /// Adds a new obstacle to the simulation.
+ ///
+ /// The number of the first vertex of the obstacle, or -1 when
+ /// the number of vertices is less than two.
+ ///
+ /// List of the vertices of the polygonal obstacle
+ /// in counterclockwise order.
+ ///
+ /// To add a "negative" obstacle, e.g. a bounding polygon around
+ /// the environment, the vertices should be listed in clockwise order.
+ ///
+ public int AddObstacle(IList vertices)
+ {
+ if (vertices.Count < 2)
+ {
+ return -1;
+ }
+
+ for (int i = 0; i < vertices.Count; ++i)
+ {
+ int next = i == vertices.Count - 1 ? 0 : i + 1;
+
+ if (RVOMath.AbsSq(vertices[next] - vertices[i]) <= RVOMath.RVO_EPSILON * RVOMath.RVO_EPSILON)
+ {
+ return -1;
+ }
+ }
+
+ int obstacleNo = _obstacles.Count;
+
+ for (int i = 0; i < vertices.Count; ++i)
+ {
+ Obstacle obstacle = new();
+ obstacle._point = vertices[i];
+
+ if (i != 0)
+ {
+ obstacle._previous = _obstacles[_obstacles.Count - 1];
+ obstacle._previous._next = obstacle;
+ }
+
+ if (i == vertices.Count - 1)
+ {
+ obstacle._next = _obstacles[obstacleNo];
+ obstacle._next._previous = obstacle;
+ }
+
+ obstacle._direction = RVOMath.Normalize(vertices[(i == vertices.Count - 1 ? 0 : i + 1)] - vertices[i]);
+
+ if (vertices.Count == 2)
+ {
+ obstacle._convex = true;
+ }
+ else
+ {
+ obstacle._convex = (RVOMath.LeftOf(vertices[(i == 0 ? vertices.Count - 1 : i - 1)], vertices[i], vertices[(i == vertices.Count - 1 ? 0 : i + 1)]) >= 0.0f);
+ }
+
+ obstacle._id = _obstacles.Count;
+ _obstacles.Add(obstacle);
+ }
+
+ return obstacleNo;
+ }
+
+ /// Adds a new obstacle to the simulation.
+ ///
+ /// The number of the first vertex of the obstacle, or -1 when
+ /// the number of vertices is less than two.
+ ///
+ /// List of the vertices of the polygonal obstacle
+ /// in counterclockwise order.
+ ///
+ /// To add a "negative" obstacle, e.g. a bounding polygon around
+ /// the environment, the vertices should be listed in clockwise order.
+ ///
+ [Obsolete("Use AddObstacle instead.", false)]
+ public int addObstacle(IList vertices)
+ {
+ return AddObstacle(vertices);
+ }
+
+ /// Clears the simulation.
+ public void Clear()
+ {
+ _agents = new List();
+ _defaultAgent = null;
+ _kdTree = new KdTree();
+ _obstacles = new List();
+ _globalTime = 0.0f;
+ _obstaclesProcessed = false;
+ _timeStep = 0.1f;
+
+ NumWorkers = 0;
+ }
+
+ /// Performs a simulation step and updates the two-dimensional
+ /// position and two-dimensional velocity of each agent.
+ ///
+ /// The global time after the simulation step.
+ public float DoStep()
+ {
+ ParallelOptions options = new() { MaxDegreeOfParallelism = _numWorkers };
+
+ _kdTree.BuildAgentTree();
+
+ Parallel.For(0, _agents.Count, options, i =>
+ {
+ _agents[i].ComputeNeighbors();
+ _agents[i].ComputeNewVelocity();
+ });
+
+ Parallel.For(0, _agents.Count, options, i => _agents[i].Update());
+
+ _globalTime += _timeStep;
+
+ return _globalTime;
+ }
+
+ /// Performs a simulation step and updates the two-dimensional
+ /// position and two-dimensional velocity of each agent.
+ ///
+ /// The global time after the simulation step.
+ [Obsolete("Use DoStep instead.", false)]
+ public float doStep()
+ {
+ return DoStep();
+ }
+
+ /// Returns the specified agent neighbor of the specified agent.
+ ///
+ ///
+ /// The number of the neighboring agent.
+ ///
+ /// The number of the agent whose agent neighbor is
+ /// to be retrieved.
+ /// The number of the agent neighbor to be
+ /// retrieved.
+ public int GetAgentAgentNeighbor(int agentNo, int neighborNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfNegative(neighborNo, nameof(neighborNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(neighborNo, _agents[agentNo]._agentNeighbors.Count, nameof(neighborNo));
+
+ return _agents[agentNo]._agentNeighbors[neighborNo].Value._id;
+ }
+
+ /// Returns the specified agent neighbor of the specified agent.
+ ///
+ ///
+ /// The number of the neighboring agent.
+ ///
+ /// The number of the agent whose agent neighbor is
+ /// to be retrieved.
+ /// The number of the agent neighbor to be
+ /// retrieved.
+ [Obsolete("Use GetAgentAgentNeighbor instead.", false)]
+ public int getAgentAgentNeighbor(int agentNo, int neighborNo)
+ {
+ return GetAgentAgentNeighbor(agentNo, neighborNo);
+ }
+
+ /// Returns the maximum neighbor count of a specified agent.
+ ///
+ ///
+ /// The present maximum neighbor count of the agent.
+ ///
+ /// The number of the agent whose maximum neighbor
+ /// count is to be retrieved.
+ public int GetAgentMaxNeighbors(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return _agents[agentNo]._maxNeighbors;
+ }
+
+ /// Returns the maximum neighbor count of a specified agent.
+ ///
+ ///
+ /// The present maximum neighbor count of the agent.
+ ///
+ /// The number of the agent whose maximum neighbor
+ /// count is to be retrieved.
+ [Obsolete("Use GetAgentMaxNeighbors instead.", false)]
+ public int getAgentMaxNeighbors(int agentNo)
+ {
+ return GetAgentMaxNeighbors(agentNo);
+ }
+
+ /// Returns the maximum speed of a specified agent.
+ ///
+ /// The present maximum speed of the agent.
+ ///
+ /// The number of the agent whose maximum speed is
+ /// to be retrieved.
+ public float GetAgentMaxSpeed(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return _agents[agentNo]._maxSpeed;
+ }
+
+ /// Returns the maximum speed of a specified agent.
+ ///
+ /// The present maximum speed of the agent.
+ ///
+ /// The number of the agent whose maximum speed is
+ /// to be retrieved.
+ [Obsolete("Use GetAgentMaxSpeed instead.", false)]
+ public float getAgentMaxSpeed(int agentNo)
+ {
+ return GetAgentMaxSpeed(agentNo);
+ }
+
+ /// Returns the maximum neighbor distance of a specified agent.
+ ///
+ ///
+ /// The present maximum neighbor distance of the agent.
+ ///
+ ///
+ /// The number of the agent whose maximum neighbor
+ /// distance is to be retrieved.
+ public float GetAgentNeighborDist(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return _agents[agentNo]._neighborDist;
+ }
+
+ /// Returns the maximum neighbor distance of a specified agent.
+ ///
+ ///
+ /// The present maximum neighbor distance of the agent.
+ ///
+ ///
+ /// The number of the agent whose maximum neighbor
+ /// distance is to be retrieved.
+ [Obsolete("Use GetAgentNeighborDist instead.", false)]
+ public float getAgentNeighborDist(int agentNo)
+ {
+ return GetAgentNeighborDist(agentNo);
+ }
+
+ /// Returns the count of agent neighbors taken into account to
+ /// compute the current velocity for the specified agent.
+ ///
+ /// The count of agent neighbors taken into account to compute
+ /// the current velocity for the specified agent.
+ ///
+ /// The number of the agent whose count of agent
+ /// neighbors is to be retrieved.
+ public int GetAgentNumAgentNeighbors(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return _agents[agentNo]._agentNeighbors.Count;
+ }
+
+ /// Returns the count of agent neighbors taken into account to
+ /// compute the current velocity for the specified agent.
+ ///
+ /// The count of agent neighbors taken into account to compute
+ /// the current velocity for the specified agent.
+ ///
+ /// The number of the agent whose count of agent
+ /// neighbors is to be retrieved.
+ [Obsolete("Use GetAgentNumAgentNeighbors instead.", false)]
+ public int getAgentNumAgentNeighbors(int agentNo)
+ {
+ return GetAgentNumAgentNeighbors(agentNo);
+ }
+
+ /// Returns the count of obstacle neighbors taken into account
+ /// to compute the current velocity for the specified agent.
+ ///
+ /// The count of obstacle neighbors taken into account to
+ /// compute the current velocity for the specified agent.
+ ///
+ /// The number of the agent whose count of obstacle
+ /// neighbors is to be retrieved.
+ public int GetAgentNumObstacleNeighbors(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return _agents[agentNo]._obstacleNeighbors.Count;
+ }
+
+ /// Returns the count of obstacle neighbors taken into account
+ /// to compute the current velocity for the specified agent.
+ ///
+ /// The count of obstacle neighbors taken into account to
+ /// compute the current velocity for the specified agent.
+ ///
+ /// The number of the agent whose count of obstacle
+ /// neighbors is to be retrieved.
+ [Obsolete("Use GetAgentNumObstacleNeighbors instead.", false)]
+ public int getAgentNumObstacleNeighbors(int agentNo)
+ {
+ return GetAgentNumObstacleNeighbors(agentNo);
+ }
+
+ /// Returns the specified obstacle neighbor of the specified
+ /// agent.
+ ///
+ /// The number of the first vertex of the neighboring obstacle
+ /// edge.
+ ///
+ /// The number of the agent whose obstacle neighbor
+ /// is to be retrieved.
+ /// The number of the obstacle neighbor to be
+ /// retrieved.
+ public int GetAgentObstacleNeighbor(int agentNo, int neighborNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfNegative(neighborNo, nameof(neighborNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(neighborNo, _agents[agentNo]._obstacleNeighbors.Count, nameof(neighborNo));
+
+ return _agents[agentNo]._obstacleNeighbors[neighborNo].Value._id;
+ }
+
+ /// Returns the specified obstacle neighbor of the specified
+ /// agent.
+ ///
+ /// The number of the first vertex of the neighboring obstacle
+ /// edge.
+ ///
+ /// The number of the agent whose obstacle neighbor
+ /// is to be retrieved.
+ /// The number of the obstacle neighbor to be
+ /// retrieved.
+ [Obsolete("Use GetAgentObstacleNeighbor instead.", false)]
+ public int getAgentObstacleNeighbor(int agentNo, int neighborNo)
+ {
+ return GetAgentObstacleNeighbor(agentNo, neighborNo);
+ }
+
+ /// Returns the ORCA constraints of the specified agent.
+ ///
+ ///
+ /// A list of lines representing the ORCA constraints.
+ ///
+ /// The number of the agent whose ORCA constraints
+ /// are to be retrieved.
+ ///
+ /// The halfplane to the left of each line is the region of
+ /// permissible velocities with respect to that ORCA constraint.
+ ///
+ public IList GetAgentOrcaLines(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return new List(_agents[agentNo]._orcaLines);
+ }
+
+ /// Returns the ORCA constraints of the specified agent.
+ ///
+ ///
+ /// A list of lines representing the ORCA constraints.
+ ///
+ /// The number of the agent whose ORCA constraints
+ /// are to be retrieved.
+ ///
+ /// The halfplane to the left of each line is the region of
+ /// permissible velocities with respect to that ORCA constraint.
+ ///
+ [Obsolete("Use GetAgentOrcaLines instead.", false)]
+ public IList getAgentOrcaLines(int agentNo)
+ {
+ return GetAgentOrcaLines(agentNo);
+ }
+
+ /// Returns the two-dimensional position of a specified agent.
+ ///
+ ///
+ /// The present two-dimensional position of the (center of the)
+ /// agent.
+ ///
+ /// The number of the agent whose two-dimensional
+ /// position is to be retrieved.
+ public Vector2 GetAgentPosition(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return _agents[agentNo]._position;
+ }
+
+ /// Returns the two-dimensional position of a specified agent.
+ ///
+ ///
+ /// The present two-dimensional position of the (center of the)
+ /// agent.
+ ///
+ /// The number of the agent whose two-dimensional
+ /// position is to be retrieved.
+ [Obsolete("Use GetAgentPosition instead.", false)]
+ public Vector2 getAgentPosition(int agentNo)
+ {
+ return GetAgentPosition(agentNo);
+ }
+
+ /// Returns the two-dimensional preferred velocity of a
+ /// specified agent.
+ ///
+ /// The present two-dimensional preferred velocity of the agent.
+ ///
+ ///
+ /// The number of the agent whose two-dimensional
+ /// preferred velocity is to be retrieved.
+ public Vector2 GetAgentPrefVelocity(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return _agents[agentNo]._prefVelocity;
+ }
+
+ /// Returns the two-dimensional preferred velocity of a
+ /// specified agent.
+ ///
+ /// The present two-dimensional preferred velocity of the agent.
+ ///
+ ///
+ /// The number of the agent whose two-dimensional
+ /// preferred velocity is to be retrieved.
+ [Obsolete("Use GetAgentPrefVelocity instead.", false)]
+ public Vector2 getAgentPrefVelocity(int agentNo)
+ {
+ return GetAgentPrefVelocity(agentNo);
+ }
+
+ /// Returns the radius of a specified agent.
+ ///
+ /// The present radius of the agent.
+ ///
+ /// The number of the agent whose radius is to be
+ /// retrieved.
+ public float GetAgentRadius(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return _agents[agentNo]._radius;
+ }
+
+ /// Returns the radius of a specified agent.
+ ///
+ /// The present radius of the agent.
+ ///
+ /// The number of the agent whose radius is to be
+ /// retrieved.
+ [Obsolete("Use GetAgentRadius instead.", false)]
+ public float getAgentRadius(int agentNo)
+ {
+ return GetAgentRadius(agentNo);
+ }
+
+ /// Returns the time horizon of a specified agent.
+ ///
+ /// The present time horizon of the agent.
+ ///
+ /// The number of the agent whose time horizon is
+ /// to be retrieved.
+ public float GetAgentTimeHorizon(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return _agents[agentNo]._timeHorizon;
+ }
+
+ /// Returns the time horizon of a specified agent.
+ ///
+ /// The present time horizon of the agent.
+ ///
+ /// The number of the agent whose time horizon is
+ /// to be retrieved.
+ [Obsolete("Use GetAgentTimeHorizon instead.", false)]
+ public float getAgentTimeHorizon(int agentNo)
+ {
+ return GetAgentTimeHorizon(agentNo);
+ }
+
+ /// Returns the time horizon with respect to obstacles of a
+ /// specified agent.
+ ///
+ /// The present time horizon with respect to obstacles of the
+ /// agent.
+ ///
+ /// The number of the agent whose time horizon with
+ /// respect to obstacles is to be retrieved.
+ public float GetAgentTimeHorizonObst(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return _agents[agentNo]._timeHorizonObst;
+ }
+
+ /// Returns the time horizon with respect to obstacles of a
+ /// specified agent.
+ ///
+ /// The present time horizon with respect to obstacles of the
+ /// agent.
+ ///
+ /// The number of the agent whose time horizon with
+ /// respect to obstacles is to be retrieved.
+ [Obsolete("Use GetAgentTimeHorizonObst instead.", false)]
+ public float getAgentTimeHorizonObst(int agentNo)
+ {
+ return GetAgentTimeHorizonObst(agentNo);
+ }
+
+ /// Returns the two-dimensional linear velocity of a specified
+ /// agent.
+ ///
+ /// The present two-dimensional linear velocity of the agent.
+ ///
+ ///
+ /// The number of the agent whose two-dimensional
+ /// linear velocity is to be retrieved.
+ public Vector2 GetAgentVelocity(int agentNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ return _agents[agentNo]._velocity;
+ }
+
+ /// Returns the two-dimensional linear velocity of a specified
+ /// agent.
+ ///
+ /// The present two-dimensional linear velocity of the agent.
+ ///
+ ///
+ /// The number of the agent whose two-dimensional
+ /// linear velocity is to be retrieved.
+ [Obsolete("Use GetAgentVelocity instead.", false)]
+ public Vector2 getAgentVelocity(int agentNo)
+ {
+ return GetAgentVelocity(agentNo);
+ }
+
+ /// Gets the global time of the simulation.
+ ///
+ /// The present global time of the simulation (zero initially).
+ ///
+ public float GlobalTime => _globalTime;
+
+ /// Returns the global time of the simulation.
+ ///
+ /// The present global time of the simulation (zero initially).
+ ///
+ [Obsolete("Use GlobalTime instead.", false)]
+ public float getGlobalTime()
+ {
+ return GlobalTime;
+ }
+
+ /// Gets the count of agents in the simulation.
+ ///
+ /// The count of agents in the simulation.
+ public int NumAgents => _agents.Count;
+
+ /// Returns the count of agents in the simulation.
+ ///
+ /// The count of agents in the simulation.
+ [Obsolete("Use NumAgents instead.", false)]
+ public int getNumAgents()
+ {
+ return NumAgents;
+ }
+
+ /// Gets the count of obstacle vertices in the simulation.
+ ///
+ ///
+ /// The count of obstacle vertices in the simulation.
+ public int NumObstacleVertices => _obstacles.Count;
+
+ /// Returns the count of obstacle vertices in the simulation.
+ ///
+ ///
+ /// The count of obstacle vertices in the simulation.
+ [Obsolete("Use NumObstacleVertices instead.", false)]
+ public int getNumObstacleVertices()
+ {
+ return NumObstacleVertices;
+ }
+
+ /// Gets or sets the maximum degree of parallelism for the
+ /// simulation step.
+ ///
+ /// The maximum number of concurrent tasks used during DoStep. A
+ /// value of zero or less imposes no limit.
+ public int NumWorkers
+ {
+ get => _numWorkers;
+ set => _numWorkers = value <= 0 ? -1 : value;
+ }
+
+ /// Returns the two-dimensional position of a specified obstacle
+ /// vertex.
+ ///
+ /// The two-dimensional position of the specified obstacle
+ /// vertex.
+ ///
+ /// The number of the obstacle vertex to be
+ /// retrieved.
+ public Vector2 GetObstacleVertex(int vertexNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(vertexNo, nameof(vertexNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(vertexNo, _obstacles.Count, nameof(vertexNo));
+
+ return _obstacles[vertexNo]._point;
+ }
+
+ /// Returns the two-dimensional position of a specified obstacle
+ /// vertex.
+ ///
+ /// The two-dimensional position of the specified obstacle
+ /// vertex.
+ ///
+ /// The number of the obstacle vertex to be
+ /// retrieved.
+ [Obsolete("Use GetObstacleVertex instead.", false)]
+ public Vector2 getObstacleVertex(int vertexNo)
+ {
+ return GetObstacleVertex(vertexNo);
+ }
+
+ /// Returns the number of the obstacle vertex succeeding the
+ /// specified obstacle vertex in its polygon.
+ ///
+ /// The number of the obstacle vertex succeeding the specified
+ /// obstacle vertex in its polygon.
+ ///
+ /// The number of the obstacle vertex whose
+ /// successor is to be retrieved.
+ public int GetNextObstacleVertexNo(int vertexNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(vertexNo, nameof(vertexNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(vertexNo, _obstacles.Count, nameof(vertexNo));
+
+ return _obstacles[vertexNo]._next._id;
+ }
+
+ /// Returns the number of the obstacle vertex succeeding the
+ /// specified obstacle vertex in its polygon.
+ ///
+ /// The number of the obstacle vertex succeeding the specified
+ /// obstacle vertex in its polygon.
+ ///
+ /// The number of the obstacle vertex whose
+ /// successor is to be retrieved.
+ [Obsolete("Use GetNextObstacleVertexNo instead.", false)]
+ public int getNextObstacleVertexNo(int vertexNo)
+ {
+ return GetNextObstacleVertexNo(vertexNo);
+ }
+
+ /// Returns the number of the obstacle vertex preceding the
+ /// specified obstacle vertex in its polygon.
+ ///
+ /// The number of the obstacle vertex preceding the specified
+ /// obstacle vertex in its polygon.
+ ///
+ /// The number of the obstacle vertex whose
+ /// predecessor is to be retrieved.
+ public int GetPrevObstacleVertexNo(int vertexNo)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(vertexNo, nameof(vertexNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(vertexNo, _obstacles.Count, nameof(vertexNo));
+
+ return _obstacles[vertexNo]._previous._id;
+ }
+
+ /// Returns the number of the obstacle vertex preceding the
+ /// specified obstacle vertex in its polygon.
+ ///
+ /// The number of the obstacle vertex preceding the specified
+ /// obstacle vertex in its polygon.
+ ///
+ /// The number of the obstacle vertex whose
+ /// predecessor is to be retrieved.
+ [Obsolete("Use GetPrevObstacleVertexNo instead.", false)]
+ public int getPrevObstacleVertexNo(int vertexNo)
+ {
+ return GetPrevObstacleVertexNo(vertexNo);
+ }
+
+ /// Gets or sets the time step of the simulation.
+ ///
+ /// The time step of the simulation. Must be positive.
+ public float TimeStep
+ {
+ get => _timeStep;
+ set
+ {
+ UnityArgumentOutOfRange.ThrowIfNegativeOrZero(value, nameof(value));
+
+ _timeStep = value;
+ }
+ }
+
+ /// Returns the time step of the simulation.
+ ///
+ /// The present time step of the simulation.
+ [Obsolete("Use TimeStep instead.", false)]
+ public float getTimeStep()
+ {
+ return TimeStep;
+ }
+
+ /// Processes the obstacles that have been added so that they
+ /// are accounted for in the simulation.
+ ///
+ /// Obstacles added to the simulation after this function has
+ /// been called are not accounted for in the simulation.
+ public void ProcessObstacles()
+ {
+ if (_obstaclesProcessed)
+ {
+ throw new InvalidOperationException("ProcessObstacles has already been called. Call Clear() to reset the simulation before processing obstacles again.");
+ }
+
+ _kdTree.BuildObstacleTree();
+ _obstaclesProcessed = true;
+ }
+
+ /// Processes the obstacles that have been added so that they
+ /// are accounted for in the simulation.
+ ///
+ /// Obstacles added to the simulation after this function has
+ /// been called are not accounted for in the simulation.
+ [Obsolete("Use ProcessObstacles instead.", false)]
+ public void processObstacles()
+ {
+ ProcessObstacles();
+ }
+
+ /// Performs a visibility query between the two specified points
+ /// with respect to the obstacles.
+ ///
+ /// A boolean specifying whether the two points are mutually
+ /// visible. Returns true when the obstacles have not been processed.
+ ///
+ ///
+ /// The first point of the query.
+ /// The second point of the query.
+ /// The minimal distance between the line connecting
+ /// the two points and the obstacles in order for the points to be
+ /// mutually visible (optional). Must be non-negative.
+ public bool QueryVisibility(Vector2 point1, Vector2 point2, float radius)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(radius, nameof(radius));
+
+ if (RVOMath.AbsSq(point2 - point1) <= RVOMath.RVO_EPSILON * RVOMath.RVO_EPSILON)
+ {
+ return true;
+ }
+
+ return _kdTree.QueryVisibility(point1, point2, radius);
+ }
+
+ /// Performs a visibility query between the two specified points
+ /// with respect to the obstacles.
+ ///
+ /// A boolean specifying whether the two points are mutually
+ /// visible. Returns true when the obstacles have not been processed.
+ ///
+ ///
+ /// The first point of the query.
+ /// The second point of the query.
+ /// The minimal distance between the line connecting
+ /// the two points and the obstacles in order for the points to be
+ /// mutually visible (optional). Must be non-negative.
+ [Obsolete("Use QueryVisibility instead.", false)]
+ public bool queryVisibility(Vector2 point1, Vector2 point2, float radius)
+ {
+ return QueryVisibility(point1, point2, radius);
+ }
+
+ /// Sets the default properties for any new agent that is added.
+ ///
+ ///
+ /// The default maximum distance (center point
+ /// to center point) to other agents a new agent takes into account in
+ /// the navigation. The larger this number, the longer the running time of
+ /// the simulation. If the number is too low, the simulation will not be
+ /// safe. Must be non-negative.
+ /// The default maximum number of other agents
+ /// a new agent takes into account in the navigation. The larger this
+ /// number, the longer the running time of the simulation. If the number
+ /// is too low, the simulation will not be safe.
+ /// The default minimal amount of time for
+ /// which a new agent's velocities that are computed by the simulation
+ /// are safe with respect to other agents. The larger this number, the
+ /// sooner an agent will respond to the presence of other agents, but the
+ /// less freedom the agent has in choosing its velocities. Must be
+ /// positive.
+ /// The default minimal amount of time for
+ /// which a new agent's velocities that are computed by the simulation
+ /// are safe with respect to obstacles. The larger this number, the
+ /// sooner an agent will respond to the presence of obstacles, but the
+ /// less freedom the agent has in choosing its velocities. Must be
+ /// positive.
+ /// The default radius of a new agent. Must be
+ /// non-negative.
+ /// The default maximum speed of a new agent. Must
+ /// be non-negative.
+ /// The default initial two-dimensional linear
+ /// velocity of a new agent.
+ public void SetAgentDefaults(float neighborDist, int maxNeighbors, float timeHorizon, float timeHorizonObst, float radius, float maxSpeed, Vector2 velocity)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(maxNeighbors, nameof(maxNeighbors));
+ UnityArgumentOutOfRange.ThrowIfNegative(neighborDist, nameof(neighborDist));
+ UnityArgumentOutOfRange.ThrowIfNegativeOrZero(timeHorizon, nameof(timeHorizon));
+ UnityArgumentOutOfRange.ThrowIfNegativeOrZero(timeHorizonObst, nameof(timeHorizonObst));
+ UnityArgumentOutOfRange.ThrowIfNegative(radius, nameof(radius));
+ UnityArgumentOutOfRange.ThrowIfNegative(maxSpeed, nameof(maxSpeed));
+
+ if (_defaultAgent is null)
+ {
+ _defaultAgent = new Agent();
+ }
+
+ _defaultAgent._maxNeighbors = maxNeighbors;
+ _defaultAgent._maxSpeed = maxSpeed;
+ _defaultAgent._neighborDist = neighborDist;
+ _defaultAgent._radius = radius;
+ _defaultAgent._timeHorizon = timeHorizon;
+ _defaultAgent._timeHorizonObst = timeHorizonObst;
+ _defaultAgent._velocity = velocity;
+ }
+
+ /// Sets the default properties for any new agent that is added.
+ ///
+ ///
+ /// The default maximum distance (center point
+ /// to center point) to other agents a new agent takes into account in
+ /// the navigation. The larger this number, the longer the running time of
+ /// the simulation. If the number is too low, the simulation will not be
+ /// safe. Must be non-negative.
+ /// The default maximum number of other agents
+ /// a new agent takes into account in the navigation. The larger this
+ /// number, the longer the running time of the simulation. If the number
+ /// is too low, the simulation will not be safe.
+ /// The default minimal amount of time for
+ /// which a new agent's velocities that are computed by the simulation
+ /// are safe with respect to other agents. The larger this number, the
+ /// sooner an agent will respond to the presence of other agents, but the
+ /// less freedom the agent has in choosing its velocities. Must be
+ /// positive.
+ /// The default minimal amount of time for
+ /// which a new agent's velocities that are computed by the simulation
+ /// are safe with respect to obstacles. The larger this number, the
+ /// sooner an agent will respond to the presence of obstacles, but the
+ /// less freedom the agent has in choosing its velocities. Must be
+ /// positive.
+ /// The default radius of a new agent. Must be
+ /// non-negative.
+ /// The default maximum speed of a new agent. Must
+ /// be non-negative.
+ /// The default initial two-dimensional linear
+ /// velocity of a new agent.
+ [Obsolete("Use SetAgentDefaults instead.", false)]
+ public void setAgentDefaults(float neighborDist, int maxNeighbors, float timeHorizon, float timeHorizonObst, float radius, float maxSpeed, Vector2 velocity)
+ {
+ SetAgentDefaults(neighborDist, maxNeighbors, timeHorizon, timeHorizonObst, radius, maxSpeed, velocity);
+ }
+
+ /// Sets the maximum neighbor count of a specified agent.
+ ///
+ ///
+ /// The number of the agent whose maximum neighbor
+ /// count is to be modified.
+ /// The replacement maximum neighbor count.
+ /// Must be non-negative.
+ public void SetAgentMaxNeighbors(int agentNo, int maxNeighbors)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfNegative(maxNeighbors, nameof(maxNeighbors));
+
+ _agents[agentNo]._maxNeighbors = maxNeighbors;
+ }
+
+ /// Sets the maximum neighbor count of a specified agent.
+ ///
+ ///
+ /// The number of the agent whose maximum neighbor
+ /// count is to be modified.
+ /// The replacement maximum neighbor count.
+ ///
+ [Obsolete("Use SetAgentMaxNeighbors instead.", false)]
+ public void setAgentMaxNeighbors(int agentNo, int maxNeighbors)
+ {
+ SetAgentMaxNeighbors(agentNo, maxNeighbors);
+ }
+
+ /// Sets the maximum speed of a specified agent.
+ ///
+ /// The number of the agent whose maximum speed is
+ /// to be modified.
+ /// The replacement maximum speed. Must be
+ /// non-negative.
+ public void SetAgentMaxSpeed(int agentNo, float maxSpeed)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfNegative(maxSpeed, nameof(maxSpeed));
+
+ _agents[agentNo]._maxSpeed = maxSpeed;
+ }
+
+ /// Sets the maximum speed of a specified agent.
+ ///
+ /// The number of the agent whose maximum speed is
+ /// to be modified.
+ /// The replacement maximum speed. Must be
+ /// non-negative.
+ [Obsolete("Use SetAgentMaxSpeed instead.", false)]
+ public void setAgentMaxSpeed(int agentNo, float maxSpeed)
+ {
+ SetAgentMaxSpeed(agentNo, maxSpeed);
+ }
+
+ /// Sets the maximum neighbor distance of a specified agent.
+ ///
+ ///
+ /// The number of the agent whose maximum neighbor
+ /// distance is to be modified.
+ /// The replacement maximum neighbor distance.
+ /// Must be non-negative.
+ public void SetAgentNeighborDist(int agentNo, float neighborDist)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfNegative(neighborDist, nameof(neighborDist));
+
+ _agents[agentNo]._neighborDist = neighborDist;
+ }
+
+ /// Sets the maximum neighbor distance of a specified agent.
+ ///
+ ///
+ /// The number of the agent whose maximum neighbor
+ /// distance is to be modified.
+ /// The replacement maximum neighbor distance.
+ /// Must be non-negative.
+ [Obsolete("Use SetAgentNeighborDist instead.", false)]
+ public void setAgentNeighborDist(int agentNo, float neighborDist)
+ {
+ SetAgentNeighborDist(agentNo, neighborDist);
+ }
+
+ /// Sets the two-dimensional position of a specified agent.
+ ///
+ ///
+ /// The number of the agent whose two-dimensional
+ /// position is to be modified.
+ /// The replacement of the two-dimensional
+ /// position.
+ public void SetAgentPosition(int agentNo, Vector2 position)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ _agents[agentNo]._position = position;
+ }
+
+ /// Sets the two-dimensional position of a specified agent.
+ ///
+ ///
+ /// The number of the agent whose two-dimensional
+ /// position is to be modified.
+ /// The replacement of the two-dimensional
+ /// position.
+ [Obsolete("Use SetAgentPosition instead.", false)]
+ public void setAgentPosition(int agentNo, Vector2 position)
+ {
+ SetAgentPosition(agentNo, position);
+ }
+
+ /// Sets the two-dimensional preferred velocity of a specified
+ /// agent.
+ ///
+ /// The number of the agent whose two-dimensional
+ /// preferred velocity is to be modified.
+ /// The replacement of the two-dimensional
+ /// preferred velocity.
+ public void SetAgentPrefVelocity(int agentNo, Vector2 prefVelocity)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ _agents[agentNo]._prefVelocity = prefVelocity;
+ }
+
+ /// Sets the two-dimensional preferred velocity of a specified
+ /// agent.
+ ///
+ /// The number of the agent whose two-dimensional
+ /// preferred velocity is to be modified.
+ /// The replacement of the two-dimensional
+ /// preferred velocity.
+ [Obsolete("Use SetAgentPrefVelocity instead.", false)]
+ public void setAgentPrefVelocity(int agentNo, Vector2 prefVelocity)
+ {
+ SetAgentPrefVelocity(agentNo, prefVelocity);
+ }
+
+ /// Sets the radius of a specified agent.
+ ///
+ /// The number of the agent whose radius is to be
+ /// modified.
+ /// The replacement radius. Must be non-negative.
+ ///
+ public void SetAgentRadius(int agentNo, float radius)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfNegative(radius, nameof(radius));
+
+ _agents[agentNo]._radius = radius;
+ }
+
+ /// Sets the radius of a specified agent.
+ ///
+ /// The number of the agent whose radius is to be
+ /// modified.
+ /// The replacement radius. Must be non-negative.
+ ///
+ [Obsolete("Use SetAgentRadius instead.", false)]
+ public void setAgentRadius(int agentNo, float radius)
+ {
+ SetAgentRadius(agentNo, radius);
+ }
+
+ /// Sets the time horizon of a specified agent with respect to
+ /// other agents.
+ ///
+ /// The number of the agent whose time horizon is
+ /// to be modified.
+ /// The replacement time horizon with respect
+ /// to other agents. Must be positive.
+ public void SetAgentTimeHorizon(int agentNo, float timeHorizon)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfNegativeOrZero(timeHorizon, nameof(timeHorizon));
+
+ _agents[agentNo]._timeHorizon = timeHorizon;
+ }
+
+ /// Sets the time horizon of a specified agent with respect to
+ /// other agents.
+ ///
+ /// The number of the agent whose time horizon is
+ /// to be modified.
+ /// The replacement time horizon with respect
+ /// to other agents. Must be positive.
+ [Obsolete("Use SetAgentTimeHorizon instead.", false)]
+ public void setAgentTimeHorizon(int agentNo, float timeHorizon)
+ {
+ SetAgentTimeHorizon(agentNo, timeHorizon);
+ }
+
+ /// Sets the time horizon of a specified agent with respect to
+ /// obstacles.
+ ///
+ /// The number of the agent whose time horizon with
+ /// respect to obstacles is to be modified.
+ /// The replacement time horizon with
+ /// respect to obstacles. Must be positive.
+ public void SetAgentTimeHorizonObst(int agentNo, float timeHorizonObst)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfNegativeOrZero(timeHorizonObst, nameof(timeHorizonObst));
+
+ _agents[agentNo]._timeHorizonObst = timeHorizonObst;
+ }
+
+ /// Sets the time horizon of a specified agent with respect to
+ /// obstacles.
+ ///
+ /// The number of the agent whose time horizon with
+ /// respect to obstacles is to be modified.
+ /// The replacement time horizon with
+ /// respect to obstacles. Must be positive.
+ [Obsolete("Use SetAgentTimeHorizonObst instead.", false)]
+ public void setAgentTimeHorizonObst(int agentNo, float timeHorizonObst)
+ {
+ SetAgentTimeHorizonObst(agentNo, timeHorizonObst);
+ }
+
+ /// Sets the two-dimensional linear velocity of a specified
+ /// agent.
+ ///
+ /// The number of the agent whose two-dimensional
+ /// linear velocity is to be modified.
+ /// The replacement two-dimensional linear
+ /// velocity.
+ public void SetAgentVelocity(int agentNo, Vector2 velocity)
+ {
+ UnityArgumentOutOfRange.ThrowIfNegative(agentNo, nameof(agentNo));
+ UnityArgumentOutOfRange.ThrowIfGreaterThanOrEqual(agentNo, _agents.Count, nameof(agentNo));
+
+ _agents[agentNo]._velocity = velocity;
+ }
+
+ /// Sets the two-dimensional linear velocity of a specified
+ /// agent.
+ ///
+ /// The number of the agent whose two-dimensional
+ /// linear velocity is to be modified.
+ /// The replacement two-dimensional linear
+ /// velocity.
+ [Obsolete("Use SetAgentVelocity instead.", false)]
+ public void setAgentVelocity(int agentNo, Vector2 velocity)
+ {
+ SetAgentVelocity(agentNo, velocity);
+ }
+
+ /// Sets the global time of the simulation.
+ ///
+ /// The global time of the simulation.
+ public void SetGlobalTime(float globalTime)
+ {
+ _globalTime = globalTime;
+ }
+
+ /// Sets the global time of the simulation.
+ ///
+ /// The global time of the simulation.
+ [Obsolete("Use SetGlobalTime instead.", false)]
+ public void setGlobalTime(float globalTime)
+ {
+ SetGlobalTime(globalTime);
+ }
+
+ /// Sets the time step of the simulation.
+ ///
+ /// The time step of the simulation. Must be
+ /// positive.
+ [Obsolete("Use TimeStep instead.", false)]
+ public void setTimeStep(float timeStep)
+ {
+ TimeStep = timeStep;
+ }
+
+ /// Constructs and initializes a simulation.
+ private Simulator()
+ {
+ Clear();
+ }
+ }
+}
+
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Simulator.cs.meta b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Simulator.cs.meta
new file mode 100644
index 0000000..6da69ef
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Simulator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 123507813c7674546a3b3050097363ef
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/UnityArgumentOutOfRange.cs b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/UnityArgumentOutOfRange.cs
new file mode 100644
index 0000000..8bf67f3
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/UnityArgumentOutOfRange.cs
@@ -0,0 +1,47 @@
+/*
+ * UnityArgumentOutOfRange.cs
+ * Unity compatibility helpers for RVO2 Library C#.
+ *
+ * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+using System;
+
+namespace RVO
+{
+ internal static class UnityArgumentOutOfRange
+ {
+ public static void ThrowIfNegative(int value, string paramName)
+ {
+ if (value < 0)
+ {
+ throw new ArgumentOutOfRangeException(paramName);
+ }
+ }
+
+ public static void ThrowIfNegative(float value, string paramName)
+ {
+ if (value < 0f)
+ {
+ throw new ArgumentOutOfRangeException(paramName);
+ }
+ }
+
+ public static void ThrowIfNegativeOrZero(float value, string paramName)
+ {
+ if (value <= 0f)
+ {
+ throw new ArgumentOutOfRangeException(paramName);
+ }
+ }
+
+ public static void ThrowIfGreaterThanOrEqual(int value, int other, string paramName)
+ {
+ if (value >= other)
+ {
+ throw new ArgumentOutOfRangeException(paramName);
+ }
+ }
+ }
+}
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/UnityArgumentOutOfRange.cs.meta b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/UnityArgumentOutOfRange.cs.meta
new file mode 100644
index 0000000..88feedf
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/UnityArgumentOutOfRange.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0e4ae8cc39feef744babebc44c47f507
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Vector2.cs b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Vector2.cs
new file mode 100644
index 0000000..d705e6b
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Vector2.cs
@@ -0,0 +1,240 @@
+/*
+ * Vector2.cs
+ * RVO2 Library C#
+ *
+ * SPDX-FileCopyrightText: 2008 University of North Carolina at Chapel Hill
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Please send all bug reports to .
+ *
+ * The authors may be contacted via:
+ *
+ * Jur van den Berg, Stephen J. Guy, Jamie Snape, Ming C. Lin, Dinesh Manocha
+ * Dept. of Computer Science
+ * 201 S. Columbia St.
+ * Frederick P. Brooks, Jr. Computer Science Bldg.
+ * Chapel Hill, N.C. 27599-3175
+ * United States of America
+ *
+ *
+ */
+
+using System;
+using System.Globalization;
+
+namespace RVO
+{
+ /// Defines a two-dimensional vector.
+ public readonly struct Vector2 : IEquatable
+ {
+ internal readonly float _x;
+ internal readonly float _y;
+
+ /// Constructs and initializes a two-dimensional vector from the
+ /// specified xy-coordinates.
+ ///
+ /// The x-coordinate of the two-dimensional vector.
+ ///
+ /// The y-coordinate of the two-dimensional vector.
+ ///
+ public Vector2(float x, float y)
+ {
+ _x = x;
+ _y = y;
+ }
+
+ /// Returns the string representation of this vector.
+ ///
+ /// The string representation of this vector.
+ public override string ToString()
+ {
+ return $"({_x.ToString(CultureInfo.InvariantCulture)},{_y.ToString(CultureInfo.InvariantCulture)})";
+ }
+
+ /// Returns true if this vector equals the specified vector.
+ ///
+ ///
+ /// True if this vector equals the specified vector.
+ ///
+ /// The vector to compare with this vector.
+ public bool Equals(Vector2 other)
+ {
+ return _x == other._x && _y == other._y;
+ }
+
+ /// Returns true if this vector equals the specified object.
+ ///
+ ///
+ /// True if this vector equals the specified object.
+ ///
+ /// The object to compare with this vector.
+ public override bool Equals(object obj)
+ {
+ return obj is Vector2 other && Equals(other);
+ }
+
+ /// Returns the hash code for this vector.
+ ///
+ /// The hash code for this vector.
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(_x, _y);
+ }
+
+ /// Returns true if the two vectors are equal.
+ ///
+ /// True if the two vectors are equal.
+ ///
+ /// The first vector.
+ /// The second vector.
+ public static bool operator ==(Vector2 left, Vector2 right)
+ {
+ return left.Equals(right);
+ }
+
+ /// Returns true if the two vectors are not equal.
+ ///
+ /// True if the two vectors are not equal.
+ ///
+ /// The first vector.
+ /// The second vector.
+ public static bool operator !=(Vector2 left, Vector2 right)
+ {
+ return !left.Equals(right);
+ }
+
+ /// Gets the x-coordinate of this two-dimensional vector.
+ ///
+ ///
+ /// The x-coordinate of the two-dimensional vector.
+ public float X => _x;
+
+ /// Gets the y-coordinate of this two-dimensional vector.
+ ///
+ ///
+ /// The y-coordinate of the two-dimensional vector.
+ public float Y => _y;
+
+ /// Returns the x-coordinate of this two-dimensional vector.
+ ///
+ ///
+ /// The x-coordinate of the two-dimensional vector.
+ [Obsolete("Use the X property instead.", false)]
+ public float x()
+ {
+ return _x;
+ }
+
+ /// Returns the y-coordinate of this two-dimensional vector.
+ ///
+ ///
+ /// The y-coordinate of the two-dimensional vector.
+ [Obsolete("Use the Y property instead.", false)]
+ public float y()
+ {
+ return _y;
+ }
+
+ /// Computes the dot product of the two specified
+ /// two-dimensional vectors.
+ ///
+ /// The dot product of the two specified two-dimensional
+ /// vectors.
+ ///
+ /// The first two-dimensional vector.
+ /// The second two-dimensional vector.
+ public static float operator *(Vector2 vector1, Vector2 vector2)
+ {
+ return vector1._x * vector2._x + vector1._y * vector2._y;
+ }
+
+ /// Computes the scalar multiplication of the specified
+ /// two-dimensional vector with the specified scalar value.
+ ///
+ /// The scalar multiplication of the specified two-dimensional
+ /// vector with the specified scalar value.
+ ///
+ /// The scalar value.
+ /// The two-dimensional vector.
+ public static Vector2 operator *(float scalar, Vector2 vector)
+ {
+ return vector * scalar;
+ }
+
+ /// Computes the scalar multiplication of the specified
+ /// two-dimensional vector with the specified scalar value.
+ ///
+ /// The scalar multiplication of the specified two-dimensional
+ /// vector with the specified scalar value.
+ ///
+ /// The two-dimensional vector.
+ /// The scalar value.
+ public static Vector2 operator *(Vector2 vector, float scalar)
+ {
+ return new Vector2(vector._x * scalar, vector._y * scalar);
+ }
+
+ /// Computes the scalar division of the specified
+ /// two-dimensional vector with the specified scalar value.
+ ///
+ /// The scalar division of the specified two-dimensional vector
+ /// with the specified scalar value.
+ ///
+ /// The two-dimensional vector.
+ /// The scalar value.
+ public static Vector2 operator /(Vector2 vector, float scalar)
+ {
+ return new Vector2(vector._x / scalar, vector._y / scalar);
+ }
+
+ /// Computes the vector sum of the two specified two-dimensional
+ /// vectors.
+ ///
+ /// The vector sum of the two specified two-dimensional vectors.
+ ///
+ ///
+ /// The first two-dimensional vector.
+ /// The second two-dimensional vector.
+ public static Vector2 operator +(Vector2 vector1, Vector2 vector2)
+ {
+ return new Vector2(vector1._x + vector2._x, vector1._y + vector2._y);
+ }
+
+ /// Computes the vector difference of the two specified
+ /// two-dimensional vectors
+ ///
+ /// The vector difference of the two specified two-dimensional
+ /// vectors.
+ ///
+ /// The first two-dimensional vector.
+ /// The second two-dimensional vector.
+ public static Vector2 operator -(Vector2 vector1, Vector2 vector2)
+ {
+ return new Vector2(vector1._x - vector2._x, vector1._y - vector2._y);
+ }
+
+ /// Computes the negation of the specified two-dimensional
+ /// vector.
+ ///
+ /// The negation of the specified two-dimensional vector.
+ ///
+ ///
+ /// The two-dimensional vector.
+ public static Vector2 operator -(Vector2 vector)
+ {
+ return new Vector2(-vector._x, -vector._y);
+ }
+ }
+}
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Vector2.cs.meta b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Vector2.cs.meta
new file mode 100644
index 0000000..e96e5cb
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/RVOCS/Vector2.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d8e0975e105dca34aa11badd99980f16
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/THIRD_PARTY_NOTICE.md b/FishROV/Assets/ThirdParty/RVO2-CS/THIRD_PARTY_NOTICE.md
new file mode 100644
index 0000000..eff2aba
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/THIRD_PARTY_NOTICE.md
@@ -0,0 +1,11 @@
+# RVO2-CS
+
+本目录导入的是 `snape/RVO2-CS` 的核心 `RVOCS` 源码,用于本地避障 benchmark 的 RVO2 方案。
+
+- 上游仓库:https://github.com/snape/RVO2-CS
+- 官方 RVO2 页面:https://gamma.cs.unc.edu/RVO2/
+- 许可证:Apache License 2.0,见 `LICENSE` 与 `LICENSES/Apache-2.0.txt`
+
+Unity 兼容改动:
+
+- `Simulator.cs` 中的 .NET 新版参数检查 API 已替换为 `UnityArgumentOutOfRange`,以兼容 Unity 2022 的运行时。
diff --git a/FishROV/Assets/ThirdParty/RVO2-CS/THIRD_PARTY_NOTICE.md.meta b/FishROV/Assets/ThirdParty/RVO2-CS/THIRD_PARTY_NOTICE.md.meta
new file mode 100644
index 0000000..18df5c0
--- /dev/null
+++ b/FishROV/Assets/ThirdParty/RVO2-CS/THIRD_PARTY_NOTICE.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: b985d3a31ffcb5a44b2e2442cb2c8fb9
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FishROV/Docs/local-avoidance-benchmark-notes.md b/FishROV/Docs/local-avoidance-benchmark-notes.md
index 7453706..7d362b7 100644
--- a/FishROV/Docs/local-avoidance-benchmark-notes.md
+++ b/FishROV/Docs/local-avoidance-benchmark-notes.md
@@ -16,7 +16,7 @@
- 小鱼数量预设和滑条
- 暂停 / 继续 / 重置
- 平均 FPS、1% Low FPS、模拟耗时、GC 分配
-- 表现对象:运行时创建的 Cube 和 Capsule。
+- 表现对象:鱼群为运行时圆锥,圆锥尖头表示朝向;鲨鱼为 Capsule。
- 共享场景:
- 自由巡游
- 对向穿流
@@ -56,21 +56,21 @@ A* RVO、RVO2、Unity NavMesh 都通过同一个调试面板选择,用同一
- 如果类型存在,adapter 会创建运行时 `RVOSimulator`,给 benchmark 对象添加 `RVOController`,把期望速度送入 A* RVO,再把反射得到的避障速度写回 `BenchmarkAgent.ApplyVelocity`。
- 共享场景、HUD、数量档、指标和相机逻辑不变。
-## RVO2 / RVO2-3D Adapter
+## RVO2 Adapter
-`Rvo2Adapter` 是反射 adapter。没有 RVO2 源码或包时,工程仍可编译。
+`Rvo2Adapter` 是反射 adapter。当前已在 `Assets/ThirdParty/RVO2-CS/` 导入 `snape/RVO2-CS` 的核心 `RVOCS` 源码,并保留 Apache-2.0 许可证说明。
-- 如果缺少 RVO2/RVO2-3D,选择 `RVO2` 时会创建同样的 benchmark 对象,并在 Game 视口状态中提示缺包,随后退回基线移动。
-- 要启用真实框架,需要把 C# 版本 RVO2/RVO2-3D 放到 `Assets/` 或 `Packages/`。
+- 选择 `RVO2` 时,adapter 会优先命中导入后的 `RVO.Simulator`。
+- 如果之后移除 RVO2 源码,工程仍可编译;Game 视口状态会提示缺包,并退回基线移动。
- adapter 会查找类似 `RVO.Simulator`、`RVO2.Simulator`、`RVO3D.Simulator`、`RVO.Simulator3D` 的 Simulator 类型。
- 必要方法包括 `addAgent` / `AddAgent`、`setAgentPrefVelocity` / `SetAgentPrefVelocity`、`getAgentVelocity` / `GetAgentVelocity`、`doStep` / `DoStep`。
+- 如果存在 `setAgentPosition` / `SetAgentPosition`,adapter 每次设置期望速度前会同步 Unity Transform 位置,避免 RVO 内部位置和 benchmark 边界夹取结果漂移。
- 2D 和 2.5D 使用 RVO 的 Vector2 风格类型,把 Unity `x/z` 映射到 RVO `x/y`;3D 模式在可用时绑定 Vector3 风格类型。
## Unity NavMesh Adapter
`UnityNavMeshAdapter` 使用内置 `UnityEngine.AI.NavMeshAgent` 做对照组。
-- benchmark 场景里的鱼和鲨鱼是运行时创建的对象,空场景默认不会有可用 NavMesh。
-- 没有运行时 NavMesh 数据时,adapter 会在 Game 视口状态中提示,并退回基线移动,不会添加无效 `NavMeshAgent`。
-- 如果要测试 Unity NavMesh 避障,需要在选择 `NavMesh` 前提供 NavMesh 数据;烘焙场景 NavMesh 即可。
-- 如果希望运行时生成 benchmark 地面 NavMesh,需要启用 `com.unity.ai.navigation` 并补 `NavMeshSurface` 构建流程。
+- adapter 会使用 `NavMeshBuilder.BuildNavMeshData` 为 benchmark 场景运行时生成一张平面 NavMesh,不需要手动烘焙场景。
+- 如果运行时 NavMesh 构建失败,Game 视口状态会提示,并退回基线移动,不会添加无效 `NavMeshAgent`。
+- 因为 NavMesh 是平面数据,3D 压测更适合作为 2D / 2.5D 对照;完整 3D 体积避障仍需要专门方案。