* Initial update for net8 and netstandard2

* delete more and fix test folders

* clean up changes

* format

* more clean up

* allow build script to run

* format again

* fix packing and tests

* do tests always

* fmt again
This commit is contained in:
Adam Hathcock
2024-06-25 15:02:20 +01:00
committed by GitHub
parent 263d1bb159
commit acdc486510
102 changed files with 17696 additions and 19434 deletions
+12
View File
@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"csharpier": {
"version": "0.28.2",
"commands": [
"dotnet-csharpier"
]
}
}
}
+7
View File
@@ -0,0 +1,7 @@
printWidth: 120
useTabs: false
tabWidth: 2
preprocessorSymbolSets:
- ""
- "DEBUG"
- "DEBUG,CODE_STYLE"
+309
View File
@@ -0,0 +1,309 @@
root = true
# Don't use tabs for indentation.
[*]
indent_style = space
# Microsoft .NET properties
csharp_using_directive_placement = outside_namespace:silent
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
# Standard properties
insert_final_newline = true
# (Please don't specify an indent_size here; that has too many unintended consequences.)
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 2
charset = utf-8
# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
space_after_last_pi_attribute = false
# Xml config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
space_after_last_pi_attribute = false
# JSON files
[*.json]
indent_size = 2
# Dotnet code style settings:
[*.{cs,vb}]
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false
# Avoid "this." and "Me." if not necessary
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
# Use language keywords instead of framework type names for type references
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:silent
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:silent
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:warning
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
# CSharp code style settings:
[*.cs]
# Prefer "var" everywhere
csharp_style_var_elsewhere = false:none
csharp_style_var_for_built_in_types = false:none
csharp_style_var_when_type_is_apparent = false:none
# Prefer method-like constructs to have a block body
csharp_style_expression_bodied_methods = true:suggestion
csharp_style_expression_bodied_constructors = false:suggestion
csharp_style_expression_bodied_operators = true:suggestion
# Prefer property-like constructs to have an expression-body
csharp_style_expression_bodied_properties = true:suggestion
csharp_style_expression_bodied_indexers = true:suggestion
csharp_style_expression_bodied_accessors = true:suggestion
# Suggest more modern language features when available
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
csharp_style_namespace_declarations = file_scoped
# Newline settings
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
# SYMBOL NAMING RULES
# Copied from https://github.com/dotnet/roslyn/blob/main/.editorconfig
# Adapted rules:
# - Constants are ALL_UPPER
# - Non-private fields are PascalCase
# Non-private fields are PascalCase
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = warning
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style
dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field
dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case
# Constants are ALL_UPPER
dotnet_naming_rule.constants_should_be_all_upper.severity = warning
dotnet_naming_rule.constants_should_be_all_upper.symbols = constants
dotnet_naming_rule.constants_should_be_all_upper.style = constant_style
dotnet_naming_symbols.constants.applicable_kinds = field, local
dotnet_naming_symbols.constants.required_modifiers = const
dotnet_naming_style.constant_style.capitalization = all_upper
# Private static fields are camelCase and start with s_
dotnet_naming_rule.static_fields_should_be_camel_case.severity = warning
dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style
dotnet_naming_symbols.static_fields.applicable_accessibilities = private
dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static
dotnet_naming_style.static_field_style.capitalization = camel_case
dotnet_naming_style.static_field_style.required_prefix = s_
# Instance fields are camelCase and start with _
dotnet_naming_rule.instance_fields_should_be_camel_case.severity = warning
dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
dotnet_naming_symbols.instance_fields.applicable_kinds = field
dotnet_naming_style.instance_field_style.capitalization = camel_case
dotnet_naming_style.instance_field_style.required_prefix = _
# Locals and parameters are camelCase
dotnet_naming_rule.locals_should_be_camel_case.severity = warning
dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
dotnet_naming_style.camel_case_style.capitalization = camel_case
# Local functions are PascalCase
dotnet_naming_rule.local_functions_should_be_pascal_case.severity = warning
dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
dotnet_naming_symbols.local_functions.applicable_kinds = local_function
dotnet_naming_style.local_function_style.capitalization = pascal_case
# By default, name items with PascalCase
dotnet_naming_rule.members_should_be_pascal_case.severity = warning
dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.all_members.applicable_kinds = *
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# Analyzer settings
dotnet_analyzer_diagnostic.category-Style.severity = warning # All rules will use this severity unless overriden
dotnet_diagnostic.ide0055.severity = none # Formatting rule: Incompatible with CSharpier
dotnet_diagnostic.ide0007.severity = none # Use var instead of explicit type: Preference
dotnet_diagnostic.ide0009.severity = none # Add this or Me qualification: Preference
dotnet_diagnostic.ide0200.severity = none # Remove unnecessary lambda expression: may be performance reasons not to
dotnet_diagnostic.ide0058.severity = none # Remove unnecessary expression value: Subjective
dotnet_diagnostic.ide0010.severity = none # Add missing cases to switch statement: Too verbose
dotnet_diagnostic.ide0200.severity = none # Remove unnecessary lambda expression: may be performance reasons not to
dotnet_diagnostic.ide0058.severity = none # Remove unnecessary expression value: Subjective
dotnet_diagnostic.ide0001.severity = suggestion # Name can be simplified: Non enforceable in build
dotnet_diagnostic.ide0046.severity = suggestion # Use conditional expression for return: Subjective
dotnet_diagnostic.ide0045.severity = suggestion # Use conditional expression for assignment: Subjective
dotnet_diagnostic.ide0078.severity = suggestion # Use pattern matching: Subjective
dotnet_diagnostic.ide0260.severity = suggestion # Use pattern matching: Subjective
dotnet_diagnostic.ide0022.severity = suggestion # Use expression body for method: Subjective
dotnet_diagnostic.ide0061.severity = suggestion # Use expression body for local functions: Subjective
dotnet_diagnostic.ide0063.severity = suggestion # Using directive can be simplified
dotnet_diagnostic.ide0066.severity = suggestion # Use switch expression: Subjective
dotnet_diagnostic.ide0029.severity = suggestion # Null check can be simplified: Subjective
dotnet_diagnostic.ide0030.severity = suggestion # Null check can be simplified: Subjective
dotnet_diagnostic.ide0270.severity = suggestion # Null check can be simplified: Subjective
dotnet_diagnostic.ide0042.severity = suggestion # Deconstruct variable declaration: Subjective
dotnet_diagnostic.ide0039.severity = suggestion # Use local function instead of lambda: Subjective
dotnet_diagnostic.ide0029.severity = suggestion # Null check can be simplified: Subjective
dotnet_diagnostic.ide0030.severity = suggestion # Null check can be simplified: Subjective
dotnet_diagnostic.ide0270.severity = suggestion # Null check can be simplified: Subjective
dotnet_diagnostic.ide0042.severity = suggestion # Deconstruct variable declaration: Subjective
dotnet_diagnostic.ide0028.severity = suggestion # Use collection initializers: Subjective
dotnet_diagnostic.ide0072.severity = suggestion # Populate switch statement: Subjective
dotnet_diagnostic.ide0074.severity = suggestion # Use compound assignment: Subjective
# Maintainability rules
dotnet_diagnostic.ca1501.severity = warning # Avoid excessive inheritance
dotnet_diagnostic.ca1502.severity = warning # Avoid excessive complexity
dotnet_diagnostic.ca1505.severity = warning # Avoid unmaintainable code
dotnet_diagnostic.ca1506.severity = warning # Avoid excessive class coupling
dotnet_diagnostic.ca1507.severity = warning # Use nameof in place of string
dotnet_diagnostic.ca1508.severity = warning # Avoid dead conditional code
dotnet_diagnostic.ca1509.severity = warning # Invalid entry in code metrics configuration file
dotnet_diagnostic.ca1861.severity = none # Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1861)
dotnet_diagnostic.cs8618.severity = suggestion # nullable problem
dotnet_diagnostic.CS0809.severity = suggestion # obsolete errors
dotnet_diagnostic.CS0618.severity = suggestion # obsolete errors
# Performance rules
dotnet_diagnostic.ca1849.severity = suggestion # Call async methods when in an async method: May decrease performance
dotnet_diagnostic.ca1822.severity = suggestion # Mark member as static
dotnet_diagnostic.ca1859.severity = suggestion # Use concrete types when possible for improved performance
# Design rule
dotnet_diagnostic.ca1002.severity = suggestion # Do not expose generic lists
dotnet_diagnostic.ca1051.severity = warning # Do not declare visible instance fields
dotnet_diagnostic.ca1056.severity = suggestion # URI properties should not be strings
dotnet_diagnostic.ca1062.severity = none # Public method must check all parameters for null
# Naming
dotnet_diagnostic.ca1707.severity = none # Remove underscores in names
# Usage
dotnet_diagnostic.ca2227.severity = suggestion # Collection props should be read-only
dotnet_code_quality.ca1051.exclude_structs = true # CA1051 is excluded in structs
dotnet_code_quality.dispose_ownership_transfer_at_constructor = true # CA2000 has a lot of false positives without this
dotnet_code_quality.dispose_ownership_transfer_at_method_call = true # CA2000 has a lot of false positives without this
dotnet_code_quality.dispose_analysis_kind = NonExceptionPathsOnlyNotDisposed # CA2000 has a lot of false positives without this
# NUnit
dotnet_diagnostic.NUnit2001.severity = warning # Consider using Assert.That(expr, Is.False) instead of Assert.False(expr)
dotnet_diagnostic.NUnit2002.severity = warning # Consider using Assert.That(expr, Is.False) instead of Assert.IsFalse(expr)
dotnet_diagnostic.NUnit2003.severity = warning # Consider using Assert.That(expr, Is.True) instead of Assert.IsTrue(expr)
dotnet_diagnostic.NUnit2004.severity = warning # Consider using Assert.That(expr, Is.True) instead of Assert.True(expr)
dotnet_diagnostic.NUnit2005.severity = warning # Consider using Assert.That(actual, Is.EqualTo(expected)) instead of Assert.AreEqual(expected, actual)
dotnet_diagnostic.NUnit2006.severity = warning # Consider using Assert.That(actual, Is.Not.EqualTo(expected)) instead of Assert.AreNotEqual(expected, actual)
dotnet_diagnostic.NUnit2010.severity = warning # Use EqualConstraint for better assertion messages in case of failure
dotnet_diagnostic.NUnit2011.severity = warning # Use ContainsConstraint for better assertion messages in case of failure
dotnet_diagnostic.NUnit2011.severity = warning # Use StartsWithConstraint for better assertion messages in case of failure
dotnet_diagnostic.NUnit2011.severity = warning # Use EndsWithConstraint for better assertion messages in case of failure
dotnet_diagnostic.NUnit2014.severity = warning # Use SomeItemsConstraint for better assertion messages in case of failure
dotnet_diagnostic.NUnit2015.severity = warning # Consider using Assert.That(actual, Is.SameAs(expected)) instead of Assert.AreSame(expected, actual)
dotnet_diagnostic.NUnit2016.severity = warning # Consider using Assert.That(expr, Is.Null) instead of Assert.Null(expr)
dotnet_diagnostic.NUnit2017.severity = warning # Consider using Assert.That(expr, Is.Null) instead of Assert.IsNull(expr)
dotnet_diagnostic.NUnit2018.severity = warning # Consider using Assert.That(expr, Is.Not.Null) instead of Assert.NotNull(expr)
dotnet_diagnostic.NUnit2028.severity = warning # Consider using Assert.That(actual, Is.GreaterThanOrEqualTo(expected)) instead of Assert.GreaterOrEqual(actual, expected)
dotnet_diagnostic.NUnit2027.severity = warning # Consider using Assert.That(actual, Is.GreaterThan(expected)) instead of Assert.Greater(actual, expected)
dotnet_diagnostic.NUnit2029.severity = warning # Consider using Assert.That(actual, Is.LessThan(expected)) instead of Assert.Less(actual, expected)
dotnet_diagnostic.NUnit2030.severity = warning # Consider using Assert.That(actual, Is.LessThanOrEqualTo(expected)) instead of Assert.LessOrEqual(actual, expected)
dotnet_diagnostic.NUnit2031.severity = warning # Consider using Assert.That(actual, Is.Not.SameAs(expected)) instead of Assert.AreNotSame(expected, actual)
dotnet_diagnostic.NUnit2032.severity = warning # Consider using Assert.That(expr, Is.Zero) instead of Assert.Zero(expr)
dotnet_diagnostic.NUnit2033.severity = warning # Consider using Assert.That(expr, Is.Not.Zero) instead of Assert.NotZero(expr)
dotnet_diagnostic.NUnit2034.severity = warning # Consider using Assert.That(expr, Is.NaN) instead of Assert.IsNaN(expr)
dotnet_diagnostic.NUnit2035.severity = warning # Consider using Assert.That(collection, Is.Empty) instead of Assert.IsEmpty(collection)
dotnet_diagnostic.NUnit2036.severity = warning # Consider using Assert.That(collection, Is.Not.Empty) instead of Assert.IsNotEmpty(collection)
dotnet_diagnostic.NUnit2037.severity = warning # Consider using Assert.That(collection, Does.Contain(instance)) instead of Assert.Contains(instance, collection)
dotnet_diagnostic.NUnit2038.severity = warning # Consider using Assert.That(actual, Is.InstanceOf(expected)) instead of Assert.IsInstanceOf(expected, actual)
dotnet_diagnostic.NUnit2039.severity = warning # Consider using Assert.That(actual, Is.Not.InstanceOf(expected)) instead of Assert.IsNotInstanceOf(expected, actual)
[*.{appxmanifest,asax,ascx,aspx,axaml,build,c,c++,cc,cginc,compute,cp,cpp,cs,cshtml,cu,cuh,cxx,dtd,fs,fsi,fsscript,fsx,fx,fxh,h,hh,hlsl,hlsli,hlslinc,hpp,hxx,inc,inl,ino,ipp,ixx,master,ml,mli,mpp,mq4,mq5,mqh,nuspec,paml,razor,resw,resx,shader,skin,tpp,usf,ush,vb,xaml,xamlx,xoml,xsd}]
indent_style = space
indent_size = 2
tab_width = 2
+76
View File
@@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at hello@speckle.systems. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
+58
View File
@@ -0,0 +1,58 @@
# Speckle Contribution Guidelines
## Introduction
Thank you for reading this! Speckle's a rather wide network of parts that depend on each other, either directly, indirectly or even just cosmetically.
> **Speckle** is a quite large ecosystem of moving parts. Any changes may have unintended effects, that can cause problems quickly for many people (and processes) that rely on Speckle.
This means that what might look like a simple quick change in one repo may have a big hidden cost that propagates around other parts of the project. We're all here to help each other, and this guide is meant to help you get started and promote a framework that can untangle all these dependecies through discussion!
## Bugs & Issues 🐞
### Found a new bug?
- First step is to check whether this is a new bug! We encourage you to search through the issues of the project in question **and** associated repos!
- If you come up with nothing, **open a new issue with a clear title and description**, as much relevant information as possible: system configuration, code samples & steps to reproduce the problem.
- Can't mention this often enough: tells us how to reproduce the problem! We will ignore or flag as such issues without reproduction steps.
- Try to reference & note all potentially affected projects.
### Sending a PR for Bug Fixes
You fixed something! Great! We hope you logged it first :) Make sure though that you've covered the lateral thinking needed for a bug report, as described above, also in your implementation! If there any tests, make sure they all pass. If there are none, it means they're missing - so add them!
### Code Style
When collaborating on a project in GitHub, it's important to follow coding conventions and style guidelines to ensure consistency and readability of the codebase. One commonly used convention is to use two spaces for indentation.
To use two spaces for indentation in GitHub, you can configure your text editor or IDE to use this indentation style. Once you've written your code, you can commit and push your changes to GitHub.
When collaborating with others on GitHub, it's important to communicate any changes to coding conventions or style guidelines, and to work together to maintain a consistent coding style throughout the project. Code reviews can also help ensure that code is well-formatted and easy to read.
## New Features 🎉
The golden rule is to Discuss First!
- Before embarking on adding a new feature, suggest it first as an issue with the `enhancement` label and/or title - this will allow relevant people to pitch in
- We'll now discuss your requirements and see how and if they fit within the Speckle ecosystem.
- The last step is to actually start writing code & submit a PR so we can follow along!
- All new features should, if and where possible, come with tests. We won't merge without!
> Many clients may potentially have overlapping scopes, some features might already be in dev somewhere else, or might have been postponed to the next major release due to api instability in that area. For example, adding a delete stream button in the accounts panel in rhino: this feature was planned for speckle admin, and the whole functionality of the accounts panel in rhino is to be greatly reduced!
## Cosmetic Patches ✨
Changes that are cosmetic in nature and do not add anything substantial to the stability or functionality of Speckle **will generally not be accepted**.
Why? However trivial the changes might seem, there might be subtle reasons for the original code to be as it is. Furthermore, there are a lot of potential hidden costs (that even maintainers themselves are not aware of fully!) and they eat up review time unncessarily.
> **Examples**: modifying the colour of an UI element in one client may have a big hidden cost and need propagation in several other clients that implement a similar ui element. Changing the default port or specifiying `localhost` instead of `0.0.0.0` breaks cross-vm debugging and developing.
## Wrap up
Don't worry if you get things wrong. We all do, including project owners: this document should've been here a long time ago. There's plenty of room for discussion on our community [forum](https://discourse.speckle.works).
🙌❤️💙💚💜🙌
+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions" # search for actions - there are other options available
directory: "/" # search in .github/workflows under root `/`
schedule:
interval: "weekly" # check for action update every week
+26
View File
@@ -0,0 +1,26 @@
name: .NET CI Build
on:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.x.x
- uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: 🔫 Build All
run: ./build.sh
+33
View File
@@ -0,0 +1,33 @@
name: .NET Build and Publish
on:
push:
branches: ["main"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
filter: tree:0
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.x.x
- uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: 🔫 Build and Pack
run: ./build.sh pack
- name: Push to nuget.org
run: dotnet nuget push output/*.nupkg --source "https://api.nuget.org/v3/index.json" --api-key ${{secrets.CONNECTORS_NUGET_TOKEN }} --skip-duplicate
+33
View File
@@ -0,0 +1,33 @@
<Project>
<PropertyGroup Label="Company Info">
<Authors>Speckle</Authors>
<Company>Speckle</Company>
<Copyright>Copyright (c) AEC Systems Ltd</Copyright>
</PropertyGroup>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AnalysisMode>Recommended</AnalysisMode>
<WarningsAsErrors>true</WarningsAsErrors>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RunAnalyzersDuringLiveAnalysis>False</RunAnalyzersDuringLiveAnalysis>
<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<IsPackable>false</IsPackable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<PackageReadmeFile>README.md</PackageReadmeFile>
<MinVerDefaultPreReleaseIdentifiers>alpha</MinVerDefaultPreReleaseIdentifiers>
</PropertyGroup>
<ItemGroup>
<None Include="..\README.md" Pack="true" PackagePath="\"/>
</ItemGroup>
</Project>
+14
View File
@@ -0,0 +1,14 @@
<Project>
<ItemGroup>
<GlobalPackageReference Include="PolySharp" Version="1.14.1" />
<GlobalPackageReference Include="MinVer" Version="5.0.0" />
<GlobalPackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageVersion Include="xunit" Version="2.8.1" />
<PackageVersion Include="Bullseye" Version="5.0.0" />
<PackageVersion Include="Glob" Version="1.1.9" />
<PackageVersion Include="SimpleExec" Version="12.0.0" />
</ItemGroup>
</Project>
+5
View File
@@ -0,0 +1,5 @@
# Speckle.DoubleNumerics
Double version of System.Numerics vector libraries
Forked from https://github.com/Weingartner/System.Numerics.DoubleVectors and updated to modern projects and nuget
@@ -0,0 +1,189 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Xunit;
namespace Speckle.DoubleNumerics.Tests.Common.System;
public static class PlatformDetection
{
public static bool IsWindows { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public static bool IsWindows7 { get; } = IsWindows && GetWindowsVersion() == 6 && GetWindowsMinorVersion() == 1;
public static bool IsOSX { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
public static bool IsNetBSD { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD"));
public static bool IsNotWindowsNanoServer { get; } =
(
IsWindows
&& File.Exists(
Path.Combine(Environment.GetEnvironmentVariable("windir") ?? throw new NotSupportedException(), "regedit.exe")
)
);
public static bool IsWindows10Version1607OrGreater { get; } =
IsWindows && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildNumber() >= 14393;
public static int WindowsVersion { get; } = GetWindowsVersion();
private static Lazy<bool> m_isWindowsSubsystemForLinux = new Lazy<bool>(GetIsWindowsSubsystemForLinux);
public static bool IsWindowsSubsystemForLinux => m_isWindowsSubsystemForLinux.Value;
public static bool IsNotWindowsSubsystemForLinux => !IsWindowsSubsystemForLinux;
private static bool GetIsWindowsSubsystemForLinux()
{
// https://github.com/Microsoft/BashOnWindows/issues/423#issuecomment-221627364
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
const string versionFile = "/proc/version";
if (File.Exists(versionFile))
{
var s = File.ReadAllText(versionFile);
if (s.Contains("Microsoft") || s.Contains("WSL"))
{
return true;
}
}
}
return false;
}
public static bool IsDebian8 { get; } = IsDistroAndVersion("debian", "8");
public static bool IsUbuntu1510 { get; } = IsDistroAndVersion("ubuntu", "15.10");
public static bool IsUbuntu1604 { get; } = IsDistroAndVersion("ubuntu", "16.04");
public static bool IsFedora23 { get; } = IsDistroAndVersion("fedora", "23");
private static bool IsDistroAndVersion(string distroId, string versionId)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
IdVersionPair v = ParseOsReleaseFile();
if (v.Id == distroId && v.VersionId == versionId)
{
return true;
}
}
return false;
}
public static Version OSXKernelVersion { get; } = GetOSXKernelVersion();
private static IdVersionPair ParseOsReleaseFile()
{
Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Linux));
IdVersionPair ret = new IdVersionPair();
ret.Id = "";
ret.VersionId = "";
if (File.Exists("/etc/os-release"))
{
foreach (string line in File.ReadLines("/etc/os-release"))
{
if (line.StartsWith("ID=", global::System.StringComparison.Ordinal))
{
ret.Id = line.Substring("ID=".Length);
}
else if (line.StartsWith("VERSION_ID=", global::System.StringComparison.Ordinal))
{
ret.VersionId = line.Substring("VERSION_ID=".Length);
}
}
}
string versionId = ret.VersionId;
if (versionId.Length >= 2 && versionId[0] == '"' && versionId[versionId.Length - 1] == '"')
{
// Remove Quotes.
ret.VersionId = versionId.Substring(1, versionId.Length - 2);
}
return ret;
}
private struct IdVersionPair
{
public string Id { get; set; }
public string VersionId { get; set; }
}
private static int GetWindowsVersion()
{
if (IsWindows)
{
RTL_OSVERSIONINFOEX osvi = new RTL_OSVERSIONINFOEX();
osvi.dwOSVersionInfoSize = (uint)Marshal.SizeOf(osvi);
Assert.Equal(0, RtlGetVersion(out osvi));
return (int)osvi.dwMajorVersion;
}
return -1;
}
private static int GetWindowsMinorVersion()
{
if (IsWindows)
{
RTL_OSVERSIONINFOEX osvi = new RTL_OSVERSIONINFOEX();
osvi.dwOSVersionInfoSize = (uint)Marshal.SizeOf(osvi);
Assert.Equal(0, RtlGetVersion(out osvi));
return (int)osvi.dwMinorVersion;
}
return -1;
}
private static int GetWindowsBuildNumber()
{
if (IsWindows)
{
RTL_OSVERSIONINFOEX osvi = new RTL_OSVERSIONINFOEX();
osvi.dwOSVersionInfoSize = (uint)Marshal.SizeOf(osvi);
Assert.Equal(0, RtlGetVersion(out osvi));
return (int)osvi.dwBuildNumber;
}
return -1;
}
private static Version GetOSXKernelVersion()
{
if (IsOSX)
{
byte[] bytes = new byte[256];
IntPtr bytesLength = new IntPtr(bytes.Length);
Assert.Equal(0, sysctlbyname("kern.osrelease", bytes, ref bytesLength, null, IntPtr.Zero));
string versionString = Encoding.UTF8.GetString(bytes);
return Version.Parse(versionString);
}
return new Version(0, 0, 0);
}
[DllImport("libc", SetLastError = true)]
private static extern int sysctlbyname(string ctlName, byte[] oldp, ref IntPtr oldpLen, byte[]? newp, IntPtr newpLen);
[DllImport("ntdll.dll")]
private static extern int RtlGetVersion(out RTL_OSVERSIONINFOEX lpVersionInformation);
[StructLayout(LayoutKind.Sequential)]
private struct RTL_OSVERSIONINFOEX
{
internal uint dwOSVersionInfoSize;
internal uint dwMajorVersion;
internal uint dwMinorVersion;
internal uint dwBuildNumber;
internal uint dwPlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
internal string szCSDVersion;
}
}
@@ -0,0 +1,151 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.CompilerServices;
namespace Speckle.DoubleNumerics.Tests;
internal class ConstantHelper
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte GetByteWithAllBitsSet()
{
Byte value = 0;
unsafe
{
unchecked
{
*&value = 0xff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SByte GetSByteWithAllBitsSet()
{
SByte value = 0;
unsafe
{
unchecked
{
*&value = (SByte)0xff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UInt16 GetUInt16WithAllBitsSet()
{
UInt16 value = 0;
unsafe
{
unchecked
{
*&value = 0xffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Int16 GetInt16WithAllBitsSet()
{
Int16 value = 0;
unsafe
{
unchecked
{
*&value = (Int16)0xffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UInt32 GetUInt32WithAllBitsSet()
{
UInt32 value = 0;
unsafe
{
unchecked
{
*&value = 0xffffffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Int32 GetInt32WithAllBitsSet()
{
Int32 value = 0;
unsafe
{
unchecked
{
*&value = (Int32)0xffffffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UInt64 GetUInt64WithAllBitsSet()
{
UInt64 value = 0;
unsafe
{
unchecked
{
*&value = 0xffffffffffffffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Int64 GetInt64WithAllBitsSet()
{
Int64 value = 0;
unsafe
{
unchecked
{
*&value = (Int64)0xffffffffffffffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Double GetDoubleWithAllBitsSet()
{
Double value = 0;
unsafe
{
unchecked
{
*((Int32*)&value) = (Int32)0xffffffffffffffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Single GetSingleWithAllBitsSet()
{
Single value = 0;
unsafe
{
unchecked
{
*&value = 0xffffffff;
}
}
return value;
}
}
@@ -2,9 +2,6 @@
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Xml.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Runtime.InteropServices" #>
<#@ include file="..\src\System\Numerics\GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #>
using System;
@@ -13,7 +10,7 @@ using System.Linq;
using System.Reflection;
using Xunit;
namespace System.Numerics.Tests
namespace System.DoubleNumerics.Tests
{
/// <summary>
/// Vector{T} tests that use random number generation and a unified generic test structure
@@ -0,0 +1,60 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Speckle.DoubleNumerics.Tests;
static class MathHelper
{
public const double Pi = Math.PI;
public const double PiOver2 = Pi / 2f;
public const double PiOver4 = Pi / 4f;
// Angle conversion helper.
public static double ToRadians(double degrees) => degrees * Pi / 180f;
// Comparison helpers with small tolerance to allow for floating point rounding during computations.
public static bool Equal(double a, double b) => (Math.Abs(a - b) < 1e-5);
public static bool Equal(Vector2 a, Vector2 b) => Equal(a.X, b.X) && Equal(a.Y, b.Y);
public static bool Equal(Vector3 a, Vector3 b) => Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z);
public static bool Equal(Vector4 a, Vector4 b) =>
Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z) && Equal(a.W, b.W);
public static bool Equal(Matrix4x4 a, Matrix4x4 b) =>
Equal(a.M11, b.M11)
&& Equal(a.M12, b.M12)
&& Equal(a.M13, b.M13)
&& Equal(a.M14, b.M14)
&& Equal(a.M21, b.M21)
&& Equal(a.M22, b.M22)
&& Equal(a.M23, b.M23)
&& Equal(a.M24, b.M24)
&& Equal(a.M31, b.M31)
&& Equal(a.M32, b.M32)
&& Equal(a.M33, b.M33)
&& Equal(a.M34, b.M34)
&& Equal(a.M41, b.M41)
&& Equal(a.M42, b.M42)
&& Equal(a.M43, b.M43)
&& Equal(a.M44, b.M44);
public static bool Equal(Matrix3x2 a, Matrix3x2 b) =>
Equal(a.M11, b.M11)
&& Equal(a.M12, b.M12)
&& Equal(a.M21, b.M21)
&& Equal(a.M22, b.M22)
&& Equal(a.M31, b.M31)
&& Equal(a.M32, b.M32);
public static bool Equal(Plane a, Plane b) => Equal(a.Normal, b.Normal) && Equal(a.D, b.D);
public static bool Equal(Quaternion a, Quaternion b) =>
Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z) && Equal(a.W, b.W);
public static bool EqualRotation(Quaternion a, Quaternion b) => Equal(a, b) || Equal(a, -b);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,64 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.Runtime.CompilerServices;
namespace Speckle.DoubleNumerics.Tests.Performance.Common.System;
/// <summary>Static helper class for performance tests</summary>
public class PerfUtils
{
private Random _rand;
/// <summary>
/// Initializes a new PerfUtils object with the default random seed.
/// </summary>
public PerfUtils()
{
_rand = new Random(1234132);
}
/// <summary>
/// Initializes a new PerfUtils object with the given seed. Use this if also
/// using MemberData that was created using PerfUtils to avoid possible collision
/// errors.
/// </summary>
public PerfUtils(int seed)
{
_rand = new Random(seed);
}
/// <summary>
/// Helper method to create a string containing a number of random
/// characters equal to the specified length
/// </summary>
public string CreateString(int length)
{
byte[] bytes = new byte[length];
_rand.NextBytes(bytes);
return Convert.ToBase64String(bytes);
}
/// <summary>Gets a test file full path that is associated with the call site.</summary>
/// <param name="index">An optional index value to use as a suffix on the file name. Typically a loop index.</param>
/// <param name="memberName">The member name of the function calling this method.</param>
/// <param name="lineNumber">The line number of the function calling this method.</param>
public string GetTestFilePath(
int? index = null,
[CallerMemberName] string? memberName = null,
[CallerLineNumber] int lineNumber = 0
) =>
Path.Combine(
Path.GetTempPath(),
string.Format(
index.HasValue ? "{0}_{1}_{2}_{3}" : "{0}_{1}_{2}",
memberName ?? "TestBase",
lineNumber,
Path.GetRandomFileName(),
index.GetValueOrDefault()
)
);
}
@@ -0,0 +1,30 @@
//using Microsoft.Xunit.Performance;
namespace Speckle.DoubleNumerics.Tests.Performance;
public static class HashCodeTest
{
/*
[Benchmark(InnerIterationCount = 100000000)]
public static void HashTest()
{
Random rand = new Random(84329);
Vector4 vector4 = new Vector4(
Convert.ToSingle(rand.NextDouble()),
Convert.ToSingle(rand.NextDouble()),
Convert.ToSingle(rand.NextDouble()),
Convert.ToSingle(rand.NextDouble()));
foreach (var iteration in Benchmark.Iterations)
{
using (iteration.StartMeasurement())
{
for (int i = 0; i < Benchmark.InnerIterationCount; i++)
{
vector4.GetHashCode();
}
}
}
}
*/
}
@@ -0,0 +1,226 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//using Microsoft.Xunit.Performance;
using System;
using System.Collections.Generic;
namespace Speckle.DoubleNumerics.Tests.Performance;
public class Perf_Vector2
{
public static IEnumerable<object[]> TestOperations()
{
foreach (Operations op in Enum.GetValues(typeof(Operations)))
yield return new object[] { op };
}
/*
[Benchmark]
[MemberData(nameof(TestOperations))]
public void Operation(Operations operation)
{
Random rand = new Random(84329);
Vector2 v1 = new Vector2(Convert.ToSingle(rand.NextDouble()), Convert.ToSingle(rand.NextDouble()));
Vector2 v2 = new Vector2(Convert.ToSingle(rand.NextDouble()), Convert.ToSingle(rand.NextDouble()));
foreach (var iteration in Benchmark.Iterations)
using (iteration.StartMeasurement())
ExecuteTest(operation, 1000000, v1, v2);
}
*/
public void ExecuteTest(
Operations operation,
int innerIterations,
System.Numerics.Vector2 v1,
System.Numerics.Vector2 v2
)
{
System.Numerics.Vector2 res;
switch (operation)
{
case Operations.Add_Operator:
for (int i = 0; i < innerIterations; i++)
{
res = v1 + v2;
res = v1 + v2;
res = v1 + v2;
res = v1 + v2;
res = v1 + v2;
res = v1 + v2;
res = v1 + v2;
res = v1 + v2;
res = v1 + v2;
res = v1 + v2;
}
break;
case Operations.Add_Function:
for (int i = 0; i < innerIterations; i++)
{
System.Numerics.Vector2.Add(v1, v2);
System.Numerics.Vector2.Add(v1, v2);
System.Numerics.Vector2.Add(v1, v2);
System.Numerics.Vector2.Add(v1, v2);
System.Numerics.Vector2.Add(v1, v2);
System.Numerics.Vector2.Add(v1, v2);
System.Numerics.Vector2.Add(v1, v2);
System.Numerics.Vector2.Add(v1, v2);
System.Numerics.Vector2.Add(v1, v2);
System.Numerics.Vector2.Add(v1, v2);
}
break;
case Operations.Sub_Operator:
for (int i = 0; i < innerIterations; i++)
{
res = v1 - v2;
res = v1 - v2;
res = v1 - v2;
res = v1 - v2;
res = v1 - v2;
res = v1 - v2;
res = v1 - v2;
res = v1 - v2;
res = v1 - v2;
res = v1 - v2;
}
break;
case Operations.Sub_Function:
for (int i = 0; i < innerIterations; i++)
{
System.Numerics.Vector2.Subtract(v1, v2);
System.Numerics.Vector2.Subtract(v1, v2);
System.Numerics.Vector2.Subtract(v1, v2);
System.Numerics.Vector2.Subtract(v1, v2);
System.Numerics.Vector2.Subtract(v1, v2);
System.Numerics.Vector2.Subtract(v1, v2);
System.Numerics.Vector2.Subtract(v1, v2);
System.Numerics.Vector2.Subtract(v1, v2);
System.Numerics.Vector2.Subtract(v1, v2);
System.Numerics.Vector2.Subtract(v1, v2);
}
break;
case Operations.Mul_Operator:
for (int i = 0; i < innerIterations; i++)
{
res = v1 * v2;
res = v1 * v2;
res = v1 * v2;
res = v1 * v2;
res = v1 * v2;
res = v1 * v2;
res = v1 * v2;
res = v1 * v2;
res = v1 * v2;
res = v1 * v2;
}
break;
case Operations.Mul_Function:
for (int i = 0; i < innerIterations; i++)
{
System.Numerics.Vector2.Multiply(v1, v2);
System.Numerics.Vector2.Multiply(v1, v2);
System.Numerics.Vector2.Multiply(v1, v2);
System.Numerics.Vector2.Multiply(v1, v2);
System.Numerics.Vector2.Multiply(v1, v2);
System.Numerics.Vector2.Multiply(v1, v2);
System.Numerics.Vector2.Multiply(v1, v2);
System.Numerics.Vector2.Multiply(v1, v2);
System.Numerics.Vector2.Multiply(v1, v2);
System.Numerics.Vector2.Multiply(v1, v2);
}
break;
case Operations.Dot:
for (int i = 0; i < innerIterations; i++)
{
System.Numerics.Vector2.Dot(v1, v2);
System.Numerics.Vector2.Dot(v1, v2);
System.Numerics.Vector2.Dot(v1, v2);
System.Numerics.Vector2.Dot(v1, v2);
System.Numerics.Vector2.Dot(v1, v2);
System.Numerics.Vector2.Dot(v1, v2);
System.Numerics.Vector2.Dot(v1, v2);
System.Numerics.Vector2.Dot(v1, v2);
System.Numerics.Vector2.Dot(v1, v2);
System.Numerics.Vector2.Dot(v1, v2);
}
break;
case Operations.SquareRoot:
for (int i = 0; i < innerIterations; i++)
{
System.Numerics.Vector2.SquareRoot(v1);
System.Numerics.Vector2.SquareRoot(v1);
System.Numerics.Vector2.SquareRoot(v1);
System.Numerics.Vector2.SquareRoot(v1);
System.Numerics.Vector2.SquareRoot(v1);
System.Numerics.Vector2.SquareRoot(v1);
System.Numerics.Vector2.SquareRoot(v1);
System.Numerics.Vector2.SquareRoot(v1);
System.Numerics.Vector2.SquareRoot(v1);
System.Numerics.Vector2.SquareRoot(v1);
}
break;
case Operations.Length_Squared:
for (int i = 0; i < innerIterations; i++)
{
v1.LengthSquared();
v1.LengthSquared();
v1.LengthSquared();
v1.LengthSquared();
v1.LengthSquared();
v1.LengthSquared();
v1.LengthSquared();
v1.LengthSquared();
v1.LengthSquared();
v1.LengthSquared();
}
break;
case Operations.Normalize:
for (int i = 0; i < innerIterations; i++)
{
System.Numerics.Vector2.Normalize(v1);
System.Numerics.Vector2.Normalize(v1);
System.Numerics.Vector2.Normalize(v1);
System.Numerics.Vector2.Normalize(v1);
System.Numerics.Vector2.Normalize(v1);
System.Numerics.Vector2.Normalize(v1);
System.Numerics.Vector2.Normalize(v1);
System.Numerics.Vector2.Normalize(v1);
System.Numerics.Vector2.Normalize(v1);
System.Numerics.Vector2.Normalize(v1);
}
break;
case Operations.Distance_Squared:
for (int i = 0; i < innerIterations; i++)
{
System.Numerics.Vector2.DistanceSquared(v1, v2);
System.Numerics.Vector2.DistanceSquared(v1, v2);
System.Numerics.Vector2.DistanceSquared(v1, v2);
System.Numerics.Vector2.DistanceSquared(v1, v2);
System.Numerics.Vector2.DistanceSquared(v1, v2);
System.Numerics.Vector2.DistanceSquared(v1, v2);
System.Numerics.Vector2.DistanceSquared(v1, v2);
System.Numerics.Vector2.DistanceSquared(v1, v2);
System.Numerics.Vector2.DistanceSquared(v1, v2);
System.Numerics.Vector2.DistanceSquared(v1, v2);
}
break;
}
}
public enum Operations
{
Add_Operator = 1,
Add_Function = 2,
Sub_Operator = 3,
Sub_Function = 4,
Mul_Operator = 5,
Mul_Function = 6,
Dot = 7,
SquareRoot = 8,
Length_Squared = 9,
Normalize = 10,
Distance_Squared = 11
}
}
@@ -8,7 +8,7 @@ using Xunit;
using System.Numerics;
using System.Collections.Generic;
namespace System.Numerics.Tests
namespace Speckle.DoubleNumerics.Tests
{
public class Perf_Vector3
{
@@ -8,7 +8,7 @@ using Xunit;
using System.Numerics;
using System.Collections.Generic;
namespace System.Numerics.Tests
namespace Speckle.DoubleNumerics.Tests
{
public class Perf_Vector4
{
+387
View File
@@ -0,0 +1,387 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using Xunit;
namespace Speckle.DoubleNumerics.Tests;
public class PlaneTests
{
// A test for Equals (Plane)
[Fact]
public void PlaneEqualsTest1()
{
Plane a = new Plane(1.0, 2.0, 3.0, 4.0);
Plane b = new Plane(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
bool expected = true;
bool actual = a.Equals(b);
Assert.Equal(expected, actual);
// case 2: compare between different values
b.Normal = new Vector3(10.0, b.Normal.Y, b.Normal.Z);
expected = false;
actual = a.Equals(b);
Assert.Equal(expected, actual);
}
// A test for Equals (object)
[Fact]
public void PlaneEqualsTest()
{
Plane a = new Plane(1.0, 2.0, 3.0, 4.0);
Plane b = new Plane(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
object? obj = b;
bool expected = true;
bool actual = a.Equals(obj);
Assert.Equal(expected, actual);
// case 2: compare between different values
b.Normal = new Vector3(10.0, b.Normal.Y, b.Normal.Z);
obj = b;
expected = false;
actual = a.Equals(obj);
Assert.Equal(expected, actual);
// case 3: compare between different types.
obj = new Quaternion();
expected = false;
actual = a.Equals(obj);
Assert.Equal(expected, actual);
// case 3: compare against null.
obj = null;
expected = false;
actual = a.Equals(obj);
Assert.Equal(expected, actual);
}
// A test for operator != (Plane, Plane)
[Fact]
public void PlaneInequalityTest()
{
Plane a = new Plane(1.0, 2.0, 3.0, 4.0);
Plane b = new Plane(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
bool expected = false;
bool actual = a != b;
Assert.Equal(expected, actual);
// case 2: compare between different values
b.Normal = new Vector3(10.0, b.Normal.Y, b.Normal.Z);
expected = true;
actual = a != b;
Assert.Equal(expected, actual);
}
// A test for operator == (Plane, Plane)
[Fact]
public void PlaneEqualityTest()
{
Plane a = new Plane(1.0, 2.0, 3.0, 4.0);
Plane b = new Plane(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
bool expected = true;
bool actual = a == b;
Assert.Equal(expected, actual);
// case 2: compare between different values
b.Normal = new Vector3(10.0, b.Normal.Y, b.Normal.Z);
expected = false;
actual = a == b;
Assert.Equal(expected, actual);
}
// A test for GetHashCode ()
[Fact]
public void PlaneGetHashCodeTest()
{
Plane target = new Plane(1.0, 2.0, 3.0, 4.0);
int expected = target.Normal.GetHashCode() + target.D.GetHashCode();
int actual = target.GetHashCode();
Assert.Equal(expected, actual);
}
// A test for Plane (double, double, double, double)
[Fact]
public void PlaneConstructorTest1()
{
double a = 1.0,
b = 2.0,
c = 3.0,
d = 4.0;
Plane target = new Plane(a, b, c, d);
Assert.True(
target.Normal.X == a && target.Normal.Y == b && target.Normal.Z == c && target.D == d,
"Plane.cstor did not return the expected value."
);
}
// A test for Plane.CreateFromVertices
[Fact]
public void PlaneCreateFromVerticesTest()
{
Vector3 point1 = new Vector3(0.0, 1.0, 1.0);
Vector3 point2 = new Vector3(0.0, 0.0, 1.0);
Vector3 point3 = new Vector3(1.0, 0.0, 1.0);
Plane target = Plane.CreateFromVertices(point1, point2, point3);
Plane expected = new Plane(new Vector3(0, 0, 1), -1.0);
Assert.Equal(target, expected);
}
// A test for Plane.CreateFromVertices
[Fact]
public void PlaneCreateFromVerticesTest2()
{
Vector3 point1 = new Vector3(0.0, 0.0, 1.0);
Vector3 point2 = new Vector3(1.0, 0.0, 0.0);
Vector3 point3 = new Vector3(1.0, 1.0, 0.0);
Plane target = Plane.CreateFromVertices(point1, point2, point3);
double invRoot2 = 1 / Math.Sqrt(2);
Plane expected = new Plane(new Vector3(invRoot2, 0, invRoot2), -invRoot2);
Assert.True(MathHelper.Equal(target, expected), "Plane.cstor did not return the expected value.");
}
// A test for Plane (Vector3, double)
[Fact]
public void PlaneConstructorTest3()
{
Vector3 normal = new Vector3(1, 2, 3);
double d = 4;
Plane target = new Plane(normal, d);
Assert.True(target.Normal == normal && target.D == d, "Plane.cstor did not return the expected value.");
}
// A test for Plane (Vector4)
[Fact]
public void PlaneConstructorTest()
{
Vector4 value = new Vector4(1.0, 2.0, 3.0, 4.0);
Plane target = new Plane(value);
Assert.True(
target.Normal.X == value.X && target.Normal.Y == value.Y && target.Normal.Z == value.Z && target.D == value.W,
"Plane.cstor did not return the expected value."
);
}
[Fact]
public void PlaneDotTest()
{
Plane target = new Plane(2, 3, 4, 5);
Vector4 value = new Vector4(5, 4, 3, 2);
double expected = 10 + 12 + 12 + 10;
double actual = Plane.Dot(target, value);
Assert.True(MathHelper.Equal(expected, actual), "Plane.Dot returns unexpected value.");
}
[Fact]
public void PlaneDotCoordinateTest()
{
Plane target = new Plane(2, 3, 4, 5);
Vector3 value = new Vector3(5, 4, 3);
double expected = 10 + 12 + 12 + 5;
double actual = Plane.DotCoordinate(target, value);
Assert.True(MathHelper.Equal(expected, actual), "Plane.DotCoordinate returns unexpected value.");
}
[Fact]
public void PlaneDotNormalTest()
{
Plane target = new Plane(2, 3, 4, 5);
Vector3 value = new Vector3(5, 4, 3);
double expected = 10 + 12 + 12;
double actual = Plane.DotNormal(target, value);
Assert.True(MathHelper.Equal(expected, actual), "Plane.DotCoordinate returns unexpected value.");
}
[Fact]
public void PlaneNormalizeTest()
{
Plane target = new Plane(1, 2, 3, 4);
double f = target.Normal.LengthSquared();
double invF = 1.0 / Math.Sqrt(f);
Plane expected = new Plane(target.Normal * invF, target.D * invF);
Plane actual = Plane.Normalize(target);
Assert.True(MathHelper.Equal(expected, actual), "Plane.Normalize returns unexpected value.");
// normalize, normalized normal.
actual = Plane.Normalize(actual);
Assert.True(MathHelper.Equal(expected, actual), "Plane.Normalize returns unexpected value.");
}
[Fact]
// Transform by matrix
public void PlaneTransformTest1()
{
Plane target = new Plane(1, 2, 3, 4);
target = Plane.Normalize(target);
Matrix4x4 m =
Matrix4x4.CreateRotationX(MathHelper.ToRadians(30.0))
* Matrix4x4.CreateRotationY(MathHelper.ToRadians(30.0))
* Matrix4x4.CreateRotationZ(MathHelper.ToRadians(30.0));
m.M41 = 10.0;
m.M42 = 20.0;
m.M43 = 30.0;
Plane expected = new Plane();
Matrix4x4 inv;
Matrix4x4.Invert(m, out inv);
Matrix4x4 itm = Matrix4x4.Transpose(inv);
double x = target.Normal.X,
y = target.Normal.Y,
z = target.Normal.Z,
w = target.D;
expected.Normal = new Vector3(
x * itm.M11 + y * itm.M21 + z * itm.M31 + w * itm.M41,
x * itm.M12 + y * itm.M22 + z * itm.M32 + w * itm.M42,
x * itm.M13 + y * itm.M23 + z * itm.M33 + w * itm.M43
);
expected.D = x * itm.M14 + y * itm.M24 + z * itm.M34 + w * itm.M44;
Plane actual;
actual = Plane.Transform(target, m);
Assert.True(MathHelper.Equal(expected, actual), "Plane.Transform did not return the expected value.");
}
[Fact]
// Transform by quaternion
public void PlaneTransformTest2()
{
Plane target = new Plane(1, 2, 3, 4);
target = Plane.Normalize(target);
Matrix4x4 m =
Matrix4x4.CreateRotationX(MathHelper.ToRadians(30.0))
* Matrix4x4.CreateRotationY(MathHelper.ToRadians(30.0))
* Matrix4x4.CreateRotationZ(MathHelper.ToRadians(30.0));
Quaternion q = Quaternion.CreateFromRotationMatrix(m);
Plane expected = new Plane();
double x = target.Normal.X,
y = target.Normal.Y,
z = target.Normal.Z,
w = target.D;
expected.Normal = new Vector3(
x * m.M11 + y * m.M21 + z * m.M31 + w * m.M41,
x * m.M12 + y * m.M22 + z * m.M32 + w * m.M42,
x * m.M13 + y * m.M23 + z * m.M33 + w * m.M43
);
expected.D = x * m.M14 + y * m.M24 + z * m.M34 + w * m.M44;
Plane actual;
actual = Plane.Transform(target, q);
Assert.True(MathHelper.Equal(expected, actual), "Plane.Transform did not return the expected value.");
}
// A test for Plane comparison involving NaN values
[Fact]
public void PlaneEqualsNanTest()
{
Plane a = new Plane(double.NaN, 0, 0, 0);
Plane b = new Plane(0, double.NaN, 0, 0);
Plane c = new Plane(0, 0, double.NaN, 0);
Plane d = new Plane(0, 0, 0, double.NaN);
Assert.False(a == new Plane(0, 0, 0, 0));
Assert.False(b == new Plane(0, 0, 0, 0));
Assert.False(c == new Plane(0, 0, 0, 0));
Assert.False(d == new Plane(0, 0, 0, 0));
Assert.True(a != new Plane(0, 0, 0, 0));
Assert.True(b != new Plane(0, 0, 0, 0));
Assert.True(c != new Plane(0, 0, 0, 0));
Assert.True(d != new Plane(0, 0, 0, 0));
Assert.False(a.Equals(new Plane(0, 0, 0, 0)));
Assert.False(b.Equals(new Plane(0, 0, 0, 0)));
Assert.False(c.Equals(new Plane(0, 0, 0, 0)));
Assert.False(d.Equals(new Plane(0, 0, 0, 0)));
// Counterintuitive result - IEEE rules for NaN comparison are weird!
Assert.False(a.Equals(a));
Assert.False(b.Equals(b));
Assert.False(c.Equals(c));
Assert.False(d.Equals(d));
}
/* Enable when size of Vector3 is correct
// A test to make sure these types are blittable directly into GPU buffer memory layouts
[Fact]
public unsafe void PlaneSizeofTest()
{
Assert.Equal(16, sizeof(Plane));
Assert.Equal(32, sizeof(Plane_2x));
Assert.Equal(20, sizeof(PlanePlusFloat));
Assert.Equal(40, sizeof(PlanePlusFloat_2x));
}
*/
[Fact]
public void PlaneToStringTest()
{
Plane target = new Plane(1, 2, 3, 4);
string expected = string.Format(CultureInfo.CurrentCulture, "{{Normal:{0:G} D:{1}}}", target.Normal, target.D);
Assert.Equal(expected, target.ToString());
}
[StructLayout(LayoutKind.Sequential)]
struct Plane_2x
{
private Plane _a;
private Plane _b;
}
[StructLayout(LayoutKind.Sequential)]
struct PlanePlusFloat
{
private Plane _v;
private double _f;
}
[StructLayout(LayoutKind.Sequential)]
struct PlanePlusFloat_2x
{
private PlanePlusFloat _a;
private PlanePlusFloat _b;
}
// A test to make sure the fields are laid out how we expect
[Fact]
public unsafe void PlaneFieldOffsetTest()
{
Plane plane = new Plane();
double* basePtr = &plane.Normal.X; // Take address of first element
Plane* planePtr = &plane; // Take address of whole Plane
Assert.Equal(new IntPtr(basePtr), new IntPtr(planePtr));
Assert.Equal(new IntPtr(basePtr + 0), new IntPtr(&plane.Normal));
Assert.Equal(new IntPtr(basePtr + 3), new IntPtr(&plane.D));
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>false</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Speckle.DoubleNumerics\Speckle.DoubleNumerics.csproj" />
</ItemGroup>
</Project>
+201
View File
@@ -0,0 +1,201 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Linq;
namespace Speckle.DoubleNumerics.Tests;
public static class Util
{
private static Random s_random = new Random();
public static void SetRandomSeed(int seed) => s_random = new Random(seed);
/// <summary>
/// Generates random floats between 0 and 100.
/// </summary>
/// <param name="numValues">The number of values to generate</param>
/// <returns>An array containing the random floats</returns>
public static double[] GenerateRandomFloats(int numValues)
{
double[] values = new double[numValues];
for (int g = 0; g < numValues; g++)
{
values[g] = s_random.NextDouble() * 99 + 1;
}
return values;
}
/// <summary>
/// Generates random ints between 0 and 99, inclusive.
/// </summary>
/// <param name="numValues">The number of values to generate</param>
/// <returns>An array containing the random ints</returns>
public static int[] GenerateRandomInts(int numValues)
{
int[] values = new int[numValues];
for (int g = 0; g < numValues; g++)
{
values[g] = s_random.Next(1, 100);
}
return values;
}
/// <summary>
/// Generates random doubles between 0 and 100.
/// </summary>
/// <param name="numValues">The number of values to generate</param>
/// <returns>An array containing the random doubles</returns>
public static double[] GenerateRandomDoubles(int numValues)
{
double[] values = new double[numValues];
for (int g = 0; g < numValues; g++)
{
values[g] = s_random.NextDouble() * 99 + 1;
}
return values;
}
/// <summary>
/// Generates random doubles between 1 and 100.
/// </summary>
/// <param name="numValues">The number of values to generate</param>
/// <returns>An array containing the random doubles</returns>
public static long[] GenerateRandomLongs(int numValues)
{
long[] values = new long[numValues];
for (int g = 0; g < numValues; g++)
{
values[g] = s_random.Next(1, 100) * (long.MaxValue / int.MaxValue);
}
return values;
}
public static T[] GenerateRandomValues<T>(int numValues, int min = 1, int max = 100)
where T : struct
{
T[] values = new T[numValues];
for (int g = 0; g < numValues; g++)
{
values[g] = GenerateSingleValue<T>(min, max);
}
return values;
}
public static T GenerateSingleValue<T>(int min = 1, int max = 100)
where T : struct
{
var randomRange = s_random.Next(min, max);
T value = (T)(dynamic)randomRange;
return value;
}
public static T Abs<T>(T value)
where T : struct
{
Type[] unsignedTypes = new[] { typeof(Byte), typeof(UInt16), typeof(UInt32), typeof(UInt64) };
if (unsignedTypes.Contains(typeof(T)))
{
return value;
}
dynamic dyn = value;
var abs = Math.Abs(dyn);
T ret = (T)abs;
return ret;
}
public static T Sqrt<T>(T value)
where T : struct => (T)(dynamic)(Math.Sqrt((dynamic)value));
public static T Multiply<T>(T left, T right)
where T : struct => (T)((dynamic)left * right);
public static T Divide<T>(T left, T right)
where T : struct => (T)((dynamic)left / right);
public static T Add<T>(T left, T right)
where T : struct => (T)((dynamic)left + right);
public static T Subtract<T>(T left, T right)
where T : struct => (T)((dynamic)left - right);
public static T Xor<T>(T left, T right)
where T : struct => (T)((dynamic)left ^ right);
public static T AndNot<T>(T left, T right)
where T : struct => (T)((dynamic)left & ~(dynamic)right);
public static T OnesComplement<T>(T left)
where T : struct => (T)(~(dynamic)left);
public static double Clamp(double value, double min, double max) =>
value > max
? max
: value < min
? min
: value;
public static T Zero<T>()
where T : struct => (T)(dynamic)0;
public static T One<T>()
where T : struct => (T)(dynamic)1;
public static bool GreaterThan<T>(T left, T right)
where T : struct
{
var result = (dynamic)left > right;
return (bool)result;
}
public static bool GreaterThanOrEqual<T>(T left, T right)
where T : struct
{
var result = (dynamic)left >= right;
return (bool)result;
}
public static bool LessThan<T>(T left, T right)
where T : struct
{
var result = (dynamic)left < right;
return (bool)result;
}
public static bool LessThanOrEqual<T>(T left, T right)
where T : struct
{
var result = (dynamic)left <= right;
return (bool)result;
}
public static bool AnyEqual<T>(T[] left, T[] right)
where T : struct
{
for (int g = 0; g < left.Length; g++)
{
if (((IEquatable<T>)left[g]).Equals(right[g]))
{
return true;
}
}
return false;
}
public static bool AllEqual<T>(T[] left, T[] right)
where T : struct
{
for (int g = 0; g < left.Length; g++)
{
if (!((IEquatable<T>)left[g]).Equals(right[g]))
{
return false;
}
}
return true;
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,135 @@
{
"version": 2,
"dependencies": {
"net8.0": {
"Microsoft.NET.Test.Sdk": {
"type": "Direct",
"requested": "[17.10.0, )",
"resolved": "17.10.0",
"contentHash": "0/2HeACkaHEYU3wc83YlcD2Fi4LMtECJjqrtvw0lPi9DCEa35zSPt1j4fuvM8NagjDqJuh1Ja35WcRtn1Um6/A==",
"dependencies": {
"Microsoft.CodeCoverage": "17.10.0",
"Microsoft.TestPlatform.TestHost": "17.10.0"
}
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"MinVer": {
"type": "Direct",
"requested": "[5.0.0, )",
"resolved": "5.0.0",
"contentHash": "ybkgpQMtt0Fo91l5rYtE3TZtD+Nmy5Ko091xvfXXOosQdMi30XO2EZ2+ShZt89gdu7RMmJqZaJ+e1q6d+6+KNw=="
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
},
"xunit": {
"type": "Direct",
"requested": "[2.8.1, )",
"resolved": "2.8.1",
"contentHash": "MLBz2NQp3rtSIoJdjj3DBEr/EeOFlQYF3oCCljat3DY9GQ7yYmtjIAv8Zyfm5BcwYso5sjvIe5scuHaJPVCGIQ==",
"dependencies": {
"xunit.analyzers": "1.14.0",
"xunit.assert": "2.8.1",
"xunit.core": "[2.8.1]"
}
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.CodeCoverage": {
"type": "Transitive",
"resolved": "17.10.0",
"contentHash": "yC7oSlnR54XO5kOuHlVOKtxomNNN1BWXX8lK1G2jaPXT9sUok7kCOoA4Pgs0qyFaCtMrNsprztYMeoEGqCm4uA=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
},
"Microsoft.TestPlatform.ObjectModel": {
"type": "Transitive",
"resolved": "17.10.0",
"contentHash": "KkwhjQevuDj0aBRoPLY6OLAhGqbPUEBuKLbaCs0kUVw29qiOYncdORd4mLVJbn9vGZ7/iFGQ/+AoJl0Tu5Umdg==",
"dependencies": {
"System.Reflection.Metadata": "1.6.0"
}
},
"Microsoft.TestPlatform.TestHost": {
"type": "Transitive",
"resolved": "17.10.0",
"contentHash": "LWpMdfqhHvcUkeMCvNYJO8QlPLlYz9XPPb+ZbaXIKhdmjAV0wqTSrTiW5FLaf7RRZT50AQADDOYMOe0HxDxNgA==",
"dependencies": {
"Microsoft.TestPlatform.ObjectModel": "17.10.0",
"Newtonsoft.Json": "13.0.1"
}
},
"Newtonsoft.Json": {
"type": "Transitive",
"resolved": "13.0.1",
"contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
},
"System.Reflection.Metadata": {
"type": "Transitive",
"resolved": "1.6.0",
"contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ=="
},
"xunit.abstractions": {
"type": "Transitive",
"resolved": "2.0.3",
"contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
},
"xunit.analyzers": {
"type": "Transitive",
"resolved": "1.14.0",
"contentHash": "KcFBmV2150xZHPUebV3YLR5gGl8R4wLuPOoxMiwCf1L4bL8ls0dcwtGFzr6NvQRgg6dWgSqbE52I6SYyeB0VnQ=="
},
"xunit.assert": {
"type": "Transitive",
"resolved": "2.8.1",
"contentHash": "DDM18ur+PeNFhQ4w/vO+uvCUy8hA3OS5+AMf/CFov9Wco7Le49zzj0hovRWwa8f/3vaUfjL5r+IkPvqEHu2IIg=="
},
"xunit.core": {
"type": "Transitive",
"resolved": "2.8.1",
"contentHash": "Ng4Q/DOwotESPl5CufcdqgP6O2KDpdEcIvNfA3upzfCiBrkj5WsmLhf/XUsCVolzvHA7b1WUlyeTo7j1ulG4gQ==",
"dependencies": {
"xunit.extensibility.core": "[2.8.1]",
"xunit.extensibility.execution": "[2.8.1]"
}
},
"xunit.extensibility.core": {
"type": "Transitive",
"resolved": "2.8.1",
"contentHash": "ilfAsxEhpne9AXXf3W+O65mRgGum94m2xHYm1yeJ1m7eiINM6OOwpaHhoNC/KWEQ2u/WF6/XiEs+Q0TOq7hiGA==",
"dependencies": {
"xunit.abstractions": "2.0.3"
}
},
"xunit.extensibility.execution": {
"type": "Transitive",
"resolved": "2.8.1",
"contentHash": "38UnJW+64Wn8QIabujcNEw0HKvWw2AlYCgU8GNwCCDqyrSuRYb7zwetn7SHoHfbL9e9FAvEiAMXmc2wSUY8sVQ==",
"dependencies": {
"xunit.extensibility.core": "[2.8.1]"
}
},
"speckle.doublenumerics": {
"type": "Project"
}
}
}
}
+60
View File
@@ -0,0 +1,60 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.DoubleNumerics", "Speckle.DoubleNumerics\Speckle.DoubleNumerics.csproj", "{18483631-763C-48A4-9045-A3C3F93D23F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.DoubleNumerics.Tests", "Speckle.DoubleNumerics.Tests\Speckle.DoubleNumerics.Tests.csproj", "{B2285BCF-508C-444F-95B0-2A7D5A4FC2A3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "build", "build\build.csproj", "{BCCBED66-C79D-48EA-980B-D17998ECB2F2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{38CFC80F-1EC0-42B1-9ED0-E030CFE2E5B0}"
ProjectSection(SolutionItems) = preProject
.csharpierrc.yaml = .csharpierrc.yaml
.editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props
Directory.Packages.props = Directory.Packages.props
global.json = global.json
.github\workflows\ci.yml = .github\workflows\ci.yml
.github\workflows\main.yml = .github\workflows\main.yml
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
net46_Debug|Any CPU = net46_Debug|Any CPU
net46_Release|Any CPU = net46_Release|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{18483631-763C-48A4-9045-A3C3F93D23F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.net46_Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.net46_Debug|Any CPU.Build.0 = Debug|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.net46_Release|Any CPU.ActiveCfg = Release|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.net46_Release|Any CPU.Build.0 = Release|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.Release|Any CPU.Build.0 = Release|Any CPU
{B2285BCF-508C-444F-95B0-2A7D5A4FC2A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2285BCF-508C-444F-95B0-2A7D5A4FC2A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2285BCF-508C-444F-95B0-2A7D5A4FC2A3}.net46_Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2285BCF-508C-444F-95B0-2A7D5A4FC2A3}.net46_Debug|Any CPU.Build.0 = Debug|Any CPU
{B2285BCF-508C-444F-95B0-2A7D5A4FC2A3}.net46_Release|Any CPU.ActiveCfg = Debug|Any CPU
{B2285BCF-508C-444F-95B0-2A7D5A4FC2A3}.net46_Release|Any CPU.Build.0 = Debug|Any CPU
{B2285BCF-508C-444F-95B0-2A7D5A4FC2A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2285BCF-508C-444F-95B0-2A7D5A4FC2A3}.Release|Any CPU.Build.0 = Release|Any CPU
{BCCBED66-C79D-48EA-980B-D17998ECB2F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BCCBED66-C79D-48EA-980B-D17998ECB2F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BCCBED66-C79D-48EA-980B-D17998ECB2F2}.net46_Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BCCBED66-C79D-48EA-980B-D17998ECB2F2}.net46_Debug|Any CPU.Build.0 = Debug|Any CPU
{BCCBED66-C79D-48EA-980B-D17998ECB2F2}.net46_Release|Any CPU.ActiveCfg = Debug|Any CPU
{BCCBED66-C79D-48EA-980B-D17998ECB2F2}.net46_Release|Any CPU.Build.0 = Debug|Any CPU
{BCCBED66-C79D-48EA-980B-D17998ECB2F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BCCBED66-C79D-48EA-980B-D17998ECB2F2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+2
View File
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CustomTools/CustomToolsData/@EntryValue">ExternalToolData|CSharpier|csharpier||csharpier|$FILE$</s:String></wpf:ResourceDictionary>
+150
View File
@@ -0,0 +1,150 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
namespace Speckle.DoubleNumerics;
internal class ConstantHelper
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte GetByteWithAllBitsSet()
{
Byte value = 0;
unsafe
{
unchecked
{
*&value = 0xff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SByte GetSByteWithAllBitsSet()
{
SByte value = 0;
unsafe
{
unchecked
{
*&value = (SByte)0xff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UInt16 GetUInt16WithAllBitsSet()
{
UInt16 value = 0;
unsafe
{
unchecked
{
*&value = 0xffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Int16 GetInt16WithAllBitsSet()
{
Int16 value = 0;
unsafe
{
unchecked
{
*&value = (Int16)0xffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UInt32 GetUInt32WithAllBitsSet()
{
UInt32 value = 0;
unsafe
{
unchecked
{
*&value = 0xffffffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Int32 GetInt32WithAllBitsSet()
{
Int32 value = 0;
unsafe
{
unchecked
{
*&value = (Int32)0xffffffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static UInt64 GetUInt64WithAllBitsSet()
{
UInt64 value = 0;
unsafe
{
unchecked
{
*&value = 0xffffffffffffffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Int64 GetInt64WithAllBitsSet()
{
Int64 value = 0;
unsafe
{
unchecked
{
*&value = (Int64)0xffffffffffffffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Double GetDoubleWithAllBitsSet()
{
Double value = 0;
unsafe
{
unchecked
{
*((Int32*)&value) = (Int32)0xffffffffffffffff;
}
}
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Single GetSingleWithAllBitsSet()
{
Single value = 0;
unsafe
{
unchecked
{
*&value = 0xffffffff;
}
}
return value;
}
}
+16
View File
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Speckle.DoubleNumerics;
internal static class HashHelpers
{
public static int Combine(int h1, int h2)
{
// The jit optimizes this to use the ROL instruction on x86
// Related GitHub pull request: dotnet/coreclr#1830
uint shift5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
return ((int)shift5 + h1) ^ h2;
}
}
+825
View File
@@ -0,0 +1,825 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Text;
namespace Speckle.DoubleNumerics;
/// <summary>
/// A structure encapsulating a 3x2 matrix.
/// </summary>
public struct Matrix3x2 : IEquatable<Matrix3x2>
{
#region Public Fields
/// <summary>
/// The first element of the first row
/// </summary>
public double M11;
/// <summary>
/// The second element of the first row
/// </summary>
public double M12;
/// <summary>
/// The first element of the second row
/// </summary>
public double M21;
/// <summary>
/// The second element of the second row
/// </summary>
public double M22;
/// <summary>
/// The first element of the third row
/// </summary>
public double M31;
/// <summary>
/// The second element of the third row
/// </summary>
public double M32;
#endregion Public Fields
private static readonly Matrix3x2 _identity = new(1, 0, 0, 1, 0, 0);
/// <summary>
/// Returns the multiplicative identity matrix.
/// </summary>
public static Matrix3x2 Identity => _identity;
/// <summary>
/// Returns whether the matrix is the identity matrix.
/// </summary>
public bool IsIdentity =>
M11 == 1
&& M22 == 1
&& // Check diagonal element first for early out.
M12 == 0
&& M21 == 0
&& M31 == 0
&& M32 == 0;
/// <summary>
/// Gets or sets the translation component of this matrix.
/// </summary>
public Vector2 Translation
{
get => new(M31, M32);
set
{
M31 = value.X;
M32 = value.Y;
}
}
/// <summary>
/// Constructs a Matrix3x2 from the given components.
/// </summary>
public Matrix3x2(double m11, double m12, double m21, double m22, double m31, double m32)
{
M11 = m11;
M12 = m12;
M21 = m21;
M22 = m22;
M31 = m31;
M32 = m32;
}
/// <summary>
/// Creates a translation matrix from the given vector.
/// </summary>
/// <param name="position">The translation position.</param>
/// <returns>A translation matrix.</returns>
public static Matrix3x2 CreateTranslation(Vector2 position)
{
Matrix3x2 result;
result.M11 = 1.0;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = 1.0;
result.M31 = position.X;
result.M32 = position.Y;
return result;
}
/// <summary>
/// Creates a translation matrix from the given X and Y components.
/// </summary>
/// <param name="xPosition">The X position.</param>
/// <param name="yPosition">The Y position.</param>
/// <returns>A translation matrix.</returns>
public static Matrix3x2 CreateTranslation(double xPosition, double yPosition)
{
Matrix3x2 result;
result.M11 = 1.0;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = 1.0;
result.M31 = xPosition;
result.M32 = yPosition;
return result;
}
public string ToMultiLineString()
{
var ci = CultureInfo.CurrentCulture;
var sb = new StringBuilder();
sb.AppendLine($"{M11.ToString(ci), -19} {M12.ToString(ci), -19}");
sb.AppendLine($"{M21.ToString(ci), -19} {M22.ToString(ci), -19}");
sb.AppendLine($"{M31.ToString(ci), -19} {M32.ToString(ci), -19}");
return sb.ToString();
}
/// <summary>
/// Creates a scale matrix from the given X and Y components.
/// </summary>
/// <param name="xScale">Value to scale by on the X-axis.</param>
/// <param name="yScale">Value to scale by on the Y-axis.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(double xScale, double yScale)
{
Matrix3x2 result;
result.M11 = xScale;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = yScale;
result.M31 = 0.0;
result.M32 = 0.0;
return result;
}
/// <summary>
/// Creates a scale matrix that is offset by a given center point.
/// </summary>
/// <param name="xScale">Value to scale by on the X-axis.</param>
/// <param name="yScale">Value to scale by on the Y-axis.</param>
/// <param name="centerPoint">The center point.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(double xScale, double yScale, Vector2 centerPoint)
{
Matrix3x2 result;
double tx = centerPoint.X * (1 - xScale);
double ty = centerPoint.Y * (1 - yScale);
result.M11 = xScale;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = yScale;
result.M31 = tx;
result.M32 = ty;
return result;
}
/// <summary>
/// Creates a scale matrix from the given vector scale.
/// </summary>
/// <param name="scales">The scale to use.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(Vector2 scales)
{
Matrix3x2 result;
result.M11 = scales.X;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = scales.Y;
result.M31 = 0.0;
result.M32 = 0.0;
return result;
}
/// <summary>
/// Creates a scale matrix from the given vector scale with an offset from the given center point.
/// </summary>
/// <param name="scales">The scale to use.</param>
/// <param name="centerPoint">The center offset.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(Vector2 scales, Vector2 centerPoint)
{
Matrix3x2 result;
double tx = centerPoint.X * (1 - scales.X);
double ty = centerPoint.Y * (1 - scales.Y);
result.M11 = scales.X;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = scales.Y;
result.M31 = tx;
result.M32 = ty;
return result;
}
/// <summary>
/// Creates a scale matrix that scales uniformly with the given scale.
/// </summary>
/// <param name="scale">The uniform scale to use.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(double scale)
{
Matrix3x2 result;
result.M11 = scale;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = scale;
result.M31 = 0.0;
result.M32 = 0.0;
return result;
}
/// <summary>
/// Creates a scale matrix that scales uniformly with the given scale with an offset from the given center.
/// </summary>
/// <param name="scale">The uniform scale to use.</param>
/// <param name="centerPoint">The center offset.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(double scale, Vector2 centerPoint)
{
Matrix3x2 result;
double tx = centerPoint.X * (1 - scale);
double ty = centerPoint.Y * (1 - scale);
result.M11 = scale;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = scale;
result.M31 = tx;
result.M32 = ty;
return result;
}
/// <summary>
/// Creates a skew matrix from the given angles in radians.
/// </summary>
/// <param name="radiansX">The X angle, in radians.</param>
/// <param name="radiansY">The Y angle, in radians.</param>
/// <returns>A skew matrix.</returns>
public static Matrix3x2 CreateSkew(double radiansX, double radiansY)
{
Matrix3x2 result;
double xTan = Math.Tan(radiansX);
double yTan = Math.Tan(radiansY);
result.M11 = 1.0;
result.M12 = yTan;
result.M21 = xTan;
result.M22 = 1.0;
result.M31 = 0.0;
result.M32 = 0.0;
return result;
}
/// <summary>
/// Creates a skew matrix from the given angles in radians and a center point.
/// </summary>
/// <param name="radiansX">The X angle, in radians.</param>
/// <param name="radiansY">The Y angle, in radians.</param>
/// <param name="centerPoint">The center point.</param>
/// <returns>A skew matrix.</returns>
public static Matrix3x2 CreateSkew(double radiansX, double radiansY, Vector2 centerPoint)
{
Matrix3x2 result;
double xTan = Math.Tan(radiansX);
double yTan = Math.Tan(radiansY);
double tx = -centerPoint.Y * xTan;
double ty = -centerPoint.X * yTan;
result.M11 = 1.0;
result.M12 = yTan;
result.M21 = xTan;
result.M22 = 1.0;
result.M31 = tx;
result.M32 = ty;
return result;
}
/// <summary>
/// Creates a rotation matrix using the given rotation in radians.
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <returns>A rotation matrix.</returns>
public static Matrix3x2 CreateRotation(double radians)
{
Matrix3x2 result;
radians = Math.IEEERemainder(radians, Math.PI * 2);
double c,
s;
const double epsilon = 0.001 * Math.PI / 180; // 0.1% of a degree
if (radians > -epsilon && radians < epsilon)
{
// Exact case for zero rotation.
c = 1;
s = 0;
}
else if (radians > Math.PI / 2 - epsilon && radians < Math.PI / 2 + epsilon)
{
// Exact case for 90 degree rotation.
c = 0;
s = 1;
}
else if (radians < -Math.PI + epsilon || radians > Math.PI - epsilon)
{
// Exact case for 180 degree rotation.
c = -1;
s = 0;
}
else if (radians > -Math.PI / 2 - epsilon && radians < -Math.PI / 2 + epsilon)
{
// Exact case for 270 degree rotation.
c = 0;
s = -1;
}
else
{
// Arbitrary rotation.
c = Math.Cos(radians);
s = Math.Sin(radians);
}
// [ c s ]
// [ -s c ]
// [ 0 0 ]
result.M11 = c;
result.M12 = s;
result.M21 = -s;
result.M22 = c;
result.M31 = 0.0;
result.M32 = 0.0;
return result;
}
/// <summary>
/// Creates a rotation matrix using the given rotation in radians and a center point.
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <param name="centerPoint">The center point.</param>
/// <returns>A rotation matrix.</returns>
public static Matrix3x2 CreateRotation(double radians, Vector2 centerPoint)
{
Matrix3x2 result;
radians = Math.IEEERemainder(radians, Math.PI * 2);
double c,
s;
const double epsilon = 0.001 * Math.PI / 180; // 0.1% of a degree
if (radians > -epsilon && radians < epsilon)
{
// Exact case for zero rotation.
c = 1;
s = 0;
}
else if (radians > Math.PI / 2 - epsilon && radians < Math.PI / 2 + epsilon)
{
// Exact case for 90 degree rotation.
c = 0;
s = 1;
}
else if (radians < -Math.PI + epsilon || radians > Math.PI - epsilon)
{
// Exact case for 180 degree rotation.
c = -1;
s = 0;
}
else if (radians > -Math.PI / 2 - epsilon && radians < -Math.PI / 2 + epsilon)
{
// Exact case for 270 degree rotation.
c = 0;
s = -1;
}
else
{
// Arbitrary rotation.
c = Math.Cos(radians);
s = Math.Sin(radians);
}
double x = centerPoint.X * (1 - c) + centerPoint.Y * s;
double y = centerPoint.Y * (1 - c) - centerPoint.X * s;
// [ c s ]
// [ -s c ]
// [ x y ]
result.M11 = c;
result.M12 = s;
result.M21 = -s;
result.M22 = c;
result.M31 = x;
result.M32 = y;
return result;
}
/// <summary>
/// Calculates the determinant for this matrix.
/// The determinant is calculated by expanding the matrix with a third column whose values are (0,0,1).
/// </summary>
/// <returns>The determinant.</returns>
public double GetDeterminant() =>
// There isn't actually any such thing as a determinant for a non-square matrix,
// but this 3x2 type is really just an optimization of a 3x3 where we happen to
// know the rightmost column is always (0, 0, 1). So we expand to 3x3 format:
//
// [ M11, M12, 0 ]
// [ M21, M22, 0 ]
// [ M31, M32, 1 ]
//
// Sum the diagonal products:
// (M11 * M22 * 1) + (M12 * 0 * M31) + (0 * M21 * M32)
//
// Subtract the opposite diagonal products:
// (M31 * M22 * 0) + (M32 * 0 * M11) + (1 * M21 * M12)
//
// Collapse out the constants and oh look, this is just a 2x2 determinant!
(M11 * M22) - (M21 * M12);
/// <summary>
/// Attempts to invert the given matrix. If the operation succeeds, the inverted matrix is stored in the result parameter.
/// </summary>
/// <param name="matrix">The source matrix.</param>
/// <param name="result">The output matrix.</param>
/// <returns>True if the operation succeeded, False otherwise.</returns>
public static bool Invert(Matrix3x2 matrix, out Matrix3x2 result)
{
double det = (matrix.M11 * matrix.M22) - (matrix.M21 * matrix.M12);
if (Math.Abs(det) < double.Epsilon)
{
result = new Matrix3x2(double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN);
return false;
}
double invDet = 1.0 / det;
result.M11 = matrix.M22 * invDet;
result.M12 = -matrix.M12 * invDet;
result.M21 = -matrix.M21 * invDet;
result.M22 = matrix.M11 * invDet;
result.M31 = (matrix.M21 * matrix.M32 - matrix.M31 * matrix.M22) * invDet;
result.M32 = (matrix.M31 * matrix.M12 - matrix.M11 * matrix.M32) * invDet;
return true;
}
/// <summary>
/// Linearly interpolates from matrix1 to matrix2, based on the third parameter.
/// </summary>
/// <param name="matrix1">The first source matrix.</param>
/// <param name="matrix2">The second source matrix.</param>
/// <param name="amount">The relative weighting of matrix2.</param>
/// <returns>The interpolated matrix.</returns>
public static Matrix3x2 Lerp(Matrix3x2 matrix1, Matrix3x2 matrix2, double amount)
{
Matrix3x2 result;
// First row
result.M11 = matrix1.M11 + (matrix2.M11 - matrix1.M11) * amount;
result.M12 = matrix1.M12 + (matrix2.M12 - matrix1.M12) * amount;
// Second row
result.M21 = matrix1.M21 + (matrix2.M21 - matrix1.M21) * amount;
result.M22 = matrix1.M22 + (matrix2.M22 - matrix1.M22) * amount;
// Third row
result.M31 = matrix1.M31 + (matrix2.M31 - matrix1.M31) * amount;
result.M32 = matrix1.M32 + (matrix2.M32 - matrix1.M32) * amount;
return result;
}
/// <summary>
/// Negates the given matrix by multiplying all values by -1.
/// </summary>
/// <param name="value">The source matrix.</param>
/// <returns>The negated matrix.</returns>
public static Matrix3x2 Negate(Matrix3x2 value)
{
Matrix3x2 result;
result.M11 = -value.M11;
result.M12 = -value.M12;
result.M21 = -value.M21;
result.M22 = -value.M22;
result.M31 = -value.M31;
result.M32 = -value.M32;
return result;
}
/// <summary>
/// Adds each matrix element in value1 with its corresponding element in value2.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The matrix containing the summed values.</returns>
public static Matrix3x2 Add(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 result;
result.M11 = value1.M11 + value2.M11;
result.M12 = value1.M12 + value2.M12;
result.M21 = value1.M21 + value2.M21;
result.M22 = value1.M22 + value2.M22;
result.M31 = value1.M31 + value2.M31;
result.M32 = value1.M32 + value2.M32;
return result;
}
/// <summary>
/// Subtracts each matrix element in value2 from its corresponding element in value1.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The matrix containing the resulting values.</returns>
public static Matrix3x2 Subtract(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 result;
result.M11 = value1.M11 - value2.M11;
result.M12 = value1.M12 - value2.M12;
result.M21 = value1.M21 - value2.M21;
result.M22 = value1.M22 - value2.M22;
result.M31 = value1.M31 - value2.M31;
result.M32 = value1.M32 - value2.M32;
return result;
}
/// <summary>
/// Multiplies two matrices together and returns the resulting matrix.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The product matrix.</returns>
public static Matrix3x2 Multiply(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 result;
// First row
result.M11 = value1.M11 * value2.M11 + value1.M12 * value2.M21;
result.M12 = value1.M11 * value2.M12 + value1.M12 * value2.M22;
// Second row
result.M21 = value1.M21 * value2.M11 + value1.M22 * value2.M21;
result.M22 = value1.M21 * value2.M12 + value1.M22 * value2.M22;
// Third row
result.M31 = value1.M31 * value2.M11 + value1.M32 * value2.M21 + value2.M31;
result.M32 = value1.M31 * value2.M12 + value1.M32 * value2.M22 + value2.M32;
return result;
}
/// <summary>
/// Scales all elements in a matrix by the given scalar factor.
/// </summary>
/// <param name="value1">The source matrix.</param>
/// <param name="value2">The scaling value to use.</param>
/// <returns>The resulting matrix.</returns>
public static Matrix3x2 Multiply(Matrix3x2 value1, double value2)
{
Matrix3x2 result;
result.M11 = value1.M11 * value2;
result.M12 = value1.M12 * value2;
result.M21 = value1.M21 * value2;
result.M22 = value1.M22 * value2;
result.M31 = value1.M31 * value2;
result.M32 = value1.M32 * value2;
return result;
}
/// <summary>
/// Negates the given matrix by multiplying all values by -1.
/// </summary>
/// <param name="value">The source matrix.</param>
/// <returns>The negated matrix.</returns>
public static Matrix3x2 operator -(Matrix3x2 value)
{
Matrix3x2 m;
m.M11 = -value.M11;
m.M12 = -value.M12;
m.M21 = -value.M21;
m.M22 = -value.M22;
m.M31 = -value.M31;
m.M32 = -value.M32;
return m;
}
/// <summary>
/// Adds each matrix element in value1 with its corresponding element in value2.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The matrix containing the summed values.</returns>
public static Matrix3x2 operator +(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 m;
m.M11 = value1.M11 + value2.M11;
m.M12 = value1.M12 + value2.M12;
m.M21 = value1.M21 + value2.M21;
m.M22 = value1.M22 + value2.M22;
m.M31 = value1.M31 + value2.M31;
m.M32 = value1.M32 + value2.M32;
return m;
}
/// <summary>
/// Subtracts each matrix element in value2 from its corresponding element in value1.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The matrix containing the resulting values.</returns>
public static Matrix3x2 operator -(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 m;
m.M11 = value1.M11 - value2.M11;
m.M12 = value1.M12 - value2.M12;
m.M21 = value1.M21 - value2.M21;
m.M22 = value1.M22 - value2.M22;
m.M31 = value1.M31 - value2.M31;
m.M32 = value1.M32 - value2.M32;
return m;
}
/// <summary>
/// Multiplies two matrices together and returns the resulting matrix.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The product matrix.</returns>
public static Matrix3x2 operator *(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 m;
// First row
m.M11 = value1.M11 * value2.M11 + value1.M12 * value2.M21;
m.M12 = value1.M11 * value2.M12 + value1.M12 * value2.M22;
// Second row
m.M21 = value1.M21 * value2.M11 + value1.M22 * value2.M21;
m.M22 = value1.M21 * value2.M12 + value1.M22 * value2.M22;
// Third row
m.M31 = value1.M31 * value2.M11 + value1.M32 * value2.M21 + value2.M31;
m.M32 = value1.M31 * value2.M12 + value1.M32 * value2.M22 + value2.M32;
return m;
}
/// <summary>
/// Scales all elements in a matrix by the given scalar factor.
/// </summary>
/// <param name="value1">The source matrix.</param>
/// <param name="value2">The scaling value to use.</param>
/// <returns>The resulting matrix.</returns>
public static Matrix3x2 operator *(Matrix3x2 value1, double value2)
{
Matrix3x2 m;
m.M11 = value1.M11 * value2;
m.M12 = value1.M12 * value2;
m.M21 = value1.M21 * value2;
m.M22 = value1.M22 * value2;
m.M31 = value1.M31 * value2;
m.M32 = value1.M32 * value2;
return m;
}
/// <summary>
/// Returns a boolean indicating whether the given matrices are equal.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>True if the matrices are equal; False otherwise.</returns>
public static bool operator ==(Matrix3x2 value1, Matrix3x2 value2) =>
(
value1.M11 == value2.M11
&& value1.M22 == value2.M22
&& // Check diagonal element first for early out.
value1.M12 == value2.M12
&& value1.M21 == value2.M21
&& value1.M31 == value2.M31
&& value1.M32 == value2.M32
);
/// <summary>
/// Returns a boolean indicating whether the given matrices are not equal.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>True if the matrices are not equal; False if they are equal.</returns>
public static bool operator !=(Matrix3x2 value1, Matrix3x2 value2) =>
(
value1.M11 != value2.M11
|| value1.M12 != value2.M12
|| value1.M21 != value2.M21
|| value1.M22 != value2.M22
|| value1.M31 != value2.M31
|| value1.M32 != value2.M32
);
/// <summary>
/// Returns a boolean indicating whether the matrix is equal to the other given matrix.
/// </summary>
/// <param name="other">The other matrix to test equality against.</param>
/// <returns>True if this matrix is equal to other; False otherwise.</returns>
public bool Equals(Matrix3x2 other) =>
(
M11 == other.M11
&& M22 == other.M22
&& // Check diagonal element first for early out.
M12 == other.M12
&& M21 == other.M21
&& M31 == other.M31
&& M32 == other.M32
);
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this matrix instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this matrix; False otherwise.</returns>
public override bool Equals(object? obj)
{
if (obj is Matrix3x2 x2)
{
return Equals(x2);
}
return false;
}
/// <summary>
/// Returns a String representing this matrix instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
CultureInfo ci = CultureInfo.CurrentCulture;
return String.Format(
ci,
"{{ {{M11:{0} M12:{1}}} {{M21:{2} M22:{3}}} {{M31:{4} M32:{5}}} }}",
M11.ToString(ci),
M12.ToString(ci),
M21.ToString(ci),
M22.ToString(ci),
M31.ToString(ci),
M32.ToString(ci)
);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode() =>
M11.GetHashCode()
+ M12.GetHashCode()
+ M21.GetHashCode()
+ M22.GetHashCode()
+ M31.GetHashCode()
+ M32.GetHashCode();
}
File diff suppressed because it is too large Load Diff
+284
View File
@@ -0,0 +1,284 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Runtime.CompilerServices;
namespace Speckle.DoubleNumerics;
/// <summary>
/// A structure encapsulating a 3D Plane
/// </summary>
public struct Plane : IEquatable<Plane>
{
/// <summary>
/// The normal vector of the Plane.
/// </summary>
public Vector3 Normal;
/// <summary>
/// The distance of the Plane along its normal from the origin.
/// </summary>
public double D;
/// <summary>
/// Constructs a Plane from the X, Y, and Z components of its normal, and its distance from the origin on that normal.
/// </summary>
/// <param name="x">The X-component of the normal.</param>
/// <param name="y">The Y-component of the normal.</param>
/// <param name="z">The Z-component of the normal.</param>
/// <param name="d">The distance of the Plane along its normal from the origin.</param>
public Plane(double x, double y, double z, double d)
{
Normal = new Vector3(x, y, z);
D = d;
}
/// <summary>
/// Constructs a Plane from the given normal and distance along the normal from the origin.
/// </summary>
/// <param name="normal">The Plane's normal vector.</param>
/// <param name="d">The Plane's distance from the origin along its normal vector.</param>
public Plane(Vector3 normal, double d)
{
Normal = normal;
D = d;
}
/// <summary>
/// Constructs a Plane from the given Vector4.
/// </summary>
/// <param name="value">A vector whose first 3 elements describe the normal vector,
/// and whose W component defines the distance along that normal from the origin.</param>
public Plane(Vector4 value)
{
Normal = new Vector3(value.X, value.Y, value.Z);
D = value.W;
}
/// <summary>
/// Creates a Plane that contains the three given points.
/// </summary>
/// <param name="point1">The first point defining the Plane.</param>
/// <param name="point2">The second point defining the Plane.</param>
/// <param name="point3">The third point defining the Plane.</param>
/// <returns>The Plane containing the three points.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane CreateFromVertices(Vector3 point1, Vector3 point2, Vector3 point3)
{
double ax = point2.X - point1.X;
double ay = point2.Y - point1.Y;
double az = point2.Z - point1.Z;
double bx = point3.X - point1.X;
double by = point3.Y - point1.Y;
double bz = point3.Z - point1.Z;
// N=Cross(a,b)
double nx = ay * bz - az * by;
double ny = az * bx - ax * bz;
double nz = ax * by - ay * bx;
// Normalize(N)
double ls = nx * nx + ny * ny + nz * nz;
double invNorm = 1.0 / Math.Sqrt(ls);
Vector3 normal = new(nx * invNorm, ny * invNorm, nz * invNorm);
return new Plane(normal, -(normal.X * point1.X + normal.Y * point1.Y + normal.Z * point1.Z));
}
/// <summary>
/// Creates a new Plane whose normal vector is the source Plane's normal vector normalized.
/// </summary>
/// <param name="value">The source Plane.</param>
/// <returns>The normalized Plane.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane Normalize(Plane value)
{
const double FLT_EPSILON = 1.192092896e-07; // smallest such that 1.0+FLT_EPSILON != 1.0
double f = value.Normal.X * value.Normal.X + value.Normal.Y * value.Normal.Y + value.Normal.Z * value.Normal.Z;
if (Math.Abs(f - 1.0) < FLT_EPSILON)
{
return value; // It already normalized, so we don't need to further process.
}
double fInv = 1.0 / Math.Sqrt(f);
return new Plane(value.Normal.X * fInv, value.Normal.Y * fInv, value.Normal.Z * fInv, value.D * fInv);
}
/// <summary>
/// Transforms a normalized Plane by a Matrix.
/// </summary>
/// <param name="plane"> The normalized Plane to transform.
/// This Plane must already be normalized, so that its Normal vector is of unit length, before this method is called.</param>
/// <param name="matrix">The transformation matrix to apply to the Plane.</param>
/// <returns>The transformed Plane.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane Transform(Plane plane, Matrix4x4 matrix)
{
Matrix4x4 m;
Matrix4x4.Invert(matrix, out m);
double x = plane.Normal.X,
y = plane.Normal.Y,
z = plane.Normal.Z,
w = plane.D;
return new Plane(
x * m.M11 + y * m.M12 + z * m.M13 + w * m.M14,
x * m.M21 + y * m.M22 + z * m.M23 + w * m.M24,
x * m.M31 + y * m.M32 + z * m.M33 + w * m.M34,
x * m.M41 + y * m.M42 + z * m.M43 + w * m.M44
);
}
/// <summary>
/// Transforms a normalized Plane by a Quaternion rotation.
/// </summary>
/// <param name="plane"> The normalized Plane to transform.
/// This Plane must already be normalized, so that its Normal vector is of unit length, before this method is called.</param>
/// <param name="rotation">The Quaternion rotation to apply to the Plane.</param>
/// <returns>A new Plane that results from applying the rotation.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane Transform(Plane plane, Quaternion rotation)
{
// Compute rotation matrix.
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wx2 = rotation.W * x2;
double wy2 = rotation.W * y2;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double xz2 = rotation.X * z2;
double yy2 = rotation.Y * y2;
double yz2 = rotation.Y * z2;
double zz2 = rotation.Z * z2;
double m11 = 1.0 - yy2 - zz2;
double m21 = xy2 - wz2;
double m31 = xz2 + wy2;
double m12 = xy2 + wz2;
double m22 = 1.0 - xx2 - zz2;
double m32 = yz2 - wx2;
double m13 = xz2 - wy2;
double m23 = yz2 + wx2;
double m33 = 1.0 - xx2 - yy2;
double x = plane.Normal.X,
y = plane.Normal.Y,
z = plane.Normal.Z;
return new Plane(x * m11 + y * m21 + z * m31, x * m12 + y * m22 + z * m32, x * m13 + y * m23 + z * m33, plane.D);
}
/// <summary>
/// Calculates the dot product of a Plane and Vector4.
/// </summary>
/// <param name="plane">The Plane.</param>
/// <param name="value">The Vector4.</param>
/// <returns>The dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Plane plane, Vector4 value) =>
plane.Normal.X * value.X + plane.Normal.Y * value.Y + plane.Normal.Z * value.Z + plane.D * value.W;
/// <summary>
/// Returns the dot product of a specified Vector3 and the normal vector of this Plane plus the distance (D) value of the Plane.
/// </summary>
/// <param name="plane">The plane.</param>
/// <param name="value">The Vector3.</param>
/// <returns>The resulting value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DotCoordinate(Plane plane, Vector3 value) =>
plane.Normal.X * value.X + plane.Normal.Y * value.Y + plane.Normal.Z * value.Z + plane.D;
/// <summary>
/// Returns the dot product of a specified Vector3 and the Normal vector of this Plane.
/// </summary>
/// <param name="plane">The plane.</param>
/// <param name="value">The Vector3.</param>
/// <returns>The resulting dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DotNormal(Plane plane, Vector3 value) =>
plane.Normal.X * value.X + plane.Normal.Y * value.Y + plane.Normal.Z * value.Z;
/// <summary>
/// Returns a boolean indicating whether the two given Planes are equal.
/// </summary>
/// <param name="value1">The first Plane to compare.</param>
/// <param name="value2">The second Plane to compare.</param>
/// <returns>True if the Planes are equal; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Plane value1, Plane value2) =>
(
value1.Normal.X == value2.Normal.X
&& value1.Normal.Y == value2.Normal.Y
&& value1.Normal.Z == value2.Normal.Z
&& value1.D == value2.D
);
/// <summary>
/// Returns a boolean indicating whether the two given Planes are not equal.
/// </summary>
/// <param name="value1">The first Plane to compare.</param>
/// <param name="value2">The second Plane to compare.</param>
/// <returns>True if the Planes are not equal; False if they are equal.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Plane value1, Plane value2) =>
(
value1.Normal.X != value2.Normal.X
|| value1.Normal.Y != value2.Normal.Y
|| value1.Normal.Z != value2.Normal.Z
|| value1.D != value2.D
);
/// <summary>
/// Returns a boolean indicating whether the given Plane is equal to this Plane instance.
/// </summary>
/// <param name="other">The Plane to compare this instance to.</param>
/// <returns>True if the other Plane is equal to this instance; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Plane other) =>
(Normal.X == other.Normal.X && Normal.Y == other.Normal.Y && Normal.Z == other.Normal.Z && D == other.D);
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this Plane instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this Plane; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object? obj)
{
if (obj is Plane plane)
{
return Equals(plane);
}
return false;
}
/// <summary>
/// Returns a String representing this Plane instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
CultureInfo ci = CultureInfo.CurrentCulture;
return String.Format(ci, "{{Normal:{0} D:{1}}}", Normal.ToString(), D.ToString(ci));
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode() => Normal.GetHashCode() + D.GetHashCode();
}
+781
View File
@@ -0,0 +1,781 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
namespace Speckle.DoubleNumerics;
/// <summary>
/// A structure encapsulating a four-dimensional vector (x,y,z,w),
/// which is used to efficiently rotate an object about the (x,y,z) vector by the angle theta, where w = cos(theta/2).
/// </summary>
public struct Quaternion : IEquatable<Quaternion>
{
/// <summary>
/// Specifies the X-value of the vector component of the Quaternion.
/// </summary>
public double X;
/// <summary>
/// Specifies the Y-value of the vector component of the Quaternion.
/// </summary>
public double Y;
/// <summary>
/// Specifies the Z-value of the vector component of the Quaternion.
/// </summary>
public double Z;
/// <summary>
/// Specifies the rotation component of the Quaternion.
/// </summary>
public double W;
/// <summary>
/// Returns a Quaternion representing no rotation.
/// </summary>
public static Quaternion Identity => new(0, 0, 0, 1);
/// <summary>
/// Returns whether the Quaternion is the identity Quaternion.
/// </summary>
public bool IsIdentity => X == 0 && Y == 0 && Z == 0 && W == 1;
/// <summary>
/// Constructs a Quaternion from the given components.
/// </summary>
/// <param name="x">The X component of the Quaternion.</param>
/// <param name="y">The Y component of the Quaternion.</param>
/// <param name="z">The Z component of the Quaternion.</param>
/// <param name="w">The W component of the Quaternion.</param>
public Quaternion(double x, double y, double z, double w)
{
X = x;
Y = y;
Z = z;
W = w;
}
/// <summary>
/// Constructs a Quaternion from the given vector and rotation parts.
/// </summary>
/// <param name="vectorPart">The vector part of the Quaternion.</param>
/// <param name="scalarPart">The rotation part of the Quaternion.</param>
public Quaternion(Vector3 vectorPart, double scalarPart)
{
X = vectorPart.X;
Y = vectorPart.Y;
Z = vectorPart.Z;
W = scalarPart;
}
/// <summary>
/// Calculates the length of the Quaternion.
/// </summary>
/// <returns>The computed length of the Quaternion.</returns>
public double Length()
{
double ls = X * X + Y * Y + Z * Z + W * W;
return Math.Sqrt(ls);
}
/// <summary>
/// Calculates the length squared of the Quaternion. This operation is cheaper than Length().
/// </summary>
/// <returns>The length squared of the Quaternion.</returns>
public double LengthSquared() => X * X + Y * Y + Z * Z + W * W;
/// <summary>
/// Divides each component of the Quaternion by the length of the Quaternion.
/// </summary>
/// <param name="value">The source Quaternion.</param>
/// <returns>The normalized Quaternion.</returns>
public static Quaternion Normalize(Quaternion value)
{
Quaternion ans;
double ls = value.X * value.X + value.Y * value.Y + value.Z * value.Z + value.W * value.W;
double invNorm = 1.0 / Math.Sqrt(ls);
ans.X = value.X * invNorm;
ans.Y = value.Y * invNorm;
ans.Z = value.Z * invNorm;
ans.W = value.W * invNorm;
return ans;
}
/// <summary>
/// Creates the conjugate of a specified Quaternion.
/// </summary>
/// <param name="value">The Quaternion of which to return the conjugate.</param>
/// <returns>A new Quaternion that is the conjugate of the specified one.</returns>
public static Quaternion Conjugate(Quaternion value)
{
Quaternion ans;
ans.X = -value.X;
ans.Y = -value.Y;
ans.Z = -value.Z;
ans.W = value.W;
return ans;
}
/// <summary>
/// Returns the inverse of a Quaternion.
/// </summary>
/// <param name="value">The source Quaternion.</param>
/// <returns>The inverted Quaternion.</returns>
public static Quaternion Inverse(Quaternion value)
{
// -1 ( a -v )
// q = ( ------------- ------------- )
// ( a^2 + |v|^2 , a^2 + |v|^2 )
Quaternion ans;
double ls = value.X * value.X + value.Y * value.Y + value.Z * value.Z + value.W * value.W;
double invNorm = 1.0 / ls;
ans.X = -value.X * invNorm;
ans.Y = -value.Y * invNorm;
ans.Z = -value.Z * invNorm;
ans.W = value.W * invNorm;
return ans;
}
/// <summary>
/// Creates a Quaternion from a normalized vector axis and an angle to rotate about the vector.
/// </summary>
/// <param name="axis">The unit vector to rotate around.
/// This vector must be normalized before calling this function or the resulting Quaternion will be incorrect.</param>
/// <param name="angle">The angle, in radians, to rotate around the vector.</param>
/// <returns>The created Quaternion.</returns>
public static Quaternion CreateFromAxisAngle(Vector3 axis, double angle)
{
Quaternion ans;
double halfAngle = angle * 0.5;
double s = Math.Sin(halfAngle);
double c = Math.Cos(halfAngle);
ans.X = axis.X * s;
ans.Y = axis.Y * s;
ans.Z = axis.Z * s;
ans.W = c;
return ans;
}
/// <summary>
/// Creates a new Quaternion from the given yaw, pitch, and roll, in radians.
/// </summary>
/// <param name="yaw">The yaw angle, in radians, around the Y-axis.</param>
/// <param name="pitch">The pitch angle, in radians, around the X-axis.</param>
/// <param name="roll">The roll angle, in radians, around the Z-axis.</param>
/// <returns></returns>
public static Quaternion CreateFromYawPitchRoll(double yaw, double pitch, double roll)
{
// Roll first, about axis the object is facing, then
// pitch upward, then yaw to face into the new heading
double sr,
cr,
sp,
cp,
sy,
cy;
double halfRoll = roll * 0.5;
sr = Math.Sin(halfRoll);
cr = Math.Cos(halfRoll);
double halfPitch = pitch * 0.5;
sp = Math.Sin(halfPitch);
cp = Math.Cos(halfPitch);
double halfYaw = yaw * 0.5;
sy = Math.Sin(halfYaw);
cy = Math.Cos(halfYaw);
Quaternion result;
result.X = cy * sp * cr + sy * cp * sr;
result.Y = sy * cp * cr - cy * sp * sr;
result.Z = cy * cp * sr - sy * sp * cr;
result.W = cy * cp * cr + sy * sp * sr;
return result;
}
/// <summary>
/// Creates a Quaternion from the given rotation matrix.
/// </summary>
/// <param name="matrix">The rotation matrix.</param>
/// <returns>The created Quaternion.</returns>
public static Quaternion CreateFromRotationMatrix(Matrix4x4 matrix)
{
double trace = matrix.M11 + matrix.M22 + matrix.M33;
Quaternion q = new();
if (trace > 0.0)
{
double s = Math.Sqrt(trace + 1.0);
q.W = s * 0.5;
s = 0.5 / s;
q.X = (matrix.M23 - matrix.M32) * s;
q.Y = (matrix.M31 - matrix.M13) * s;
q.Z = (matrix.M12 - matrix.M21) * s;
}
else
{
if (matrix.M11 >= matrix.M22 && matrix.M11 >= matrix.M33)
{
double s = Math.Sqrt(1.0 + matrix.M11 - matrix.M22 - matrix.M33);
double invS = 0.5 / s;
q.X = 0.5 * s;
q.Y = (matrix.M12 + matrix.M21) * invS;
q.Z = (matrix.M13 + matrix.M31) * invS;
q.W = (matrix.M23 - matrix.M32) * invS;
}
else if (matrix.M22 > matrix.M33)
{
double s = Math.Sqrt(1.0 + matrix.M22 - matrix.M11 - matrix.M33);
double invS = 0.5 / s;
q.X = (matrix.M21 + matrix.M12) * invS;
q.Y = 0.5 * s;
q.Z = (matrix.M32 + matrix.M23) * invS;
q.W = (matrix.M31 - matrix.M13) * invS;
}
else
{
double s = Math.Sqrt(1.0 + matrix.M33 - matrix.M11 - matrix.M22);
double invS = 0.5 / s;
q.X = (matrix.M31 + matrix.M13) * invS;
q.Y = (matrix.M32 + matrix.M23) * invS;
q.Z = 0.5 * s;
q.W = (matrix.M12 - matrix.M21) * invS;
}
}
return q;
}
/// <summary>
/// Calculates the dot product of two Quaternions.
/// </summary>
/// <param name="quaternion1">The first source Quaternion.</param>
/// <param name="quaternion2">The second source Quaternion.</param>
/// <returns>The dot product of the Quaternions.</returns>
public static double Dot(Quaternion quaternion1, Quaternion quaternion2) =>
quaternion1.X * quaternion2.X
+ quaternion1.Y * quaternion2.Y
+ quaternion1.Z * quaternion2.Z
+ quaternion1.W * quaternion2.W;
/// <summary>
/// Interpolates between two quaternions, using spherical linear interpolation.
/// </summary>
/// <param name="quaternion1">The first source Quaternion.</param>
/// <param name="quaternion2">The second source Quaternion.</param>
/// <param name="amount">The relative weight of the second source Quaternion in the interpolation.</param>
/// <returns>The interpolated Quaternion.</returns>
public static Quaternion Slerp(Quaternion quaternion1, Quaternion quaternion2, double amount)
{
const double epsilon = 1e-6;
double t = amount;
double cosOmega =
quaternion1.X * quaternion2.X
+ quaternion1.Y * quaternion2.Y
+ quaternion1.Z * quaternion2.Z
+ quaternion1.W * quaternion2.W;
bool flip = false;
if (cosOmega < 0.0)
{
flip = true;
cosOmega = -cosOmega;
}
double s1,
s2;
if (cosOmega > (1.0 - epsilon))
{
// Too close, do straight linear interpolation.
s1 = 1.0 - t;
s2 = (flip) ? -t : t;
}
else
{
double omega = Math.Acos(cosOmega);
double invSinOmega = 1 / Math.Sin(omega);
s1 = Math.Sin((1.0 - t) * omega) * invSinOmega;
s2 = (flip) ? -Math.Sin(t * omega) * invSinOmega : Math.Sin(t * omega) * invSinOmega;
}
Quaternion ans;
ans.X = s1 * quaternion1.X + s2 * quaternion2.X;
ans.Y = s1 * quaternion1.Y + s2 * quaternion2.Y;
ans.Z = s1 * quaternion1.Z + s2 * quaternion2.Z;
ans.W = s1 * quaternion1.W + s2 * quaternion2.W;
return ans;
}
/// <summary>
/// Linearly interpolates between two quaternions.
/// </summary>
/// <param name="quaternion1">The first source Quaternion.</param>
/// <param name="quaternion2">The second source Quaternion.</param>
/// <param name="amount">The relative weight of the second source Quaternion in the interpolation.</param>
/// <returns>The interpolated Quaternion.</returns>
public static Quaternion Lerp(Quaternion quaternion1, Quaternion quaternion2, double amount)
{
double t = amount;
double t1 = 1.0 - t;
Quaternion r = new();
double dot =
quaternion1.X * quaternion2.X
+ quaternion1.Y * quaternion2.Y
+ quaternion1.Z * quaternion2.Z
+ quaternion1.W * quaternion2.W;
if (dot >= 0.0)
{
r.X = t1 * quaternion1.X + t * quaternion2.X;
r.Y = t1 * quaternion1.Y + t * quaternion2.Y;
r.Z = t1 * quaternion1.Z + t * quaternion2.Z;
r.W = t1 * quaternion1.W + t * quaternion2.W;
}
else
{
r.X = t1 * quaternion1.X - t * quaternion2.X;
r.Y = t1 * quaternion1.Y - t * quaternion2.Y;
r.Z = t1 * quaternion1.Z - t * quaternion2.Z;
r.W = t1 * quaternion1.W - t * quaternion2.W;
}
// Normalize it.
double ls = r.X * r.X + r.Y * r.Y + r.Z * r.Z + r.W * r.W;
double invNorm = 1.0 / Math.Sqrt(ls);
r.X *= invNorm;
r.Y *= invNorm;
r.Z *= invNorm;
r.W *= invNorm;
return r;
}
/// <summary>
/// Concatenates two Quaternions; the result represents the value1 rotation followed by the value2 rotation.
/// </summary>
/// <param name="value1">The first Quaternion rotation in the series.</param>
/// <param name="value2">The second Quaternion rotation in the series.</param>
/// <returns>A new Quaternion representing the concatenation of the value1 rotation followed by the value2 rotation.</returns>
public static Quaternion Concatenate(Quaternion value1, Quaternion value2)
{
Quaternion ans;
// Concatenate rotation is actually q2 * q1 instead of q1 * q2.
// So that's why value2 goes q1 and value1 goes q2.
double q1x = value2.X;
double q1y = value2.Y;
double q1z = value2.Z;
double q1w = value2.W;
double q2x = value1.X;
double q2y = value1.Y;
double q2z = value1.Z;
double q2w = value1.W;
// cross(av, bv)
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;
return ans;
}
/// <summary>
/// Flips the sign of each component of the quaternion.
/// </summary>
/// <param name="value">The source Quaternion.</param>
/// <returns>The negated Quaternion.</returns>
public static Quaternion Negate(Quaternion value)
{
Quaternion ans;
ans.X = -value.X;
ans.Y = -value.Y;
ans.Z = -value.Z;
ans.W = -value.W;
return ans;
}
/// <summary>
/// Adds two Quaternions element-by-element.
/// </summary>
/// <param name="value1">The first source Quaternion.</param>
/// <param name="value2">The second source Quaternion.</param>
/// <returns>The result of adding the Quaternions.</returns>
public static Quaternion Add(Quaternion value1, Quaternion value2)
{
Quaternion ans;
ans.X = value1.X + value2.X;
ans.Y = value1.Y + value2.Y;
ans.Z = value1.Z + value2.Z;
ans.W = value1.W + value2.W;
return ans;
}
/// <summary>
/// Subtracts one Quaternion from another.
/// </summary>
/// <param name="value1">The first source Quaternion.</param>
/// <param name="value2">The second Quaternion, to be subtracted from the first.</param>
/// <returns>The result of the subtraction.</returns>
public static Quaternion Subtract(Quaternion value1, Quaternion value2)
{
Quaternion ans;
ans.X = value1.X - value2.X;
ans.Y = value1.Y - value2.Y;
ans.Z = value1.Z - value2.Z;
ans.W = value1.W - value2.W;
return ans;
}
/// <summary>
/// Multiplies two Quaternions together.
/// </summary>
/// <param name="value1">The Quaternion on the left side of the multiplication.</param>
/// <param name="value2">The Quaternion on the right side of the multiplication.</param>
/// <returns>The result of the multiplication.</returns>
public static Quaternion Multiply(Quaternion value1, Quaternion value2)
{
Quaternion ans;
double q1x = value1.X;
double q1y = value1.Y;
double q1z = value1.Z;
double q1w = value1.W;
double q2x = value2.X;
double q2y = value2.Y;
double q2z = value2.Z;
double q2w = value2.W;
// cross(av, bv)
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;
return ans;
}
/// <summary>
/// Multiplies a Quaternion by a scalar value.
/// </summary>
/// <param name="value1">The source Quaternion.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the multiplication.</returns>
public static Quaternion Multiply(Quaternion value1, double value2)
{
Quaternion ans;
ans.X = value1.X * value2;
ans.Y = value1.Y * value2;
ans.Z = value1.Z * value2;
ans.W = value1.W * value2;
return ans;
}
/// <summary>
/// Divides a Quaternion by another Quaternion.
/// </summary>
/// <param name="value1">The source Quaternion.</param>
/// <param name="value2">The divisor.</param>
/// <returns>The result of the division.</returns>
public static Quaternion Divide(Quaternion value1, Quaternion value2)
{
Quaternion ans;
double q1x = value1.X;
double q1y = value1.Y;
double q1z = value1.Z;
double q1w = value1.W;
//-------------------------------------
// Inverse part.
double ls = value2.X * value2.X + value2.Y * value2.Y + value2.Z * value2.Z + value2.W * value2.W;
double invNorm = 1.0 / ls;
double q2x = -value2.X * invNorm;
double q2y = -value2.Y * invNorm;
double q2z = -value2.Z * invNorm;
double q2w = value2.W * invNorm;
//-------------------------------------
// Multiply part.
// cross(av, bv)
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;
return ans;
}
/// <summary>
/// Flips the sign of each component of the quaternion.
/// </summary>
/// <param name="value">The source Quaternion.</param>
/// <returns>The negated Quaternion.</returns>
public static Quaternion operator -(Quaternion value)
{
Quaternion ans;
ans.X = -value.X;
ans.Y = -value.Y;
ans.Z = -value.Z;
ans.W = -value.W;
return ans;
}
/// <summary>
/// Adds two Quaternions element-by-element.
/// </summary>
/// <param name="value1">The first source Quaternion.</param>
/// <param name="value2">The second source Quaternion.</param>
/// <returns>The result of adding the Quaternions.</returns>
public static Quaternion operator +(Quaternion value1, Quaternion value2)
{
Quaternion ans;
ans.X = value1.X + value2.X;
ans.Y = value1.Y + value2.Y;
ans.Z = value1.Z + value2.Z;
ans.W = value1.W + value2.W;
return ans;
}
/// <summary>
/// Subtracts one Quaternion from another.
/// </summary>
/// <param name="value1">The first source Quaternion.</param>
/// <param name="value2">The second Quaternion, to be subtracted from the first.</param>
/// <returns>The result of the subtraction.</returns>
public static Quaternion operator -(Quaternion value1, Quaternion value2)
{
Quaternion ans;
ans.X = value1.X - value2.X;
ans.Y = value1.Y - value2.Y;
ans.Z = value1.Z - value2.Z;
ans.W = value1.W - value2.W;
return ans;
}
/// <summary>
/// Multiplies two Quaternions together.
/// </summary>
/// <param name="value1">The Quaternion on the left side of the multiplication.</param>
/// <param name="value2">The Quaternion on the right side of the multiplication.</param>
/// <returns>The result of the multiplication.</returns>
public static Quaternion operator *(Quaternion value1, Quaternion value2)
{
Quaternion ans;
double q1x = value1.X;
double q1y = value1.Y;
double q1z = value1.Z;
double q1w = value1.W;
double q2x = value2.X;
double q2y = value2.Y;
double q2z = value2.Z;
double q2w = value2.W;
// cross(av, bv)
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;
return ans;
}
/// <summary>
/// Multiplies a Quaternion by a scalar value.
/// </summary>
/// <param name="value1">The source Quaternion.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the multiplication.</returns>
public static Quaternion operator *(Quaternion value1, double value2)
{
Quaternion ans;
ans.X = value1.X * value2;
ans.Y = value1.Y * value2;
ans.Z = value1.Z * value2;
ans.W = value1.W * value2;
return ans;
}
/// <summary>
/// Divides a Quaternion by another Quaternion.
/// </summary>
/// <param name="value1">The source Quaternion.</param>
/// <param name="value2">The divisor.</param>
/// <returns>The result of the division.</returns>
public static Quaternion operator /(Quaternion value1, Quaternion value2)
{
Quaternion ans;
double q1x = value1.X;
double q1y = value1.Y;
double q1z = value1.Z;
double q1w = value1.W;
//-------------------------------------
// Inverse part.
double ls = value2.X * value2.X + value2.Y * value2.Y + value2.Z * value2.Z + value2.W * value2.W;
double invNorm = 1.0 / ls;
double q2x = -value2.X * invNorm;
double q2y = -value2.Y * invNorm;
double q2z = -value2.Z * invNorm;
double q2w = value2.W * invNorm;
//-------------------------------------
// Multiply part.
// cross(av, bv)
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;
return ans;
}
/// <summary>
/// Returns a boolean indicating whether the two given Quaternions are equal.
/// </summary>
/// <param name="value1">The first Quaternion to compare.</param>
/// <param name="value2">The second Quaternion to compare.</param>
/// <returns>True if the Quaternions are equal; False otherwise.</returns>
public static bool operator ==(Quaternion value1, Quaternion value2) =>
(value1.X == value2.X && value1.Y == value2.Y && value1.Z == value2.Z && value1.W == value2.W);
/// <summary>
/// Returns a boolean indicating whether the two given Quaternions are not equal.
/// </summary>
/// <param name="value1">The first Quaternion to compare.</param>
/// <param name="value2">The second Quaternion to compare.</param>
/// <returns>True if the Quaternions are not equal; False if they are equal.</returns>
public static bool operator !=(Quaternion value1, Quaternion value2) =>
(value1.X != value2.X || value1.Y != value2.Y || value1.Z != value2.Z || value1.W != value2.W);
/// <summary>
/// Returns a boolean indicating whether the given Quaternion is equal to this Quaternion instance.
/// </summary>
/// <param name="other">The Quaternion to compare this instance to.</param>
/// <returns>True if the other Quaternion is equal to this instance; False otherwise.</returns>
public bool Equals(Quaternion other) => (X == other.X && Y == other.Y && Z == other.Z && W == other.W);
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this Quaternion instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this Quaternion; False otherwise.</returns>
public override bool Equals(object? obj)
{
if (obj is Quaternion quaternion)
{
return Equals(quaternion);
}
return false;
}
/// <summary>
/// Returns a String representing this Quaternion instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
CultureInfo ci = CultureInfo.CurrentCulture;
return String.Format(
ci,
"{{X:{0} Y:{1} Z:{2} W:{3}}}",
X.ToString(ci),
Y.ToString(ci),
Z.ToString(ci),
W.ToString(ci)
);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode() => X.GetHashCode() + Y.GetHashCode() + Z.GetHashCode() + W.GetHashCode();
}
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
<PackageId>Speckle.DoubleNumerics</PackageId>
<PackageVersion>4.0.0</PackageVersion>
<Description>Double version of System.Numerics vector libraries</Description>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageTags>numerics vector matrix</PackageTags>
<LicenseUrl>https://opensource.org/licenses/MIT</LicenseUrl>
<IsPackable>true</IsPackable>
</PropertyGroup>
</Project>
@@ -8,11 +8,10 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace System.DoubleNumerics {
using System.Reflection;
/// <summary>
using System.Reflection;
namespace Speckle.DoubleNumerics {
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
@@ -39,7 +38,7 @@ namespace System.DoubleNumerics {
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("System.DoubleNumerics.Strings", typeof(Strings).GetTypeInfo().Assembly);
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Speckle.DoubleNumerics.Strings", typeof(Strings).GetTypeInfo().Assembly);
resourceMan = temp;
}
return resourceMan;
+359
View File
@@ -0,0 +1,359 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
namespace Speckle.DoubleNumerics;
/// <summary>
/// A structure encapsulating two single precision floating point values and provides hardware accelerated methods.
/// </summary>
public partial struct Vector2 : IEquatable<Vector2>, IFormattable
{
#region Public Static Properties
/// <summary>
/// Returns the vector (0,0).
/// </summary>
public static Vector2 Zero => new();
/// <summary>
/// Returns the vector (1,1).
/// </summary>
public static Vector2 One => new(1.0, 1.0);
/// <summary>
/// Returns the vector (1,0).
/// </summary>
public static Vector2 UnitX => new(1.0, 0.0);
/// <summary>
/// Returns the vector (0,1).
/// </summary>
public static Vector2 UnitY => new(0.0, 1.0);
#endregion Public Static Properties
#region Public instance methods
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
int hash = X.GetHashCode();
hash = HashHelpers.Combine(hash, Y.GetHashCode());
return hash;
}
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this Vector2 instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this Vector2; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object? obj)
{
if (!(obj is Vector2 vector2))
return false;
return Equals(vector2);
}
/// <summary>
/// Returns a String representing this Vector2 instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString() => ToString("G", CultureInfo.CurrentCulture);
/// <summary>
/// Returns a String representing this Vector2 instance, using the specified format to format individual elements.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string format) => ToString(format, CultureInfo.CurrentCulture);
/// <summary>
/// Returns a String representing this Vector2 instance, using the specified format to format individual elements
/// and the given IFormatProvider.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <param name="formatProvider">The format provider to use when formatting elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string? format, IFormatProvider? formatProvider)
{
StringBuilder sb = new();
string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
sb.Append('<');
sb.Append(X.ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(Y.ToString(format, formatProvider));
sb.Append('>');
return sb.ToString();
}
/// <summary>
/// Returns the length of the vector.
/// </summary>
/// <returns>The vector's length.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Length()
{
double ls = X * X + Y * Y;
return Math.Sqrt(ls);
}
/// <summary>
/// Returns the length of the vector squared. This operation is cheaper than Length().
/// </summary>
/// <returns>The vector's length squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double LengthSquared() => X * X + Y * Y;
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the Euclidean distance between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Distance(Vector2 value1, Vector2 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double ls = dx * dx + dy * dy;
return Math.Sqrt(ls);
}
/// <summary>
/// Returns the Euclidean distance squared between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DistanceSquared(Vector2 value1, Vector2 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
return dx * dx + dy * dy;
}
/// <summary>
/// Returns a vector with the same direction as the given vector, but with a length of 1.
/// </summary>
/// <param name="value">The vector to normalize.</param>
/// <returns>The normalized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Normalize(Vector2 value)
{
double ls = value.X * value.X + value.Y * value.Y;
double invNorm = 1.0 / Math.Sqrt(ls);
return new Vector2(value.X * invNorm, value.Y * invNorm);
}
/// <summary>
/// Returns the reflection of a vector off a surface that has the specified normal.
/// </summary>
/// <param name="vector">The source vector.</param>
/// <param name="normal">The normal of the surface being reflected off.</param>
/// <returns>The reflected vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Reflect(Vector2 vector, Vector2 normal)
{
double dot = vector.X * normal.X + vector.Y * normal.Y;
return new Vector2(vector.X - 2.0 * dot * normal.X, vector.Y - 2.0 * dot * normal.Y);
}
/// <summary>
/// Restricts a vector between a min and max value.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max)
{
// This compare order is very important!!!
// We must follow HLSL behavior in the case user specified min value is bigger than max value.
double x = value1.X;
x = (x > max.X) ? max.X : x;
x = (x < min.X) ? min.X : x;
double y = value1.Y;
y = (y > max.Y) ? max.Y : y;
y = (y < min.Y) ? min.Y : y;
return new Vector2(x, y);
}
/// <summary>
/// Linearly interpolates between two vectors based on the given weighting.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <param name="amount">Value between 0 and 1 indicating the weight of the second source vector.</param>
/// <returns>The interpolated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Lerp(Vector2 value1, Vector2 value2, double amount) =>
new(value1.X + (value2.X - value1.X) * amount, value1.Y + (value2.Y - value1.Y) * amount);
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="position">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Transform(Vector2 position, Matrix3x2 matrix) =>
new(
position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M31,
position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M32
);
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="position">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Transform(Vector2 position, Matrix4x4 matrix) =>
new(
position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M41,
position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M42
);
/// <summary>
/// Transforms a vector normal by the given matrix.
/// </summary>
/// <param name="normal">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 TransformNormal(Vector2 normal, Matrix3x2 matrix) =>
new(normal.X * matrix.M11 + normal.Y * matrix.M21, normal.X * matrix.M12 + normal.Y * matrix.M22);
/// <summary>
/// Transforms a vector normal by the given matrix.
/// </summary>
/// <param name="normal">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 TransformNormal(Vector2 normal, Matrix4x4 matrix) =>
new(normal.X * matrix.M11 + normal.Y * matrix.M21, normal.X * matrix.M12 + normal.Y * matrix.M22);
/// <summary>
/// Transforms a vector by the given Quaternion rotation value.
/// </summary>
/// <param name="value">The source vector to be rotated.</param>
/// <param name="rotation">The rotation to apply.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Transform(Vector2 value, Quaternion rotation)
{
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double yy2 = rotation.Y * y2;
double zz2 = rotation.Z * z2;
return new Vector2(
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2),
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2)
);
}
#endregion Public Static Methods
#region Public operator methods
// all the below methods should be inlined as they are
// implemented over JIT intrinsics
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Add(Vector2 left, Vector2 right) => left + right;
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Subtract(Vector2 left, Vector2 right) => left - right;
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Multiply(Vector2 left, Vector2 right) => left * right;
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Multiply(Vector2 left, Double right) => left * right;
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Multiply(Double left, Vector2 right) => left * right;
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Divide(Vector2 left, Vector2 right) => left / right;
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="divisor">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Divide(Vector2 left, Double divisor) => left / divisor;
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Negate(Vector2 value) => -value;
#endregion Public operator methods
}
@@ -0,0 +1,236 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
namespace Speckle.DoubleNumerics;
// This file contains the definitions for all of the JIT intrinsic methods and properties that are recognized by the current x64 JIT compiler.
// The implementation defined here is used in any circumstance where the JIT fails to recognize these members as intrinsic.
// The JIT recognizes these methods and properties by name and signature: if either is changed, the JIT will no longer recognize the member.
// Some methods declared here are not strictly intrinsic, but delegate to an intrinsic method. For example, only one overload of CopyTo()
public partial struct Vector2
{
/// <summary>
/// The X component of the vector.
/// </summary>
public Double X;
/// <summary>
/// The Y component of the vector.
/// </summary>
public Double Y;
#region Constructors
/// <summary>
/// Constructs a vector whose elements are all the single specified value.
/// </summary>
/// <param name="value">The element to fill the vector with.</param>
public Vector2(Double value)
: this(value, value) { }
/// <summary>
/// Constructs a vector with the given individual elements.
/// </summary>
/// <param name="x">The X component.</param>
/// <param name="y">The Y component.</param>
public Vector2(Double x, Double y)
{
X = x;
Y = y;
}
#endregion Constructors
#region Public Instance Methods
/// <summary>
/// Copies the contents of the vector into the given array.
/// </summary>
/// <param name="array">The destination array.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Double[] array) => CopyTo(array, 0);
/// <summary>
/// Copies the contents of the vector into the given array, starting from the given index.
/// </summary>
/// <exception cref="ArgumentNullException">If array is null.</exception>
/// <exception cref="RankException">If array is multidimensional.</exception>
/// <exception cref="ArgumentOutOfRangeException">If index is greater than end of the array or index is less than zero.</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array
/// or if there are not enough elements to copy.</exception>
public void CopyTo(Double[]? array, int index)
{
if (array == null)
{
// Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull.
throw new NullReferenceException(Strings.Arg_NullArgumentNullRef);
}
if (index < 0 || index >= array.Length)
{
throw new ArgumentOutOfRangeException(
nameof(index),
String.Format(Strings.Arg_ArgumentOutOfRangeException, index)
);
}
if ((array.Length - index) < 2)
{
throw new ArgumentException(String.Format(Strings.Arg_ElementsInSourceIsGreaterThanDestination, index));
}
array[index] = X;
array[index + 1] = Y;
}
/// <summary>
/// Returns a boolean indicating whether the given Vector2 is equal to this Vector2 instance.
/// </summary>
/// <param name="other">The Vector2 to compare this instance to.</param>
/// <returns>True if the other Vector2 is equal to this instance; False otherwise.</returns>
public bool Equals(Vector2 other) => X == other.X && Y == other.Y;
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the dot product of two vectors.
/// </summary>
/// <param name="value1">The first vector.</param>
/// <param name="value2">The second vector.</param>
/// <returns>The dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Vector2 value1, Vector2 value2) => value1.X * value2.X + value1.Y * value2.Y;
/// <summary>
/// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The minimized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Min(Vector2 value1, Vector2 value2) =>
new((value1.X < value2.X) ? value1.X : value2.X, (value1.Y < value2.Y) ? value1.Y : value2.Y);
/// <summary>
/// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors
/// </summary>
/// <param name="value1">The first source vector</param>
/// <param name="value2">The second source vector</param>
/// <returns>The maximized vector</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Max(Vector2 value1, Vector2 value2) =>
new((value1.X > value2.X) ? value1.X : value2.X, (value1.Y > value2.Y) ? value1.Y : value2.Y);
/// <summary>
/// Returns a vector whose elements are the absolute values of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The absolute value vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Abs(Vector2 value) => new(Math.Abs(value.X), Math.Abs(value.Y));
/// <summary>
/// Returns a vector whose elements are the square root of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The square root vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 SquareRoot(Vector2 value) => new(Math.Sqrt(value.X), Math.Sqrt(value.Y));
#endregion Public Static Methods
#region Public Static Operators
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator +(Vector2 left, Vector2 right) => new(left.X + right.X, left.Y + right.Y);
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator -(Vector2 left, Vector2 right) => new(left.X - right.X, left.Y - right.Y);
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(Vector2 left, Vector2 right) => new(left.X * right.X, left.Y * right.Y);
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(Double left, Vector2 right) => new Vector2(left, left) * right;
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(Vector2 left, Double right) => left * new Vector2(right, right);
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator /(Vector2 left, Vector2 right) => new(left.X / right.X, left.Y / right.Y);
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator /(Vector2 value1, double value2)
{
double invDiv = 1.0 / value2;
return new Vector2(value1.X * invDiv, value1.Y * invDiv);
}
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator -(Vector2 value) => Zero - value;
/// <summary>
/// Returns a boolean indicating whether the two given vectors are equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are equal; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector2 left, Vector2 right) => left.Equals(right);
/// <summary>
/// Returns a boolean indicating whether the two given vectors are not equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are not equal; False if they are equal.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vector2 left, Vector2 right) => !(left == right);
#endregion Public Static Operators
}
+384
View File
@@ -0,0 +1,384 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
namespace Speckle.DoubleNumerics;
/// <summary>
/// A structure encapsulating three single precision floating point values and provides hardware accelerated methods.
/// </summary>
public partial struct Vector3 : IEquatable<Vector3>, IFormattable
{
#region Public Static Properties
/// <summary>
/// Returns the vector (0,0,0).
/// </summary>
public static Vector3 Zero => new();
/// <summary>
/// Returns the vector (1,1,1).
/// </summary>
public static Vector3 One => new(1.0, 1.0, 1.0);
/// <summary>
/// Returns the vector (1,0,0).
/// </summary>
public static Vector3 UnitX => new(1.0, 0.0, 0.0);
/// <summary>
/// Returns the vector (0,1,0).
/// </summary>
public static Vector3 UnitY => new(0.0, 1.0, 0.0);
/// <summary>
/// Returns the vector (0,0,1).
/// </summary>
public static Vector3 UnitZ => new(0.0, 0.0, 1.0);
#endregion Public Static Properties
#region Public Instance Methods
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
int hash = X.GetHashCode();
hash = HashHelpers.Combine(hash, Y.GetHashCode());
hash = HashHelpers.Combine(hash, Z.GetHashCode());
return hash;
}
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this Vector3 instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this Vector3; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object? obj)
{
if (!(obj is Vector3 vector3))
return false;
return Equals(vector3);
}
/// <summary>
/// Returns a String representing this Vector3 instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString() => ToString("G", CultureInfo.CurrentCulture);
/// <summary>
/// Returns a String representing this Vector3 instance, using the specified format to format individual elements.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string format) => ToString(format, CultureInfo.CurrentCulture);
/// <summary>
/// Returns a String representing this Vector3 instance, using the specified format to format individual elements
/// and the given IFormatProvider.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <param name="formatProvider">The format provider to use when formatting elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string? format, IFormatProvider? formatProvider)
{
StringBuilder sb = new();
string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
sb.Append('<');
sb.Append(X.ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(Y.ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(Z.ToString(format, formatProvider));
sb.Append('>');
return sb.ToString();
}
/// <summary>
/// Returns the length of the vector.
/// </summary>
/// <returns>The vector's length.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Length()
{
double ls = X * X + Y * Y + Z * Z;
return Math.Sqrt(ls);
}
/// <summary>
/// Returns the length of the vector squared. This operation is cheaper than Length().
/// </summary>
/// <returns>The vector's length squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double LengthSquared() => X * X + Y * Y + Z * Z;
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the Euclidean distance between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Distance(Vector3 value1, Vector3 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double dz = value1.Z - value2.Z;
double ls = dx * dx + dy * dy + dz * dz;
return Math.Sqrt(ls);
}
/// <summary>
/// Returns the Euclidean distance squared between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DistanceSquared(Vector3 value1, Vector3 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double dz = value1.Z - value2.Z;
return dx * dx + dy * dy + dz * dz;
}
/// <summary>
/// Returns a vector with the same direction as the given vector, but with a length of 1.
/// </summary>
/// <param name="value">The vector to normalize.</param>
/// <returns>The normalized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Normalize(Vector3 value)
{
double ls = value.X * value.X + value.Y * value.Y + value.Z * value.Z;
double length = Math.Sqrt(ls);
return new Vector3(value.X / length, value.Y / length, value.Z / length);
}
/// <summary>
/// Computes the cross product of two vectors.
/// </summary>
/// <param name="vector1">The first vector.</param>
/// <param name="vector2">The second vector.</param>
/// <returns>The cross product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Cross(Vector3 vector1, Vector3 vector2) =>
new(
vector1.Y * vector2.Z - vector1.Z * vector2.Y,
vector1.Z * vector2.X - vector1.X * vector2.Z,
vector1.X * vector2.Y - vector1.Y * vector2.X
);
/// <summary>
/// Returns the reflection of a vector off a surface that has the specified normal.
/// </summary>
/// <param name="vector">The source vector.</param>
/// <param name="normal">The normal of the surface being reflected off.</param>
/// <returns>The reflected vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Reflect(Vector3 vector, Vector3 normal)
{
double dot = vector.X * normal.X + vector.Y * normal.Y + vector.Z * normal.Z;
double tempX = normal.X * dot * 2;
double tempY = normal.Y * dot * 2;
double tempZ = normal.Z * dot * 2;
return new Vector3(vector.X - tempX, vector.Y - tempY, vector.Z - tempZ);
}
/// <summary>
/// Restricts a vector between a min and max value.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <returns>The restricted vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max)
{
// This compare order is very important!!!
// We must follow HLSL behavior in the case user specified min value is bigger than max value.
double x = value1.X;
x = (x > max.X) ? max.X : x;
x = (x < min.X) ? min.X : x;
double y = value1.Y;
y = (y > max.Y) ? max.Y : y;
y = (y < min.Y) ? min.Y : y;
double z = value1.Z;
z = (z > max.Z) ? max.Z : z;
z = (z < min.Z) ? min.Z : z;
return new Vector3(x, y, z);
}
/// <summary>
/// Linearly interpolates between two vectors based on the given weighting.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <param name="amount">Value between 0 and 1 indicating the weight of the second source vector.</param>
/// <returns>The interpolated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Lerp(Vector3 value1, Vector3 value2, double amount) =>
new(
value1.X + (value2.X - value1.X) * amount,
value1.Y + (value2.Y - value1.Y) * amount,
value1.Z + (value2.Z - value1.Z) * amount
);
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="position">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Transform(Vector3 position, Matrix4x4 matrix) =>
new(
position.X * matrix.M11 + position.Y * matrix.M21 + position.Z * matrix.M31 + matrix.M41,
position.X * matrix.M12 + position.Y * matrix.M22 + position.Z * matrix.M32 + matrix.M42,
position.X * matrix.M13 + position.Y * matrix.M23 + position.Z * matrix.M33 + matrix.M43
);
/// <summary>
/// Transforms a vector normal by the given matrix.
/// </summary>
/// <param name="normal">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 TransformNormal(Vector3 normal, Matrix4x4 matrix) =>
new(
normal.X * matrix.M11 + normal.Y * matrix.M21 + normal.Z * matrix.M31,
normal.X * matrix.M12 + normal.Y * matrix.M22 + normal.Z * matrix.M32,
normal.X * matrix.M13 + normal.Y * matrix.M23 + normal.Z * matrix.M33
);
/// <summary>
/// Transforms a vector by the given Quaternion rotation value.
/// </summary>
/// <param name="value">The source vector to be rotated.</param>
/// <param name="rotation">The rotation to apply.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Transform(Vector3 value, Quaternion rotation)
{
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wx2 = rotation.W * x2;
double wy2 = rotation.W * y2;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double xz2 = rotation.X * z2;
double yy2 = rotation.Y * y2;
double yz2 = rotation.Y * z2;
double zz2 = rotation.Z * z2;
return new Vector3(
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2),
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2) + value.Z * (yz2 - wx2),
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2) + value.Z * (1.0 - xx2 - yy2)
);
}
#endregion Public Static Methods
#region Public operator methods
// All these methods should be inlined as they are implemented
// over JIT intrinsics
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Add(Vector3 left, Vector3 right) => left + right;
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Subtract(Vector3 left, Vector3 right) => left - right;
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Multiply(Vector3 left, Vector3 right) => left * right;
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Multiply(Vector3 left, Double right) => left * right;
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Multiply(Double left, Vector3 right) => left * right;
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Divide(Vector3 left, Vector3 right) => left / right;
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="divisor">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Divide(Vector3 left, Double divisor) => left / divisor;
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Negate(Vector3 value) => -value;
#endregion Public operator methods
}
@@ -0,0 +1,267 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
namespace Speckle.DoubleNumerics;
// This file contains the definitions for all of the JIT intrinsic methods and properties that are recognized by the current x64 JIT compiler.
// The implementation defined here is used in any circumstance where the JIT fails to recognize these members as intrinsic.
// The JIT recognizes these methods and properties by name and signature: if either is changed, the JIT will no longer recognize the member.
// Some methods declared here are not strictly intrinsic, but delegate to an intrinsic method. For example, only one overload of CopyTo()
// is actually recognized by the JIT, but both are here for simplicity.
public partial struct Vector3
{
/// <summary>
/// The X component of the vector.
/// </summary>
public Double X;
/// <summary>
/// The Y component of the vector.
/// </summary>
public Double Y;
/// <summary>
/// The Z component of the vector.
/// </summary>
public Double Z;
#region Constructors
/// <summary>
/// Constructs a vector whose elements are all the single specified value.
/// </summary>
/// <param name="value">The element to fill the vector with.</param>
public Vector3(Double value)
: this(value, value, value) { }
/// <summary>
/// Constructs a Vector3 from the given Vector2 and a third value.
/// </summary>
/// <param name="value">The Vector to extract X and Y components from.</param>
/// <param name="z">The Z component.</param>
public Vector3(Vector2 value, double z)
: this(value.X, value.Y, z) { }
/// <summary>
/// Constructs a vector with the given individual elements.
/// </summary>
/// <param name="x">The X component.</param>
/// <param name="y">The Y component.</param>
/// <param name="z">The Z component.</param>
public Vector3(Double x, Double y, Double z)
{
X = x;
Y = y;
Z = z;
}
#endregion Constructors
#region Public Instance Methods
/// <summary>
/// Copies the contents of the vector into the given array.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Double[] array) => CopyTo(array, 0);
/// <summary>
/// Copies the contents of the vector into the given array, starting from index.
/// </summary>
/// <exception cref="ArgumentNullException">If array is null.</exception>
/// <exception cref="RankException">If array is multidimensional.</exception>
/// <exception cref="ArgumentOutOfRangeException">If index is greater than end of the array or index is less than zero.</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Double[]? array, int index)
{
if (array == null)
{
// Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull.
throw new NullReferenceException(Strings.Arg_NullArgumentNullRef);
}
if (index < 0 || index >= array.Length)
{
throw new ArgumentOutOfRangeException(
nameof(index),
String.Format(Strings.Arg_ArgumentOutOfRangeException, index)
);
}
if ((array.Length - index) < 3)
{
throw new ArgumentException(String.Format(Strings.Arg_ElementsInSourceIsGreaterThanDestination, index));
}
array[index] = X;
array[index + 1] = Y;
array[index + 2] = Z;
}
/// <summary>
/// Returns a boolean indicating whether the given Vector3 is equal to this Vector3 instance.
/// </summary>
/// <param name="other">The Vector3 to compare this instance to.</param>
/// <returns>True if the other Vector3 is equal to this instance; False otherwise.</returns>
public bool Equals(Vector3 other) => X == other.X && Y == other.Y && Z == other.Z;
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the dot product of two vectors.
/// </summary>
/// <param name="vector1">The first vector.</param>
/// <param name="vector2">The second vector.</param>
/// <returns>The dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Vector3 vector1, Vector3 vector2) =>
vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z;
/// <summary>
/// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The minimized vector.</returns>
public static Vector3 Min(Vector3 value1, Vector3 value2) =>
new(
(value1.X < value2.X) ? value1.X : value2.X,
(value1.Y < value2.Y) ? value1.Y : value2.Y,
(value1.Z < value2.Z) ? value1.Z : value2.Z
);
/// <summary>
/// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The maximized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Max(Vector3 value1, Vector3 value2) =>
new(
(value1.X > value2.X) ? value1.X : value2.X,
(value1.Y > value2.Y) ? value1.Y : value2.Y,
(value1.Z > value2.Z) ? value1.Z : value2.Z
);
/// <summary>
/// Returns a vector whose elements are the absolute values of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The absolute value vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Abs(Vector3 value) => new(Math.Abs(value.X), Math.Abs(value.Y), Math.Abs(value.Z));
/// <summary>
/// Returns a vector whose elements are the square root of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The square root vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 SquareRoot(Vector3 value) => new(Math.Sqrt(value.X), Math.Sqrt(value.Y), Math.Sqrt(value.Z));
#endregion Public Static Methods
#region Public Static Operators
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator +(Vector3 left, Vector3 right) =>
new(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator -(Vector3 left, Vector3 right) =>
new(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(Vector3 left, Vector3 right) =>
new(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(Vector3 left, Double right) => left * new Vector3(right);
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(Double left, Vector3 right) => new Vector3(left) * right;
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator /(Vector3 left, Vector3 right) =>
new(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator /(Vector3 value1, double value2)
{
double invDiv = 1.0 / value2;
return new Vector3(value1.X * invDiv, value1.Y * invDiv, value1.Z * invDiv);
}
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator -(Vector3 value) => Zero - value;
/// <summary>
/// Returns a boolean indicating whether the two given vectors are equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are equal; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector3 left, Vector3 right) =>
(left.X == right.X && left.Y == right.Y && left.Z == right.Z);
/// <summary>
/// Returns a boolean indicating whether the two given vectors are not equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are not equal; False if they are equal.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vector3 left, Vector3 right) =>
(left.X != right.X || left.Y != right.Y || left.Z != right.Z);
#endregion Public Static Operators
}
+450
View File
@@ -0,0 +1,450 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
namespace Speckle.DoubleNumerics;
/// <summary>
/// A structure encapsulating four single precision floating point values and provides hardware accelerated methods.
/// </summary>
public partial struct Vector4 : IEquatable<Vector4>, IFormattable
{
#region Public Static Properties
/// <summary>
/// Returns the vector (0,0,0,0).
/// </summary>
public static Vector4 Zero => new();
/// <summary>
/// Returns the vector (1,1,1,1).
/// </summary>
public static Vector4 One => new(1.0, 1.0, 1.0, 1.0);
/// <summary>
/// Returns the vector (1,0,0,0).
/// </summary>
public static Vector4 UnitX => new(1.0, 0.0, 0.0, 0.0);
/// <summary>
/// Returns the vector (0,1,0,0).
/// </summary>
public static Vector4 UnitY => new(0.0, 1.0, 0.0, 0.0);
/// <summary>
/// Returns the vector (0,0,1,0).
/// </summary>
public static Vector4 UnitZ => new(0.0, 0.0, 1.0, 0.0);
/// <summary>
/// Returns the vector (0,0,0,1).
/// </summary>
public static Vector4 UnitW => new(0.0, 0.0, 0.0, 1.0);
#endregion Public Static Properties
#region Public instance methods
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
int hash = X.GetHashCode();
hash = HashHelpers.Combine(hash, Y.GetHashCode());
hash = HashHelpers.Combine(hash, Z.GetHashCode());
hash = HashHelpers.Combine(hash, W.GetHashCode());
return hash;
}
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this Vector4 instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this Vector4; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object? obj)
{
if (!(obj is Vector4 vector4))
return false;
return Equals(vector4);
}
/// <summary>
/// Returns a String representing this Vector4 instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString() => ToString("G", CultureInfo.CurrentCulture);
/// <summary>
/// Returns a String representing this Vector4 instance, using the specified format to format individual elements.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string format) => ToString(format, CultureInfo.CurrentCulture);
/// <summary>
/// Returns a String representing this Vector4 instance, using the specified format to format individual elements
/// and the given IFormatProvider.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <param name="formatProvider">The format provider to use when formatting elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string? format, IFormatProvider? formatProvider)
{
StringBuilder sb = new();
string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
sb.Append('<');
sb.Append(X.ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(Y.ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(Z.ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(W.ToString(format, formatProvider));
sb.Append('>');
return sb.ToString();
}
/// <summary>
/// Returns the length of the vector. This operation is cheaper than Length().
/// </summary>
/// <returns>The vector's length.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Length()
{
double ls = X * X + Y * Y + Z * Z + W * W;
return Math.Sqrt(ls);
}
/// <summary>
/// Returns the length of the vector squared.
/// </summary>
/// <returns>The vector's length squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double LengthSquared() => X * X + Y * Y + Z * Z + W * W;
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the Euclidean distance between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Distance(Vector4 value1, Vector4 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double dz = value1.Z - value2.Z;
double dw = value1.W - value2.W;
double ls = dx * dx + dy * dy + dz * dz + dw * dw;
return Math.Sqrt(ls);
}
/// <summary>
/// Returns the Euclidean distance squared between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DistanceSquared(Vector4 value1, Vector4 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double dz = value1.Z - value2.Z;
double dw = value1.W - value2.W;
return dx * dx + dy * dy + dz * dz + dw * dw;
}
/// <summary>
/// Returns a vector with the same direction as the given vector, but with a length of 1.
/// </summary>
/// <param name="vector">The vector to normalize.</param>
/// <returns>The normalized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Normalize(Vector4 vector)
{
double ls = vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z + vector.W * vector.W;
double invNorm = 1.0 / Math.Sqrt(ls);
return new Vector4(vector.X * invNorm, vector.Y * invNorm, vector.Z * invNorm, vector.W * invNorm);
}
/// <summary>
/// Restricts a vector between a min and max value.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <returns>The restricted vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Clamp(Vector4 value1, Vector4 min, Vector4 max)
{
// This compare order is very important!!!
// We must follow HLSL behavior in the case user specified min value is bigger than max value.
double x = value1.X;
x = (x > max.X) ? max.X : x;
x = (x < min.X) ? min.X : x;
double y = value1.Y;
y = (y > max.Y) ? max.Y : y;
y = (y < min.Y) ? min.Y : y;
double z = value1.Z;
z = (z > max.Z) ? max.Z : z;
z = (z < min.Z) ? min.Z : z;
double w = value1.W;
w = (w > max.W) ? max.W : w;
w = (w < min.W) ? min.W : w;
return new Vector4(x, y, z, w);
}
/// <summary>
/// Linearly interpolates between two vectors based on the given weighting.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <param name="amount">Value between 0 and 1 indicating the weight of the second source vector.</param>
/// <returns>The interpolated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Lerp(Vector4 value1, Vector4 value2, double amount) =>
new(
value1.X + (value2.X - value1.X) * amount,
value1.Y + (value2.Y - value1.Y) * amount,
value1.Z + (value2.Z - value1.Z) * amount,
value1.W + (value2.W - value1.W) * amount
);
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="position">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector2 position, Matrix4x4 matrix) =>
new(
position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M41,
position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M42,
position.X * matrix.M13 + position.Y * matrix.M23 + matrix.M43,
position.X * matrix.M14 + position.Y * matrix.M24 + matrix.M44
);
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="position">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector3 position, Matrix4x4 matrix) =>
new(
position.X * matrix.M11 + position.Y * matrix.M21 + position.Z * matrix.M31 + matrix.M41,
position.X * matrix.M12 + position.Y * matrix.M22 + position.Z * matrix.M32 + matrix.M42,
position.X * matrix.M13 + position.Y * matrix.M23 + position.Z * matrix.M33 + matrix.M43,
position.X * matrix.M14 + position.Y * matrix.M24 + position.Z * matrix.M34 + matrix.M44
);
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="vector">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector4 vector, Matrix4x4 matrix) =>
new(
vector.X * matrix.M11 + vector.Y * matrix.M21 + vector.Z * matrix.M31 + vector.W * matrix.M41,
vector.X * matrix.M12 + vector.Y * matrix.M22 + vector.Z * matrix.M32 + vector.W * matrix.M42,
vector.X * matrix.M13 + vector.Y * matrix.M23 + vector.Z * matrix.M33 + vector.W * matrix.M43,
vector.X * matrix.M14 + vector.Y * matrix.M24 + vector.Z * matrix.M34 + vector.W * matrix.M44
);
/// <summary>
/// Transforms a vector by the given Quaternion rotation value.
/// </summary>
/// <param name="value">The source vector to be rotated.</param>
/// <param name="rotation">The rotation to apply.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector2 value, Quaternion rotation)
{
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wx2 = rotation.W * x2;
double wy2 = rotation.W * y2;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double xz2 = rotation.X * z2;
double yy2 = rotation.Y * y2;
double yz2 = rotation.Y * z2;
double zz2 = rotation.Z * z2;
return new Vector4(
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2),
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2),
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2),
1.0
);
}
/// <summary>
/// Transforms a vector by the given Quaternion rotation value.
/// </summary>
/// <param name="value">The source vector to be rotated.</param>
/// <param name="rotation">The rotation to apply.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector3 value, Quaternion rotation)
{
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wx2 = rotation.W * x2;
double wy2 = rotation.W * y2;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double xz2 = rotation.X * z2;
double yy2 = rotation.Y * y2;
double yz2 = rotation.Y * z2;
double zz2 = rotation.Z * z2;
return new Vector4(
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2),
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2) + value.Z * (yz2 - wx2),
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2) + value.Z * (1.0 - xx2 - yy2),
1.0
);
}
/// <summary>
/// Transforms a vector by the given Quaternion rotation value.
/// </summary>
/// <param name="value">The source vector to be rotated.</param>
/// <param name="rotation">The rotation to apply.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector4 value, Quaternion rotation)
{
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wx2 = rotation.W * x2;
double wy2 = rotation.W * y2;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double xz2 = rotation.X * z2;
double yy2 = rotation.Y * y2;
double yz2 = rotation.Y * z2;
double zz2 = rotation.Z * z2;
return new Vector4(
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2),
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2) + value.Z * (yz2 - wx2),
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2) + value.Z * (1.0 - xx2 - yy2),
value.W
);
}
#endregion Public Static Methods
#region Public operator methods
// All these methods should be inlines as they are implemented
// over JIT intrinsics
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Add(Vector4 left, Vector4 right) => left + right;
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Subtract(Vector4 left, Vector4 right) => left - right;
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Multiply(Vector4 left, Vector4 right) => left * right;
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Multiply(Vector4 left, Double right) => left * new Vector4(right, right, right, right);
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Multiply(Double left, Vector4 right) => new Vector4(left, left, left, left) * right;
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Divide(Vector4 left, Vector4 right) => left / right;
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="divisor">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Divide(Vector4 left, Double divisor) => left / divisor;
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Negate(Vector4 value) => -value;
#endregion Public operator methods
}
@@ -0,0 +1,297 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
namespace Speckle.DoubleNumerics;
// This file contains the definitions for all of the JIT intrinsic methods and properties that are recognized by the current x64 JIT compiler.
// The implementation defined here is used in any circumstance where the JIT fails to recognize these members as intrinsic.
// The JIT recognizes these methods and properties by name and signature: if either is changed, the JIT will no longer recognize the member.
// Some methods declared here are not strictly intrinsic, but delegate to an intrinsic method. For example, only one overload of CopyTo()
public partial struct Vector4
{
/// <summary>
/// The X component of the vector.
/// </summary>
public Double X;
/// <summary>
/// The Y component of the vector.
/// </summary>
public Double Y;
/// <summary>
/// The Z component of the vector.
/// </summary>
public Double Z;
/// <summary>
/// The W component of the vector.
/// </summary>
public Double W;
#region Constructors
/// <summary>
/// Constructs a vector whose elements are all the single specified value.
/// </summary>
/// <param name="value">The element to fill the vector with.</param>
public Vector4(Double value)
: this(value, value, value, value) { }
/// <summary>
/// Constructs a vector with the given individual elements.
/// </summary>
/// <param name="w">W component.</param>
/// <param name="x">X component.</param>
/// <param name="y">Y component.</param>
/// <param name="z">Z component.</param>
public Vector4(Double x, Double y, Double z, Double w)
{
W = w;
X = x;
Y = y;
Z = z;
}
/// <summary>
/// Constructs a Vector4 from the given Vector2 and a Z and W component.
/// </summary>
/// <param name="value">The vector to use as the X and Y components.</param>
/// <param name="z">The Z component.</param>
/// <param name="w">The W component.</param>
public Vector4(Vector2 value, Double z, Double w)
{
X = value.X;
Y = value.Y;
Z = z;
W = w;
}
/// <summary>
/// Constructs a Vector4 from the given Vector3 and a W component.
/// </summary>
/// <param name="value">The vector to use as the X, Y, and Z components.</param>
/// <param name="w">The W component.</param>
public Vector4(Vector3 value, Double w)
{
X = value.X;
Y = value.Y;
Z = value.Z;
W = w;
}
#endregion Constructors
#region Public Instance Methods
/// <summary>
/// Copies the contents of the vector into the given array.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Double[] array) => CopyTo(array, 0);
/// <summary>
/// Copies the contents of the vector into the given array, starting from index.
/// </summary>
/// <exception cref="ArgumentNullException">If array is null.</exception>
/// <exception cref="RankException">If array is multidimensional.</exception>
/// <exception cref="ArgumentOutOfRangeException">If index is greater than end of the array or index is less than zero.</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Double[]? array, int index)
{
if (array == null)
{
// Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull.
throw new NullReferenceException(Strings.Arg_NullArgumentNullRef);
}
if (index < 0 || index >= array.Length)
{
throw new ArgumentOutOfRangeException(
nameof(index),
String.Format(Strings.Arg_ArgumentOutOfRangeException, index)
);
}
if ((array.Length - index) < 4)
{
throw new ArgumentException(String.Format(Strings.Arg_ElementsInSourceIsGreaterThanDestination, index));
}
array[index] = X;
array[index + 1] = Y;
array[index + 2] = Z;
array[index + 3] = W;
}
/// <summary>
/// Returns a boolean indicating whether the given Vector4 is equal to this Vector4 instance.
/// </summary>
/// <param name="other">The Vector4 to compare this instance to.</param>
/// <returns>True if the other Vector4 is equal to this instance; False otherwise.</returns>
public bool Equals(Vector4 other) => X == other.X && Y == other.Y && Z == other.Z && W == other.W;
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the dot product of two vectors.
/// </summary>
/// <param name="vector1">The first vector.</param>
/// <param name="vector2">The second vector.</param>
/// <returns>The dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Vector4 vector1, Vector4 vector2) =>
vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z + vector1.W * vector2.W;
/// <summary>
/// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The minimized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Min(Vector4 value1, Vector4 value2) =>
new(
(value1.X < value2.X) ? value1.X : value2.X,
(value1.Y < value2.Y) ? value1.Y : value2.Y,
(value1.Z < value2.Z) ? value1.Z : value2.Z,
(value1.W < value2.W) ? value1.W : value2.W
);
/// <summary>
/// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The maximized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Max(Vector4 value1, Vector4 value2) =>
new(
(value1.X > value2.X) ? value1.X : value2.X,
(value1.Y > value2.Y) ? value1.Y : value2.Y,
(value1.Z > value2.Z) ? value1.Z : value2.Z,
(value1.W > value2.W) ? value1.W : value2.W
);
/// <summary>
/// Returns a vector whose elements are the absolute values of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The absolute value vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Abs(Vector4 value) =>
new(Math.Abs(value.X), Math.Abs(value.Y), Math.Abs(value.Z), Math.Abs(value.W));
/// <summary>
/// Returns a vector whose elements are the square root of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The square root vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 SquareRoot(Vector4 value) =>
new(Math.Sqrt(value.X), Math.Sqrt(value.Y), Math.Sqrt(value.Z), Math.Sqrt(value.W));
#endregion Public Static Methods
#region Public static operators
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator +(Vector4 left, Vector4 right) =>
new(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W);
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator -(Vector4 left, Vector4 right) =>
new(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W);
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator *(Vector4 left, Vector4 right) =>
new(left.X * right.X, left.Y * right.Y, left.Z * right.Z, left.W * right.W);
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator *(Vector4 left, Double right) => left * new Vector4(right);
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator *(Double left, Vector4 right) => new Vector4(left) * right;
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator /(Vector4 left, Vector4 right) =>
new(left.X / right.X, left.Y / right.Y, left.Z / right.Z, left.W / right.W);
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator /(Vector4 value1, double value2)
{
double invDiv = 1.0 / value2;
return new Vector4(value1.X * invDiv, value1.Y * invDiv, value1.Z * invDiv, value1.W * invDiv);
}
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator -(Vector4 value) => Zero - value;
/// <summary>
/// Returns a boolean indicating whether the two given vectors are equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are equal; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector4 left, Vector4 right) => left.Equals(right);
/// <summary>
/// Returns a boolean indicating whether the two given vectors are not equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are not equal; False if they are equal.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vector4 left, Vector4 right) => !(left == right);
#endregion Public static operators
}
+87
View File
@@ -0,0 +1,87 @@
{
"version": 2,
"dependencies": {
".NETStandard,Version=v2.0": {
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"MinVer": {
"type": "Direct",
"requested": "[5.0.0, )",
"resolved": "5.0.0",
"contentHash": "ybkgpQMtt0Fo91l5rYtE3TZtD+Nmy5Ko091xvfXXOosQdMi30XO2EZ2+ShZt89gdu7RMmJqZaJ+e1q6d+6+KNw=="
},
"NETStandard.Library": {
"type": "Direct",
"requested": "[2.0.3, )",
"resolved": "2.0.3",
"contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.0"
}
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.NETCore.Platforms": {
"type": "Transitive",
"resolved": "1.1.0",
"contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
}
},
"net6.0": {
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"MinVer": {
"type": "Direct",
"requested": "[5.0.0, )",
"resolved": "5.0.0",
"contentHash": "ybkgpQMtt0Fo91l5rYtE3TZtD+Nmy5Ko091xvfXXOosQdMi30XO2EZ2+ShZt89gdu7RMmJqZaJ+e1q6d+6+KNw=="
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
}
}
}
}
+2
View File
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CustomTools/CustomToolsData/@EntryValue">ExternalToolData|CSharpier|csharpier||csharpier|$FILE$</s:String></wpf:ResourceDictionary>
@@ -1,17 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Common.System.Numerics.Hashing
{
internal static class HashHelpers
{
public static int Combine(int h1, int h2)
{
// The jit optimizes this to use the ROL instruction on x86
// Related GitHub pull request: dotnet/coreclr#1830
uint shift5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
return ((int)shift5 + h1) ^ h2;
}
}
}
-142
View File
@@ -1,142 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
namespace System.DoubleNumerics
{
internal class ConstantHelper
{
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Byte GetByteWithAllBitsSet()
{
Byte value = 0;
unsafe
{
unchecked
{
*((Byte*)&value) = (Byte)0xff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static SByte GetSByteWithAllBitsSet()
{
SByte value = 0;
unsafe
{
unchecked
{
*((SByte*)&value) = (SByte)0xff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static UInt16 GetUInt16WithAllBitsSet()
{
UInt16 value = 0;
unsafe
{
unchecked
{
*((UInt16*)&value) = (UInt16)0xffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Int16 GetInt16WithAllBitsSet()
{
Int16 value = 0;
unsafe
{
unchecked
{
*((Int16*)&value) = (Int16)0xffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static UInt32 GetUInt32WithAllBitsSet()
{
UInt32 value = 0;
unsafe
{
unchecked
{
*((UInt32*)&value) = (UInt32)0xffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Int32 GetInt32WithAllBitsSet()
{
Int32 value = 0;
unsafe
{
unchecked
{
*((Int32*)&value) = (Int32)0xffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static UInt64 GetUInt64WithAllBitsSet()
{
UInt64 value = 0;
unsafe
{
unchecked
{
*((UInt64*)&value) = (UInt64)0xffffffffffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Int64 GetInt64WithAllBitsSet()
{
Int64 value = 0;
unsafe
{
unchecked
{
*((Int64*)&value) = (Int64)0xffffffffffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Double GetDoubleWithAllBitsSet()
{
Double value = 0;
unsafe
{
unchecked
{
*((Int32*)&value) = (Int32)0xffffffffffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Single GetSingleWithAllBitsSet()
{
Single value = 0;
unsafe
{
unchecked
{
*((Single*)&value) = (Single)0xffffffff;
}
}
return value;
}
}
}
-60
View File
@@ -1,60 +0,0 @@
<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Xml.dll" #>
<#@ Assembly Name="System.Xml.Linq.dll" #>
<#@ Assembly Name="System.Windows.Forms.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Runtime.InteropServices" #>
<#@ include file="GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #>
using System.Runtime.CompilerServices;
namespace System.DoubleNumerics
{
internal class ConstantHelper
{
<# foreach (var type in supportedTypes)
{
string hexValue = "0x" + new string('f', Marshal.SizeOf(type) * 2);
#>
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static <#= type.Name #> Get<#= type.Name #>WithAllBitsSet()
{
<#= type.Name #> value = 0;
unsafe
{
unchecked
{
*((<#= GetIntegralEquivalent(type).Name #>*)&value) = (<#=GetIntegralEquivalent(type).Name#>)<#= hexValue #>;
}
}
return value;
}
<#
}
#>
}
}<#+
public Type GetIntegralEquivalent(Type type)
{
if (type == typeof(Double))
{
return typeof(Int32);
}
else if (type == typeof(double))
{
return typeof(Int64);
}
else
{
return type;
}
}
#>
@@ -1,69 +0,0 @@
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#+
/* This file includes static data used as compilation configuration for the rest of the code generation.
It is shared here to ensure that all generated code compiles with the same constants and configurations. */
// The set of supported numeric types to compile
public static Type[] supportedTypes = new[]
{
typeof(Byte), typeof(SByte), typeof(UInt16), typeof(Int16),
typeof(UInt32), typeof(Int32), typeof(UInt64), typeof(Int64),
typeof(Double), typeof(Single)
};
// The set of unsigned types, a subset of the above. Used for excluding from certain methods, i.e. Abs and Negate
public static Type[] unsignedTypes = new[]
{
typeof(Byte), typeof(UInt16), typeof(UInt32), typeof(UInt64)
};
public static Type[] integralTypes = new[]
{
typeof(Byte), typeof(SByte), typeof(UInt16), typeof(Int16),
typeof(UInt32), typeof(Int32), typeof(UInt64), typeof(Int64)
};
public static Type[] nonClsCompliantTypes = new[]
{
typeof(SByte), typeof(UInt16),
typeof(UInt32), typeof(UInt64)
};
// The total register size, in bytes. 16 for SSE2, 32 for AVX, 64 for AVX512
public static int totalSize = 16;
/* General template helper procedures */
// Returns the constructed register field name for the given type and index.
public string GetRegisterFieldName(Type t, int index)
{
return "register." + t.Name.ToLowerInvariant() + "_" + index;
}
// Returns the number of fields for a given type, based on the current configuration's register size
public int GetNumFields(Type t, int totalSize)
{
return totalSize / Marshal.SizeOf(t);
}
public void GenerateCopyrightHeader()
{
#>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
<#+
}
public string GenerateIfStatementHeader(Type type)
{
string keyword = (type == supportedTypes[0]) ? "if" : "else if";
return string.Format("{0} (typeof(T) == typeof({1}))", keyword, type.Name);
}
public string GenerateIfStatementHeader(Type type, IEnumerable<Type> allTypes)
{
string keyword = (type == allTypes.ToArray()[0]) ? "if" : "else if";
return string.Format("{0} (typeof(T) == typeof({1}))", keyword, type.Name);
}
#>
-821
View File
@@ -1,821 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Text;
namespace System.DoubleNumerics
{
/// <summary>
/// A structure encapsulating a 3x2 matrix.
/// </summary>
public struct Matrix3x2 : IEquatable<Matrix3x2>
{
#region Public Fields
/// <summary>
/// The first element of the first row
/// </summary>
public double M11;
/// <summary>
/// The second element of the first row
/// </summary>
public double M12;
/// <summary>
/// The first element of the second row
/// </summary>
public double M21;
/// <summary>
/// The second element of the second row
/// </summary>
public double M22;
/// <summary>
/// The first element of the third row
/// </summary>
public double M31;
/// <summary>
/// The second element of the third row
/// </summary>
public double M32;
#endregion Public Fields
private static readonly Matrix3x2 _identity = new Matrix3x2
(
1, 0,
0, 1,
0, 0
);
/// <summary>
/// Returns the multiplicative identity matrix.
/// </summary>
public static Matrix3x2 Identity
{
get { return _identity; }
}
/// <summary>
/// Returns whether the matrix is the identity matrix.
/// </summary>
public bool IsIdentity
{
get
{
return M11 == 1 && M22 == 1 && // Check diagonal element first for early out.
M12 == 0 &&
M21 == 0 &&
M31 == 0 && M32 == 0;
}
}
/// <summary>
/// Gets or sets the translation component of this matrix.
/// </summary>
public Vector2 Translation
{
get
{
return new Vector2(M31, M32);
}
set
{
M31 = value.X;
M32 = value.Y;
}
}
/// <summary>
/// Constructs a Matrix3x2 from the given components.
/// </summary>
public Matrix3x2(double m11, double m12,
double m21, double m22,
double m31, double m32)
{
this.M11 = m11;
this.M12 = m12;
this.M21 = m21;
this.M22 = m22;
this.M31 = m31;
this.M32 = m32;
}
/// <summary>
/// Creates a translation matrix from the given vector.
/// </summary>
/// <param name="position">The translation position.</param>
/// <returns>A translation matrix.</returns>
public static Matrix3x2 CreateTranslation(Vector2 position)
{
Matrix3x2 result;
result.M11 = 1.0;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = 1.0;
result.M31 = position.X;
result.M32 = position.Y;
return result;
}
/// <summary>
/// Creates a translation matrix from the given X and Y components.
/// </summary>
/// <param name="xPosition">The X position.</param>
/// <param name="yPosition">The Y position.</param>
/// <returns>A translation matrix.</returns>
public static Matrix3x2 CreateTranslation(double xPosition, double yPosition)
{
Matrix3x2 result;
result.M11 = 1.0;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = 1.0;
result.M31 = xPosition;
result.M32 = yPosition;
return result;
}
public string ToMultiLineString()
{
var ci = CultureInfo.CurrentCulture;
var sb = new StringBuilder();
sb.AppendLine($"{M11.ToString(ci),-19} {M12.ToString(ci),-19}");
sb.AppendLine($"{M21.ToString(ci),-19} {M22.ToString(ci),-19}");
sb.AppendLine($"{M31.ToString(ci),-19} {M32.ToString(ci),-19}");
return sb.ToString();
}
/// <summary>
/// Creates a scale matrix from the given X and Y components.
/// </summary>
/// <param name="xScale">Value to scale by on the X-axis.</param>
/// <param name="yScale">Value to scale by on the Y-axis.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(double xScale, double yScale)
{
Matrix3x2 result;
result.M11 = xScale;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = yScale;
result.M31 = 0.0;
result.M32 = 0.0;
return result;
}
/// <summary>
/// Creates a scale matrix that is offset by a given center point.
/// </summary>
/// <param name="xScale">Value to scale by on the X-axis.</param>
/// <param name="yScale">Value to scale by on the Y-axis.</param>
/// <param name="centerPoint">The center point.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(double xScale, double yScale, Vector2 centerPoint)
{
Matrix3x2 result;
double tx = centerPoint.X * (1 - xScale);
double ty = centerPoint.Y * (1 - yScale);
result.M11 = xScale;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = yScale;
result.M31 = tx;
result.M32 = ty;
return result;
}
/// <summary>
/// Creates a scale matrix from the given vector scale.
/// </summary>
/// <param name="scales">The scale to use.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(Vector2 scales)
{
Matrix3x2 result;
result.M11 = scales.X;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = scales.Y;
result.M31 = 0.0;
result.M32 = 0.0;
return result;
}
/// <summary>
/// Creates a scale matrix from the given vector scale with an offset from the given center point.
/// </summary>
/// <param name="scales">The scale to use.</param>
/// <param name="centerPoint">The center offset.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(Vector2 scales, Vector2 centerPoint)
{
Matrix3x2 result;
double tx = centerPoint.X * (1 - scales.X);
double ty = centerPoint.Y * (1 - scales.Y);
result.M11 = scales.X;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = scales.Y;
result.M31 = tx;
result.M32 = ty;
return result;
}
/// <summary>
/// Creates a scale matrix that scales uniformly with the given scale.
/// </summary>
/// <param name="scale">The uniform scale to use.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(double scale)
{
Matrix3x2 result;
result.M11 = scale;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = scale;
result.M31 = 0.0;
result.M32 = 0.0;
return result;
}
/// <summary>
/// Creates a scale matrix that scales uniformly with the given scale with an offset from the given center.
/// </summary>
/// <param name="scale">The uniform scale to use.</param>
/// <param name="centerPoint">The center offset.</param>
/// <returns>A scaling matrix.</returns>
public static Matrix3x2 CreateScale(double scale, Vector2 centerPoint)
{
Matrix3x2 result;
double tx = centerPoint.X * (1 - scale);
double ty = centerPoint.Y * (1 - scale);
result.M11 = scale;
result.M12 = 0.0;
result.M21 = 0.0;
result.M22 = scale;
result.M31 = tx;
result.M32 = ty;
return result;
}
/// <summary>
/// Creates a skew matrix from the given angles in radians.
/// </summary>
/// <param name="radiansX">The X angle, in radians.</param>
/// <param name="radiansY">The Y angle, in radians.</param>
/// <returns>A skew matrix.</returns>
public static Matrix3x2 CreateSkew(double radiansX, double radiansY)
{
Matrix3x2 result;
double xTan = (double)Math.Tan(radiansX);
double yTan = (double)Math.Tan(radiansY);
result.M11 = 1.0;
result.M12 = yTan;
result.M21 = xTan;
result.M22 = 1.0;
result.M31 = 0.0;
result.M32 = 0.0;
return result;
}
/// <summary>
/// Creates a skew matrix from the given angles in radians and a center point.
/// </summary>
/// <param name="radiansX">The X angle, in radians.</param>
/// <param name="radiansY">The Y angle, in radians.</param>
/// <param name="centerPoint">The center point.</param>
/// <returns>A skew matrix.</returns>
public static Matrix3x2 CreateSkew(double radiansX, double radiansY, Vector2 centerPoint)
{
Matrix3x2 result;
double xTan = (double)Math.Tan(radiansX);
double yTan = (double)Math.Tan(radiansY);
double tx = -centerPoint.Y * xTan;
double ty = -centerPoint.X * yTan;
result.M11 = 1.0;
result.M12 = yTan;
result.M21 = xTan;
result.M22 = 1.0;
result.M31 = tx;
result.M32 = ty;
return result;
}
/// <summary>
/// Creates a rotation matrix using the given rotation in radians.
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <returns>A rotation matrix.</returns>
public static Matrix3x2 CreateRotation(double radians)
{
Matrix3x2 result;
radians = (double)Math.IEEERemainder(radians, Math.PI * 2);
double c, s;
const double epsilon = 0.001 * (double)Math.PI / 180; // 0.1% of a degree
if (radians > -epsilon && radians < epsilon)
{
// Exact case for zero rotation.
c = 1;
s = 0;
}
else if (radians > Math.PI / 2 - epsilon && radians < Math.PI / 2 + epsilon)
{
// Exact case for 90 degree rotation.
c = 0;
s = 1;
}
else if (radians < -Math.PI + epsilon || radians > Math.PI - epsilon)
{
// Exact case for 180 degree rotation.
c = -1;
s = 0;
}
else if (radians > -Math.PI / 2 - epsilon && radians < -Math.PI / 2 + epsilon)
{
// Exact case for 270 degree rotation.
c = 0;
s = -1;
}
else
{
// Arbitrary rotation.
c = (double)Math.Cos(radians);
s = (double)Math.Sin(radians);
}
// [ c s ]
// [ -s c ]
// [ 0 0 ]
result.M11 = c;
result.M12 = s;
result.M21 = -s;
result.M22 = c;
result.M31 = 0.0;
result.M32 = 0.0;
return result;
}
/// <summary>
/// Creates a rotation matrix using the given rotation in radians and a center point.
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <param name="centerPoint">The center point.</param>
/// <returns>A rotation matrix.</returns>
public static Matrix3x2 CreateRotation(double radians, Vector2 centerPoint)
{
Matrix3x2 result;
radians = (double)Math.IEEERemainder(radians, Math.PI * 2);
double c, s;
const double epsilon = 0.001 * (double)Math.PI / 180; // 0.1% of a degree
if (radians > -epsilon && radians < epsilon)
{
// Exact case for zero rotation.
c = 1;
s = 0;
}
else if (radians > Math.PI / 2 - epsilon && radians < Math.PI / 2 + epsilon)
{
// Exact case for 90 degree rotation.
c = 0;
s = 1;
}
else if (radians < -Math.PI + epsilon || radians > Math.PI - epsilon)
{
// Exact case for 180 degree rotation.
c = -1;
s = 0;
}
else if (radians > -Math.PI / 2 - epsilon && radians < -Math.PI / 2 + epsilon)
{
// Exact case for 270 degree rotation.
c = 0;
s = -1;
}
else
{
// Arbitrary rotation.
c = (double)Math.Cos(radians);
s = (double)Math.Sin(radians);
}
double x = centerPoint.X * (1 - c) + centerPoint.Y * s;
double y = centerPoint.Y * (1 - c) - centerPoint.X * s;
// [ c s ]
// [ -s c ]
// [ x y ]
result.M11 = c;
result.M12 = s;
result.M21 = -s;
result.M22 = c;
result.M31 = x;
result.M32 = y;
return result;
}
/// <summary>
/// Calculates the determinant for this matrix.
/// The determinant is calculated by expanding the matrix with a third column whose values are (0,0,1).
/// </summary>
/// <returns>The determinant.</returns>
public double GetDeterminant()
{
// There isn't actually any such thing as a determinant for a non-square matrix,
// but this 3x2 type is really just an optimization of a 3x3 where we happen to
// know the rightmost column is always (0, 0, 1). So we expand to 3x3 format:
//
// [ M11, M12, 0 ]
// [ M21, M22, 0 ]
// [ M31, M32, 1 ]
//
// Sum the diagonal products:
// (M11 * M22 * 1) + (M12 * 0 * M31) + (0 * M21 * M32)
//
// Subtract the opposite diagonal products:
// (M31 * M22 * 0) + (M32 * 0 * M11) + (1 * M21 * M12)
//
// Collapse out the constants and oh look, this is just a 2x2 determinant!
return (M11 * M22) - (M21 * M12);
}
/// <summary>
/// Attempts to invert the given matrix. If the operation succeeds, the inverted matrix is stored in the result parameter.
/// </summary>
/// <param name="matrix">The source matrix.</param>
/// <param name="result">The output matrix.</param>
/// <returns>True if the operation succeeded, False otherwise.</returns>
public static bool Invert(Matrix3x2 matrix, out Matrix3x2 result)
{
double det = (matrix.M11 * matrix.M22) - (matrix.M21 * matrix.M12);
if (Math.Abs(det) < double.Epsilon)
{
result = new Matrix3x2(double.NaN, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN);
return false;
}
double invDet = 1.0 / det;
result.M11 = matrix.M22 * invDet;
result.M12 = -matrix.M12 * invDet;
result.M21 = -matrix.M21 * invDet;
result.M22 = matrix.M11 * invDet;
result.M31 = (matrix.M21 * matrix.M32 - matrix.M31 * matrix.M22) * invDet;
result.M32 = (matrix.M31 * matrix.M12 - matrix.M11 * matrix.M32) * invDet;
return true;
}
/// <summary>
/// Linearly interpolates from matrix1 to matrix2, based on the third parameter.
/// </summary>
/// <param name="matrix1">The first source matrix.</param>
/// <param name="matrix2">The second source matrix.</param>
/// <param name="amount">The relative weighting of matrix2.</param>
/// <returns>The interpolated matrix.</returns>
public static Matrix3x2 Lerp(Matrix3x2 matrix1, Matrix3x2 matrix2, double amount)
{
Matrix3x2 result;
// First row
result.M11 = matrix1.M11 + (matrix2.M11 - matrix1.M11) * amount;
result.M12 = matrix1.M12 + (matrix2.M12 - matrix1.M12) * amount;
// Second row
result.M21 = matrix1.M21 + (matrix2.M21 - matrix1.M21) * amount;
result.M22 = matrix1.M22 + (matrix2.M22 - matrix1.M22) * amount;
// Third row
result.M31 = matrix1.M31 + (matrix2.M31 - matrix1.M31) * amount;
result.M32 = matrix1.M32 + (matrix2.M32 - matrix1.M32) * amount;
return result;
}
/// <summary>
/// Negates the given matrix by multiplying all values by -1.
/// </summary>
/// <param name="value">The source matrix.</param>
/// <returns>The negated matrix.</returns>
public static Matrix3x2 Negate(Matrix3x2 value)
{
Matrix3x2 result;
result.M11 = -value.M11;
result.M12 = -value.M12;
result.M21 = -value.M21;
result.M22 = -value.M22;
result.M31 = -value.M31;
result.M32 = -value.M32;
return result;
}
/// <summary>
/// Adds each matrix element in value1 with its corresponding element in value2.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The matrix containing the summed values.</returns>
public static Matrix3x2 Add(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 result;
result.M11 = value1.M11 + value2.M11;
result.M12 = value1.M12 + value2.M12;
result.M21 = value1.M21 + value2.M21;
result.M22 = value1.M22 + value2.M22;
result.M31 = value1.M31 + value2.M31;
result.M32 = value1.M32 + value2.M32;
return result;
}
/// <summary>
/// Subtracts each matrix element in value2 from its corresponding element in value1.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The matrix containing the resulting values.</returns>
public static Matrix3x2 Subtract(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 result;
result.M11 = value1.M11 - value2.M11;
result.M12 = value1.M12 - value2.M12;
result.M21 = value1.M21 - value2.M21;
result.M22 = value1.M22 - value2.M22;
result.M31 = value1.M31 - value2.M31;
result.M32 = value1.M32 - value2.M32;
return result;
}
/// <summary>
/// Multiplies two matrices together and returns the resulting matrix.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The product matrix.</returns>
public static Matrix3x2 Multiply(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 result;
// First row
result.M11 = value1.M11 * value2.M11 + value1.M12 * value2.M21;
result.M12 = value1.M11 * value2.M12 + value1.M12 * value2.M22;
// Second row
result.M21 = value1.M21 * value2.M11 + value1.M22 * value2.M21;
result.M22 = value1.M21 * value2.M12 + value1.M22 * value2.M22;
// Third row
result.M31 = value1.M31 * value2.M11 + value1.M32 * value2.M21 + value2.M31;
result.M32 = value1.M31 * value2.M12 + value1.M32 * value2.M22 + value2.M32;
return result;
}
/// <summary>
/// Scales all elements in a matrix by the given scalar factor.
/// </summary>
/// <param name="value1">The source matrix.</param>
/// <param name="value2">The scaling value to use.</param>
/// <returns>The resulting matrix.</returns>
public static Matrix3x2 Multiply(Matrix3x2 value1, double value2)
{
Matrix3x2 result;
result.M11 = value1.M11 * value2;
result.M12 = value1.M12 * value2;
result.M21 = value1.M21 * value2;
result.M22 = value1.M22 * value2;
result.M31 = value1.M31 * value2;
result.M32 = value1.M32 * value2;
return result;
}
/// <summary>
/// Negates the given matrix by multiplying all values by -1.
/// </summary>
/// <param name="value">The source matrix.</param>
/// <returns>The negated matrix.</returns>
public static Matrix3x2 operator -(Matrix3x2 value)
{
Matrix3x2 m;
m.M11 = -value.M11;
m.M12 = -value.M12;
m.M21 = -value.M21;
m.M22 = -value.M22;
m.M31 = -value.M31;
m.M32 = -value.M32;
return m;
}
/// <summary>
/// Adds each matrix element in value1 with its corresponding element in value2.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The matrix containing the summed values.</returns>
public static Matrix3x2 operator +(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 m;
m.M11 = value1.M11 + value2.M11;
m.M12 = value1.M12 + value2.M12;
m.M21 = value1.M21 + value2.M21;
m.M22 = value1.M22 + value2.M22;
m.M31 = value1.M31 + value2.M31;
m.M32 = value1.M32 + value2.M32;
return m;
}
/// <summary>
/// Subtracts each matrix element in value2 from its corresponding element in value1.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The matrix containing the resulting values.</returns>
public static Matrix3x2 operator -(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 m;
m.M11 = value1.M11 - value2.M11;
m.M12 = value1.M12 - value2.M12;
m.M21 = value1.M21 - value2.M21;
m.M22 = value1.M22 - value2.M22;
m.M31 = value1.M31 - value2.M31;
m.M32 = value1.M32 - value2.M32;
return m;
}
/// <summary>
/// Multiplies two matrices together and returns the resulting matrix.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>The product matrix.</returns>
public static Matrix3x2 operator *(Matrix3x2 value1, Matrix3x2 value2)
{
Matrix3x2 m;
// First row
m.M11 = value1.M11 * value2.M11 + value1.M12 * value2.M21;
m.M12 = value1.M11 * value2.M12 + value1.M12 * value2.M22;
// Second row
m.M21 = value1.M21 * value2.M11 + value1.M22 * value2.M21;
m.M22 = value1.M21 * value2.M12 + value1.M22 * value2.M22;
// Third row
m.M31 = value1.M31 * value2.M11 + value1.M32 * value2.M21 + value2.M31;
m.M32 = value1.M31 * value2.M12 + value1.M32 * value2.M22 + value2.M32;
return m;
}
/// <summary>
/// Scales all elements in a matrix by the given scalar factor.
/// </summary>
/// <param name="value1">The source matrix.</param>
/// <param name="value2">The scaling value to use.</param>
/// <returns>The resulting matrix.</returns>
public static Matrix3x2 operator *(Matrix3x2 value1, double value2)
{
Matrix3x2 m;
m.M11 = value1.M11 * value2;
m.M12 = value1.M12 * value2;
m.M21 = value1.M21 * value2;
m.M22 = value1.M22 * value2;
m.M31 = value1.M31 * value2;
m.M32 = value1.M32 * value2;
return m;
}
/// <summary>
/// Returns a boolean indicating whether the given matrices are equal.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>True if the matrices are equal; False otherwise.</returns>
public static bool operator ==(Matrix3x2 value1, Matrix3x2 value2)
{
return (value1.M11 == value2.M11 && value1.M22 == value2.M22 && // Check diagonal element first for early out.
value1.M12 == value2.M12 &&
value1.M21 == value2.M21 &&
value1.M31 == value2.M31 && value1.M32 == value2.M32);
}
/// <summary>
/// Returns a boolean indicating whether the given matrices are not equal.
/// </summary>
/// <param name="value1">The first source matrix.</param>
/// <param name="value2">The second source matrix.</param>
/// <returns>True if the matrices are not equal; False if they are equal.</returns>
public static bool operator !=(Matrix3x2 value1, Matrix3x2 value2)
{
return (value1.M11 != value2.M11 || value1.M12 != value2.M12 ||
value1.M21 != value2.M21 || value1.M22 != value2.M22 ||
value1.M31 != value2.M31 || value1.M32 != value2.M32);
}
/// <summary>
/// Returns a boolean indicating whether the matrix is equal to the other given matrix.
/// </summary>
/// <param name="other">The other matrix to test equality against.</param>
/// <returns>True if this matrix is equal to other; False otherwise.</returns>
public bool Equals(Matrix3x2 other)
{
return (M11 == other.M11 && M22 == other.M22 && // Check diagonal element first for early out.
M12 == other.M12 &&
M21 == other.M21 &&
M31 == other.M31 && M32 == other.M32);
}
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this matrix instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this matrix; False otherwise.</returns>
public override bool Equals(object obj)
{
if (obj is Matrix3x2)
{
return Equals((Matrix3x2)obj);
}
return false;
}
/// <summary>
/// Returns a String representing this matrix instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
CultureInfo ci = CultureInfo.CurrentCulture;
return String.Format(ci, "{{ {{M11:{0} M12:{1}}} {{M21:{2} M22:{3}}} {{M31:{4} M32:{5}}} }}",
M11.ToString(ci), M12.ToString(ci),
M21.ToString(ci), M22.ToString(ci),
M31.ToString(ci), M32.ToString(ci));
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
return M11.GetHashCode() + M12.GetHashCode() +
M21.GetHashCode() + M22.GetHashCode() +
M31.GetHashCode() + M32.GetHashCode();
}
}
}
File diff suppressed because it is too large Load Diff
-313
View File
@@ -1,313 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Runtime.CompilerServices;
namespace System.DoubleNumerics
{
/// <summary>
/// A structure encapsulating a 3D Plane
/// </summary>
public struct Plane : IEquatable<Plane>
{
/// <summary>
/// The normal vector of the Plane.
/// </summary>
public Vector3 Normal;
/// <summary>
/// The distance of the Plane along its normal from the origin.
/// </summary>
public double D;
/// <summary>
/// Constructs a Plane from the X, Y, and Z components of its normal, and its distance from the origin on that normal.
/// </summary>
/// <param name="x">The X-component of the normal.</param>
/// <param name="y">The Y-component of the normal.</param>
/// <param name="z">The Z-component of the normal.</param>
/// <param name="d">The distance of the Plane along its normal from the origin.</param>
public Plane(double x, double y, double z, double d)
{
Normal = new Vector3(x, y, z);
this.D = d;
}
/// <summary>
/// Constructs a Plane from the given normal and distance along the normal from the origin.
/// </summary>
/// <param name="normal">The Plane's normal vector.</param>
/// <param name="d">The Plane's distance from the origin along its normal vector.</param>
public Plane(Vector3 normal, double d)
{
this.Normal = normal;
this.D = d;
}
/// <summary>
/// Constructs a Plane from the given Vector4.
/// </summary>
/// <param name="value">A vector whose first 3 elements describe the normal vector,
/// and whose W component defines the distance along that normal from the origin.</param>
public Plane(Vector4 value)
{
Normal = new Vector3(value.X, value.Y, value.Z);
D = value.W;
}
/// <summary>
/// Creates a Plane that contains the three given points.
/// </summary>
/// <param name="point1">The first point defining the Plane.</param>
/// <param name="point2">The second point defining the Plane.</param>
/// <param name="point3">The third point defining the Plane.</param>
/// <returns>The Plane containing the three points.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane CreateFromVertices(Vector3 point1, Vector3 point2, Vector3 point3)
{
double ax = point2.X - point1.X;
double ay = point2.Y - point1.Y;
double az = point2.Z - point1.Z;
double bx = point3.X - point1.X;
double by = point3.Y - point1.Y;
double bz = point3.Z - point1.Z;
// N=Cross(a,b)
double nx = ay * bz - az * by;
double ny = az * bx - ax * bz;
double nz = ax * by - ay * bx;
// Normalize(N)
double ls = nx * nx + ny * ny + nz * nz;
double invNorm = 1.0 / (double)Math.Sqrt((double)ls);
Vector3 normal = new Vector3(
nx * invNorm,
ny * invNorm,
nz * invNorm);
return new Plane(
normal,
-(normal.X * point1.X + normal.Y * point1.Y + normal.Z * point1.Z));
}
/// <summary>
/// Creates a new Plane whose normal vector is the source Plane's normal vector normalized.
/// </summary>
/// <param name="value">The source Plane.</param>
/// <returns>The normalized Plane.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane Normalize(Plane value)
{
const double FLT_EPSILON = 1.192092896e-07; // smallest such that 1.0+FLT_EPSILON != 1.0
double f = value.Normal.X * value.Normal.X + value.Normal.Y * value.Normal.Y + value.Normal.Z * value.Normal.Z;
if (Math.Abs(f - 1.0) < FLT_EPSILON)
{
return value; // It already normalized, so we don't need to further process.
}
double fInv = 1.0 / (double)Math.Sqrt(f);
return new Plane(
value.Normal.X * fInv,
value.Normal.Y * fInv,
value.Normal.Z * fInv,
value.D * fInv);
}
/// <summary>
/// Transforms a normalized Plane by a Matrix.
/// </summary>
/// <param name="plane"> The normalized Plane to transform.
/// This Plane must already be normalized, so that its Normal vector is of unit length, before this method is called.</param>
/// <param name="matrix">The transformation matrix to apply to the Plane.</param>
/// <returns>The transformed Plane.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane Transform(Plane plane, Matrix4x4 matrix)
{
Matrix4x4 m;
Matrix4x4.Invert(matrix, out m);
double x = plane.Normal.X, y = plane.Normal.Y, z = plane.Normal.Z, w = plane.D;
return new Plane(
x * m.M11 + y * m.M12 + z * m.M13 + w * m.M14,
x * m.M21 + y * m.M22 + z * m.M23 + w * m.M24,
x * m.M31 + y * m.M32 + z * m.M33 + w * m.M34,
x * m.M41 + y * m.M42 + z * m.M43 + w * m.M44);
}
/// <summary>
/// Transforms a normalized Plane by a Quaternion rotation.
/// </summary>
/// <param name="plane"> The normalized Plane to transform.
/// This Plane must already be normalized, so that its Normal vector is of unit length, before this method is called.</param>
/// <param name="rotation">The Quaternion rotation to apply to the Plane.</param>
/// <returns>A new Plane that results from applying the rotation.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Plane Transform(Plane plane, Quaternion rotation)
{
// Compute rotation matrix.
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wx2 = rotation.W * x2;
double wy2 = rotation.W * y2;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double xz2 = rotation.X * z2;
double yy2 = rotation.Y * y2;
double yz2 = rotation.Y * z2;
double zz2 = rotation.Z * z2;
double m11 = 1.0 - yy2 - zz2;
double m21 = xy2 - wz2;
double m31 = xz2 + wy2;
double m12 = xy2 + wz2;
double m22 = 1.0 - xx2 - zz2;
double m32 = yz2 - wx2;
double m13 = xz2 - wy2;
double m23 = yz2 + wx2;
double m33 = 1.0 - xx2 - yy2;
double x = plane.Normal.X, y = plane.Normal.Y, z = plane.Normal.Z;
return new Plane(
x * m11 + y * m21 + z * m31,
x * m12 + y * m22 + z * m32,
x * m13 + y * m23 + z * m33,
plane.D);
}
/// <summary>
/// Calculates the dot product of a Plane and Vector4.
/// </summary>
/// <param name="plane">The Plane.</param>
/// <param name="value">The Vector4.</param>
/// <returns>The dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Plane plane, Vector4 value)
{
return plane.Normal.X * value.X +
plane.Normal.Y * value.Y +
plane.Normal.Z * value.Z +
plane.D * value.W;
}
/// <summary>
/// Returns the dot product of a specified Vector3 and the normal vector of this Plane plus the distance (D) value of the Plane.
/// </summary>
/// <param name="plane">The plane.</param>
/// <param name="value">The Vector3.</param>
/// <returns>The resulting value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DotCoordinate(Plane plane, Vector3 value)
{
return plane.Normal.X * value.X +
plane.Normal.Y * value.Y +
plane.Normal.Z * value.Z +
plane.D;
}
/// <summary>
/// Returns the dot product of a specified Vector3 and the Normal vector of this Plane.
/// </summary>
/// <param name="plane">The plane.</param>
/// <param name="value">The Vector3.</param>
/// <returns>The resulting dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DotNormal(Plane plane, Vector3 value)
{
return plane.Normal.X * value.X +
plane.Normal.Y * value.Y +
plane.Normal.Z * value.Z;
}
/// <summary>
/// Returns a boolean indicating whether the two given Planes are equal.
/// </summary>
/// <param name="value1">The first Plane to compare.</param>
/// <param name="value2">The second Plane to compare.</param>
/// <returns>True if the Planes are equal; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Plane value1, Plane value2)
{
return (value1.Normal.X == value2.Normal.X &&
value1.Normal.Y == value2.Normal.Y &&
value1.Normal.Z == value2.Normal.Z &&
value1.D == value2.D);
}
/// <summary>
/// Returns a boolean indicating whether the two given Planes are not equal.
/// </summary>
/// <param name="value1">The first Plane to compare.</param>
/// <param name="value2">The second Plane to compare.</param>
/// <returns>True if the Planes are not equal; False if they are equal.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Plane value1, Plane value2)
{
return (value1.Normal.X != value2.Normal.X ||
value1.Normal.Y != value2.Normal.Y ||
value1.Normal.Z != value2.Normal.Z ||
value1.D != value2.D);
}
/// <summary>
/// Returns a boolean indicating whether the given Plane is equal to this Plane instance.
/// </summary>
/// <param name="other">The Plane to compare this instance to.</param>
/// <returns>True if the other Plane is equal to this instance; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Plane other)
{
return (Normal.X == other.Normal.X &&
Normal.Y == other.Normal.Y &&
Normal.Z == other.Normal.Z &&
D == other.D);
}
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this Plane instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this Plane; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (obj is Plane)
{
return Equals((Plane)obj);
}
return false;
}
/// <summary>
/// Returns a String representing this Plane instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
CultureInfo ci = CultureInfo.CurrentCulture;
return String.Format(ci, "{{Normal:{0} D:{1}}}", Normal.ToString(), D.ToString(ci));
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
return Normal.GetHashCode() + D.GetHashCode();
}
}
}
-794
View File
@@ -1,794 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
namespace System.DoubleNumerics
{
/// <summary>
/// A structure encapsulating a four-dimensional vector (x,y,z,w),
/// which is used to efficiently rotate an object about the (x,y,z) vector by the angle theta, where w = cos(theta/2).
/// </summary>
public struct Quaternion : IEquatable<Quaternion>
{
/// <summary>
/// Specifies the X-value of the vector component of the Quaternion.
/// </summary>
public double X;
/// <summary>
/// Specifies the Y-value of the vector component of the Quaternion.
/// </summary>
public double Y;
/// <summary>
/// Specifies the Z-value of the vector component of the Quaternion.
/// </summary>
public double Z;
/// <summary>
/// Specifies the rotation component of the Quaternion.
/// </summary>
public double W;
/// <summary>
/// Returns a Quaternion representing no rotation.
/// </summary>
public static Quaternion Identity
{
get { return new Quaternion(0, 0, 0, 1); }
}
/// <summary>
/// Returns whether the Quaternion is the identity Quaternion.
/// </summary>
public bool IsIdentity
{
get { return X == 0 && Y == 0 && Z == 0 && W == 1; }
}
/// <summary>
/// Constructs a Quaternion from the given components.
/// </summary>
/// <param name="x">The X component of the Quaternion.</param>
/// <param name="y">The Y component of the Quaternion.</param>
/// <param name="z">The Z component of the Quaternion.</param>
/// <param name="w">The W component of the Quaternion.</param>
public Quaternion(double x, double y, double z, double w)
{
this.X = x;
this.Y = y;
this.Z = z;
this.W = w;
}
/// <summary>
/// Constructs a Quaternion from the given vector and rotation parts.
/// </summary>
/// <param name="vectorPart">The vector part of the Quaternion.</param>
/// <param name="scalarPart">The rotation part of the Quaternion.</param>
public Quaternion(Vector3 vectorPart, double scalarPart)
{
X = vectorPart.X;
Y = vectorPart.Y;
Z = vectorPart.Z;
W = scalarPart;
}
/// <summary>
/// Calculates the length of the Quaternion.
/// </summary>
/// <returns>The computed length of the Quaternion.</returns>
public double Length()
{
double ls = X * X + Y * Y + Z * Z + W * W;
return (double)Math.Sqrt((double)ls);
}
/// <summary>
/// Calculates the length squared of the Quaternion. This operation is cheaper than Length().
/// </summary>
/// <returns>The length squared of the Quaternion.</returns>
public double LengthSquared()
{
return X * X + Y * Y + Z * Z + W * W;
}
/// <summary>
/// Divides each component of the Quaternion by the length of the Quaternion.
/// </summary>
/// <param name="value">The source Quaternion.</param>
/// <returns>The normalized Quaternion.</returns>
public static Quaternion Normalize(Quaternion value)
{
Quaternion ans;
double ls = value.X * value.X + value.Y * value.Y + value.Z * value.Z + value.W * value.W;
double invNorm = 1.0 / (double)Math.Sqrt((double)ls);
ans.X = value.X * invNorm;
ans.Y = value.Y * invNorm;
ans.Z = value.Z * invNorm;
ans.W = value.W * invNorm;
return ans;
}
/// <summary>
/// Creates the conjugate of a specified Quaternion.
/// </summary>
/// <param name="value">The Quaternion of which to return the conjugate.</param>
/// <returns>A new Quaternion that is the conjugate of the specified one.</returns>
public static Quaternion Conjugate(Quaternion value)
{
Quaternion ans;
ans.X = -value.X;
ans.Y = -value.Y;
ans.Z = -value.Z;
ans.W = value.W;
return ans;
}
/// <summary>
/// Returns the inverse of a Quaternion.
/// </summary>
/// <param name="value">The source Quaternion.</param>
/// <returns>The inverted Quaternion.</returns>
public static Quaternion Inverse(Quaternion value)
{
// -1 ( a -v )
// q = ( ------------- ------------- )
// ( a^2 + |v|^2 , a^2 + |v|^2 )
Quaternion ans;
double ls = value.X * value.X + value.Y * value.Y + value.Z * value.Z + value.W * value.W;
double invNorm = 1.0 / ls;
ans.X = -value.X * invNorm;
ans.Y = -value.Y * invNorm;
ans.Z = -value.Z * invNorm;
ans.W = value.W * invNorm;
return ans;
}
/// <summary>
/// Creates a Quaternion from a normalized vector axis and an angle to rotate about the vector.
/// </summary>
/// <param name="axis">The unit vector to rotate around.
/// This vector must be normalized before calling this function or the resulting Quaternion will be incorrect.</param>
/// <param name="angle">The angle, in radians, to rotate around the vector.</param>
/// <returns>The created Quaternion.</returns>
public static Quaternion CreateFromAxisAngle(Vector3 axis, double angle)
{
Quaternion ans;
double halfAngle = angle * 0.5;
double s = (double)Math.Sin(halfAngle);
double c = (double)Math.Cos(halfAngle);
ans.X = axis.X * s;
ans.Y = axis.Y * s;
ans.Z = axis.Z * s;
ans.W = c;
return ans;
}
/// <summary>
/// Creates a new Quaternion from the given yaw, pitch, and roll, in radians.
/// </summary>
/// <param name="yaw">The yaw angle, in radians, around the Y-axis.</param>
/// <param name="pitch">The pitch angle, in radians, around the X-axis.</param>
/// <param name="roll">The roll angle, in radians, around the Z-axis.</param>
/// <returns></returns>
public static Quaternion CreateFromYawPitchRoll(double yaw, double pitch, double roll)
{
// Roll first, about axis the object is facing, then
// pitch upward, then yaw to face into the new heading
double sr, cr, sp, cp, sy, cy;
double halfRoll = roll * 0.5;
sr = (double)Math.Sin(halfRoll);
cr = (double)Math.Cos(halfRoll);
double halfPitch = pitch * 0.5;
sp = (double)Math.Sin(halfPitch);
cp = (double)Math.Cos(halfPitch);
double halfYaw = yaw * 0.5;
sy = (double)Math.Sin(halfYaw);
cy = (double)Math.Cos(halfYaw);
Quaternion result;
result.X = cy * sp * cr + sy * cp * sr;
result.Y = sy * cp * cr - cy * sp * sr;
result.Z = cy * cp * sr - sy * sp * cr;
result.W = cy * cp * cr + sy * sp * sr;
return result;
}
/// <summary>
/// Creates a Quaternion from the given rotation matrix.
/// </summary>
/// <param name="matrix">The rotation matrix.</param>
/// <returns>The created Quaternion.</returns>
public static Quaternion CreateFromRotationMatrix(Matrix4x4 matrix)
{
double trace = matrix.M11 + matrix.M22 + matrix.M33;
Quaternion q = new Quaternion();
if (trace > 0.0)
{
double s = (double)Math.Sqrt(trace + 1.0);
q.W = s * 0.5;
s = 0.5 / s;
q.X = (matrix.M23 - matrix.M32) * s;
q.Y = (matrix.M31 - matrix.M13) * s;
q.Z = (matrix.M12 - matrix.M21) * s;
}
else
{
if (matrix.M11 >= matrix.M22 && matrix.M11 >= matrix.M33)
{
double s = (double)Math.Sqrt(1.0 + matrix.M11 - matrix.M22 - matrix.M33);
double invS = 0.5 / s;
q.X = 0.5 * s;
q.Y = (matrix.M12 + matrix.M21) * invS;
q.Z = (matrix.M13 + matrix.M31) * invS;
q.W = (matrix.M23 - matrix.M32) * invS;
}
else if (matrix.M22 > matrix.M33)
{
double s = (double)Math.Sqrt(1.0 + matrix.M22 - matrix.M11 - matrix.M33);
double invS = 0.5 / s;
q.X = (matrix.M21 + matrix.M12) * invS;
q.Y = 0.5 * s;
q.Z = (matrix.M32 + matrix.M23) * invS;
q.W = (matrix.M31 - matrix.M13) * invS;
}
else
{
double s = (double)Math.Sqrt(1.0 + matrix.M33 - matrix.M11 - matrix.M22);
double invS = 0.5 / s;
q.X = (matrix.M31 + matrix.M13) * invS;
q.Y = (matrix.M32 + matrix.M23) * invS;
q.Z = 0.5 * s;
q.W = (matrix.M12 - matrix.M21) * invS;
}
}
return q;
}
/// <summary>
/// Calculates the dot product of two Quaternions.
/// </summary>
/// <param name="quaternion1">The first source Quaternion.</param>
/// <param name="quaternion2">The second source Quaternion.</param>
/// <returns>The dot product of the Quaternions.</returns>
public static double Dot(Quaternion quaternion1, Quaternion quaternion2)
{
return quaternion1.X * quaternion2.X +
quaternion1.Y * quaternion2.Y +
quaternion1.Z * quaternion2.Z +
quaternion1.W * quaternion2.W;
}
/// <summary>
/// Interpolates between two quaternions, using spherical linear interpolation.
/// </summary>
/// <param name="quaternion1">The first source Quaternion.</param>
/// <param name="quaternion2">The second source Quaternion.</param>
/// <param name="amount">The relative weight of the second source Quaternion in the interpolation.</param>
/// <returns>The interpolated Quaternion.</returns>
public static Quaternion Slerp(Quaternion quaternion1, Quaternion quaternion2, double amount)
{
const double epsilon = 1e-6;
double t = amount;
double cosOmega = quaternion1.X * quaternion2.X + quaternion1.Y * quaternion2.Y +
quaternion1.Z * quaternion2.Z + quaternion1.W * quaternion2.W;
bool flip = false;
if (cosOmega < 0.0)
{
flip = true;
cosOmega = -cosOmega;
}
double s1, s2;
if (cosOmega > (1.0 - epsilon))
{
// Too close, do straight linear interpolation.
s1 = 1.0 - t;
s2 = (flip) ? -t : t;
}
else
{
double omega = (double)Math.Acos(cosOmega);
double invSinOmega = (double)(1 / Math.Sin(omega));
s1 = (double)Math.Sin((1.0 - t) * omega) * invSinOmega;
s2 = (flip)
? (double)-Math.Sin(t * omega) * invSinOmega
: (double)Math.Sin(t * omega) * invSinOmega;
}
Quaternion ans;
ans.X = s1 * quaternion1.X + s2 * quaternion2.X;
ans.Y = s1 * quaternion1.Y + s2 * quaternion2.Y;
ans.Z = s1 * quaternion1.Z + s2 * quaternion2.Z;
ans.W = s1 * quaternion1.W + s2 * quaternion2.W;
return ans;
}
/// <summary>
/// Linearly interpolates between two quaternions.
/// </summary>
/// <param name="quaternion1">The first source Quaternion.</param>
/// <param name="quaternion2">The second source Quaternion.</param>
/// <param name="amount">The relative weight of the second source Quaternion in the interpolation.</param>
/// <returns>The interpolated Quaternion.</returns>
public static Quaternion Lerp(Quaternion quaternion1, Quaternion quaternion2, double amount)
{
double t = amount;
double t1 = 1.0 - t;
Quaternion r = new Quaternion();
double dot = quaternion1.X * quaternion2.X + quaternion1.Y * quaternion2.Y +
quaternion1.Z * quaternion2.Z + quaternion1.W * quaternion2.W;
if (dot >= 0.0)
{
r.X = t1 * quaternion1.X + t * quaternion2.X;
r.Y = t1 * quaternion1.Y + t * quaternion2.Y;
r.Z = t1 * quaternion1.Z + t * quaternion2.Z;
r.W = t1 * quaternion1.W + t * quaternion2.W;
}
else
{
r.X = t1 * quaternion1.X - t * quaternion2.X;
r.Y = t1 * quaternion1.Y - t * quaternion2.Y;
r.Z = t1 * quaternion1.Z - t * quaternion2.Z;
r.W = t1 * quaternion1.W - t * quaternion2.W;
}
// Normalize it.
double ls = r.X * r.X + r.Y * r.Y + r.Z * r.Z + r.W * r.W;
double invNorm = 1.0 / (double)Math.Sqrt((double)ls);
r.X *= invNorm;
r.Y *= invNorm;
r.Z *= invNorm;
r.W *= invNorm;
return r;
}
/// <summary>
/// Concatenates two Quaternions; the result represents the value1 rotation followed by the value2 rotation.
/// </summary>
/// <param name="value1">The first Quaternion rotation in the series.</param>
/// <param name="value2">The second Quaternion rotation in the series.</param>
/// <returns>A new Quaternion representing the concatenation of the value1 rotation followed by the value2 rotation.</returns>
public static Quaternion Concatenate(Quaternion value1, Quaternion value2)
{
Quaternion ans;
// Concatenate rotation is actually q2 * q1 instead of q1 * q2.
// So that's why value2 goes q1 and value1 goes q2.
double q1x = value2.X;
double q1y = value2.Y;
double q1z = value2.Z;
double q1w = value2.W;
double q2x = value1.X;
double q2y = value1.Y;
double q2z = value1.Z;
double q2w = value1.W;
// cross(av, bv)
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;
return ans;
}
/// <summary>
/// Flips the sign of each component of the quaternion.
/// </summary>
/// <param name="value">The source Quaternion.</param>
/// <returns>The negated Quaternion.</returns>
public static Quaternion Negate(Quaternion value)
{
Quaternion ans;
ans.X = -value.X;
ans.Y = -value.Y;
ans.Z = -value.Z;
ans.W = -value.W;
return ans;
}
/// <summary>
/// Adds two Quaternions element-by-element.
/// </summary>
/// <param name="value1">The first source Quaternion.</param>
/// <param name="value2">The second source Quaternion.</param>
/// <returns>The result of adding the Quaternions.</returns>
public static Quaternion Add(Quaternion value1, Quaternion value2)
{
Quaternion ans;
ans.X = value1.X + value2.X;
ans.Y = value1.Y + value2.Y;
ans.Z = value1.Z + value2.Z;
ans.W = value1.W + value2.W;
return ans;
}
/// <summary>
/// Subtracts one Quaternion from another.
/// </summary>
/// <param name="value1">The first source Quaternion.</param>
/// <param name="value2">The second Quaternion, to be subtracted from the first.</param>
/// <returns>The result of the subtraction.</returns>
public static Quaternion Subtract(Quaternion value1, Quaternion value2)
{
Quaternion ans;
ans.X = value1.X - value2.X;
ans.Y = value1.Y - value2.Y;
ans.Z = value1.Z - value2.Z;
ans.W = value1.W - value2.W;
return ans;
}
/// <summary>
/// Multiplies two Quaternions together.
/// </summary>
/// <param name="value1">The Quaternion on the left side of the multiplication.</param>
/// <param name="value2">The Quaternion on the right side of the multiplication.</param>
/// <returns>The result of the multiplication.</returns>
public static Quaternion Multiply(Quaternion value1, Quaternion value2)
{
Quaternion ans;
double q1x = value1.X;
double q1y = value1.Y;
double q1z = value1.Z;
double q1w = value1.W;
double q2x = value2.X;
double q2y = value2.Y;
double q2z = value2.Z;
double q2w = value2.W;
// cross(av, bv)
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;
return ans;
}
/// <summary>
/// Multiplies a Quaternion by a scalar value.
/// </summary>
/// <param name="value1">The source Quaternion.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the multiplication.</returns>
public static Quaternion Multiply(Quaternion value1, double value2)
{
Quaternion ans;
ans.X = value1.X * value2;
ans.Y = value1.Y * value2;
ans.Z = value1.Z * value2;
ans.W = value1.W * value2;
return ans;
}
/// <summary>
/// Divides a Quaternion by another Quaternion.
/// </summary>
/// <param name="value1">The source Quaternion.</param>
/// <param name="value2">The divisor.</param>
/// <returns>The result of the division.</returns>
public static Quaternion Divide(Quaternion value1, Quaternion value2)
{
Quaternion ans;
double q1x = value1.X;
double q1y = value1.Y;
double q1z = value1.Z;
double q1w = value1.W;
//-------------------------------------
// Inverse part.
double ls = value2.X * value2.X + value2.Y * value2.Y +
value2.Z * value2.Z + value2.W * value2.W;
double invNorm = 1.0 / ls;
double q2x = -value2.X * invNorm;
double q2y = -value2.Y * invNorm;
double q2z = -value2.Z * invNorm;
double q2w = value2.W * invNorm;
//-------------------------------------
// Multiply part.
// cross(av, bv)
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;
return ans;
}
/// <summary>
/// Flips the sign of each component of the quaternion.
/// </summary>
/// <param name="value">The source Quaternion.</param>
/// <returns>The negated Quaternion.</returns>
public static Quaternion operator -(Quaternion value)
{
Quaternion ans;
ans.X = -value.X;
ans.Y = -value.Y;
ans.Z = -value.Z;
ans.W = -value.W;
return ans;
}
/// <summary>
/// Adds two Quaternions element-by-element.
/// </summary>
/// <param name="value1">The first source Quaternion.</param>
/// <param name="value2">The second source Quaternion.</param>
/// <returns>The result of adding the Quaternions.</returns>
public static Quaternion operator +(Quaternion value1, Quaternion value2)
{
Quaternion ans;
ans.X = value1.X + value2.X;
ans.Y = value1.Y + value2.Y;
ans.Z = value1.Z + value2.Z;
ans.W = value1.W + value2.W;
return ans;
}
/// <summary>
/// Subtracts one Quaternion from another.
/// </summary>
/// <param name="value1">The first source Quaternion.</param>
/// <param name="value2">The second Quaternion, to be subtracted from the first.</param>
/// <returns>The result of the subtraction.</returns>
public static Quaternion operator -(Quaternion value1, Quaternion value2)
{
Quaternion ans;
ans.X = value1.X - value2.X;
ans.Y = value1.Y - value2.Y;
ans.Z = value1.Z - value2.Z;
ans.W = value1.W - value2.W;
return ans;
}
/// <summary>
/// Multiplies two Quaternions together.
/// </summary>
/// <param name="value1">The Quaternion on the left side of the multiplication.</param>
/// <param name="value2">The Quaternion on the right side of the multiplication.</param>
/// <returns>The result of the multiplication.</returns>
public static Quaternion operator *(Quaternion value1, Quaternion value2)
{
Quaternion ans;
double q1x = value1.X;
double q1y = value1.Y;
double q1z = value1.Z;
double q1w = value1.W;
double q2x = value2.X;
double q2y = value2.Y;
double q2z = value2.Z;
double q2w = value2.W;
// cross(av, bv)
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;
return ans;
}
/// <summary>
/// Multiplies a Quaternion by a scalar value.
/// </summary>
/// <param name="value1">The source Quaternion.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the multiplication.</returns>
public static Quaternion operator *(Quaternion value1, double value2)
{
Quaternion ans;
ans.X = value1.X * value2;
ans.Y = value1.Y * value2;
ans.Z = value1.Z * value2;
ans.W = value1.W * value2;
return ans;
}
/// <summary>
/// Divides a Quaternion by another Quaternion.
/// </summary>
/// <param name="value1">The source Quaternion.</param>
/// <param name="value2">The divisor.</param>
/// <returns>The result of the division.</returns>
public static Quaternion operator /(Quaternion value1, Quaternion value2)
{
Quaternion ans;
double q1x = value1.X;
double q1y = value1.Y;
double q1z = value1.Z;
double q1w = value1.W;
//-------------------------------------
// Inverse part.
double ls = value2.X * value2.X + value2.Y * value2.Y +
value2.Z * value2.Z + value2.W * value2.W;
double invNorm = 1.0 / ls;
double q2x = -value2.X * invNorm;
double q2y = -value2.Y * invNorm;
double q2z = -value2.Z * invNorm;
double q2w = value2.W * invNorm;
//-------------------------------------
// Multiply part.
// cross(av, bv)
double cx = q1y * q2z - q1z * q2y;
double cy = q1z * q2x - q1x * q2z;
double cz = q1x * q2y - q1y * q2x;
double dot = q1x * q2x + q1y * q2y + q1z * q2z;
ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;
return ans;
}
/// <summary>
/// Returns a boolean indicating whether the two given Quaternions are equal.
/// </summary>
/// <param name="value1">The first Quaternion to compare.</param>
/// <param name="value2">The second Quaternion to compare.</param>
/// <returns>True if the Quaternions are equal; False otherwise.</returns>
public static bool operator ==(Quaternion value1, Quaternion value2)
{
return (value1.X == value2.X &&
value1.Y == value2.Y &&
value1.Z == value2.Z &&
value1.W == value2.W);
}
/// <summary>
/// Returns a boolean indicating whether the two given Quaternions are not equal.
/// </summary>
/// <param name="value1">The first Quaternion to compare.</param>
/// <param name="value2">The second Quaternion to compare.</param>
/// <returns>True if the Quaternions are not equal; False if they are equal.</returns>
public static bool operator !=(Quaternion value1, Quaternion value2)
{
return (value1.X != value2.X ||
value1.Y != value2.Y ||
value1.Z != value2.Z ||
value1.W != value2.W);
}
/// <summary>
/// Returns a boolean indicating whether the given Quaternion is equal to this Quaternion instance.
/// </summary>
/// <param name="other">The Quaternion to compare this instance to.</param>
/// <returns>True if the other Quaternion is equal to this instance; False otherwise.</returns>
public bool Equals(Quaternion other)
{
return (X == other.X &&
Y == other.Y &&
Z == other.Z &&
W == other.W);
}
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this Quaternion instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this Quaternion; False otherwise.</returns>
public override bool Equals(object obj)
{
if (obj is Quaternion)
{
return Equals((Quaternion)obj);
}
return false;
}
/// <summary>
/// Returns a String representing this Quaternion instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
CultureInfo ci = CultureInfo.CurrentCulture;
return String.Format(ci, "{{X:{0} Y:{1} Z:{2} W:{3}}}", X.ToString(ci), Y.ToString(ci), Z.ToString(ci), W.ToString(ci));
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
return X.GetHashCode() + Y.GetHashCode() + Z.GetHashCode() + W.GetHashCode();
}
}
}
-141
View File
@@ -1,141 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Arg_ArgumentOutOfRangeException" xml:space="preserve">
<value>Index was out of bounds:</value>
</data>
<data name="Arg_ElementsInSourceIsGreaterThanDestination" xml:space="preserve">
<value>Number of elements in source vector is greater than the destination array</value>
</data>
<data name="Arg_MultiDimArrayNotSupported" xml:space="preserve">
<value>Only one-dimensional arrays are supported</value>
</data>
<data name="Arg_NullArgumentNullRef" xml:space="preserve">
<value>The method was called with a null array argument.</value>
</data>
<data name="Arg_RegisterLengthOfRangeException" xml:space="preserve">
<value>length must be less than</value>
</data>
<data name="Arg_TypeNotSupported" xml:space="preserve">
<value>Specified type is not supported</value>
</data>
<data name="Reflection_MethodNotSupported" xml:space="preserve">
<value>Vector&lt;T&gt;.Count cannot be called via reflection when intrinsics are enabled.</value>
</data>
</root>
@@ -1,42 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework>
<PackageId>System.DoubleNumerics</PackageId>
<PackageVersion>3.1.3</PackageVersion>
<Authors>Weingartner</Authors>
<Description>Double version of System.Numerics vector libraries</Description>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageReleaseNotes>Rebuild for release mode</PackageReleaseNotes>
<PackageTags>numerics vector matrix</PackageTags>
<LicenseUrl>https://opensource.org/licenses/MIT</LicenseUrl>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<None Update="ConstantHelper.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>ConstantHelper.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<ItemGroup>
<Compile Update="ConstantHelper.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>ConstantHelper.tt</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
</Project>
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> -->
<ItemGroup>
<Project Include="System.Numerics.Vectors.csproj" />
<Project Include="System.Numerics.Vectors.csproj">
<TargetGroup>net46</TargetGroup>
</Project>
</ItemGroup>
<!-- <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" /> -->
</Project>
File diff suppressed because it is too large Load Diff
-406
View File
@@ -1,406 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Common.System.Numerics.Hashing;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
namespace System.DoubleNumerics
{
/// <summary>
/// A structure encapsulating two single precision floating point values and provides hardware accelerated methods.
/// </summary>
public partial struct Vector2 : IEquatable<Vector2>, IFormattable
{
#region Public Static Properties
/// <summary>
/// Returns the vector (0,0).
/// </summary>
public static Vector2 Zero { get { return new Vector2(); } }
/// <summary>
/// Returns the vector (1,1).
/// </summary>
public static Vector2 One { get { return new Vector2(1.0, 1.0); } }
/// <summary>
/// Returns the vector (1,0).
/// </summary>
public static Vector2 UnitX { get { return new Vector2(1.0, 0.0); } }
/// <summary>
/// Returns the vector (0,1).
/// </summary>
public static Vector2 UnitY { get { return new Vector2(0.0, 1.0); } }
#endregion Public Static Properties
#region Public instance methods
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
int hash = this.X.GetHashCode();
hash = HashHelpers.Combine(hash, this.Y.GetHashCode());
return hash;
}
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this Vector2 instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this Vector2; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (!(obj is Vector2))
return false;
return Equals((Vector2)obj);
}
/// <summary>
/// Returns a String representing this Vector2 instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
return ToString("G", CultureInfo.CurrentCulture);
}
/// <summary>
/// Returns a String representing this Vector2 instance, using the specified format to format individual elements.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string format)
{
return ToString(format, CultureInfo.CurrentCulture);
}
/// <summary>
/// Returns a String representing this Vector2 instance, using the specified format to format individual elements
/// and the given IFormatProvider.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <param name="formatProvider">The format provider to use when formatting elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string format, IFormatProvider formatProvider)
{
StringBuilder sb = new StringBuilder();
string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
sb.Append('<');
sb.Append(this.X.ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(this.Y.ToString(format, formatProvider));
sb.Append('>');
return sb.ToString();
}
/// <summary>
/// Returns the length of the vector.
/// </summary>
/// <returns>The vector's length.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Length()
{
double ls = X * X + Y * Y;
return (double)Math.Sqrt((double)ls);
}
/// <summary>
/// Returns the length of the vector squared. This operation is cheaper than Length().
/// </summary>
/// <returns>The vector's length squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double LengthSquared()
{
return X * X + Y * Y;
}
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the Euclidean distance between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Distance(Vector2 value1, Vector2 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double ls = dx * dx + dy * dy;
return (double)Math.Sqrt((double)ls);
}
/// <summary>
/// Returns the Euclidean distance squared between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DistanceSquared(Vector2 value1, Vector2 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
return dx * dx + dy * dy;
}
/// <summary>
/// Returns a vector with the same direction as the given vector, but with a length of 1.
/// </summary>
/// <param name="value">The vector to normalize.</param>
/// <returns>The normalized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Normalize(Vector2 value)
{
double ls = value.X * value.X + value.Y * value.Y;
double invNorm = 1.0 / (double)Math.Sqrt((double)ls);
return new Vector2(
value.X * invNorm,
value.Y * invNorm);
}
/// <summary>
/// Returns the reflection of a vector off a surface that has the specified normal.
/// </summary>
/// <param name="vector">The source vector.</param>
/// <param name="normal">The normal of the surface being reflected off.</param>
/// <returns>The reflected vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Reflect(Vector2 vector, Vector2 normal)
{
double dot = vector.X * normal.X + vector.Y * normal.Y;
return new Vector2(
vector.X - 2.0 * dot * normal.X,
vector.Y - 2.0 * dot * normal.Y);
}
/// <summary>
/// Restricts a vector between a min and max value.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max)
{
// This compare order is very important!!!
// We must follow HLSL behavior in the case user specified min value is bigger than max value.
double x = value1.X;
x = (x > max.X) ? max.X : x;
x = (x < min.X) ? min.X : x;
double y = value1.Y;
y = (y > max.Y) ? max.Y : y;
y = (y < min.Y) ? min.Y : y;
return new Vector2(x, y);
}
/// <summary>
/// Linearly interpolates between two vectors based on the given weighting.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <param name="amount">Value between 0 and 1 indicating the weight of the second source vector.</param>
/// <returns>The interpolated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Lerp(Vector2 value1, Vector2 value2, double amount)
{
return new Vector2(
value1.X + (value2.X - value1.X) * amount,
value1.Y + (value2.Y - value1.Y) * amount);
}
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="position">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Transform(Vector2 position, Matrix3x2 matrix)
{
return new Vector2(
position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M31,
position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M32);
}
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="position">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Transform(Vector2 position, Matrix4x4 matrix)
{
return new Vector2(
position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M41,
position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M42);
}
/// <summary>
/// Transforms a vector normal by the given matrix.
/// </summary>
/// <param name="normal">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 TransformNormal(Vector2 normal, Matrix3x2 matrix)
{
return new Vector2(
normal.X * matrix.M11 + normal.Y * matrix.M21,
normal.X * matrix.M12 + normal.Y * matrix.M22);
}
/// <summary>
/// Transforms a vector normal by the given matrix.
/// </summary>
/// <param name="normal">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 TransformNormal(Vector2 normal, Matrix4x4 matrix)
{
return new Vector2(
normal.X * matrix.M11 + normal.Y * matrix.M21,
normal.X * matrix.M12 + normal.Y * matrix.M22);
}
/// <summary>
/// Transforms a vector by the given Quaternion rotation value.
/// </summary>
/// <param name="value">The source vector to be rotated.</param>
/// <param name="rotation">The rotation to apply.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Transform(Vector2 value, Quaternion rotation)
{
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double yy2 = rotation.Y * y2;
double zz2 = rotation.Z * z2;
return new Vector2(
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2),
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2));
}
#endregion Public Static Methods
#region Public operator methods
// all the below methods should be inlined as they are
// implemented over JIT intrinsics
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Add(Vector2 left, Vector2 right)
{
return left + right;
}
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Subtract(Vector2 left, Vector2 right)
{
return left - right;
}
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Multiply(Vector2 left, Vector2 right)
{
return left * right;
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Multiply(Vector2 left, Double right)
{
return left * right;
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Multiply(Double left, Vector2 right)
{
return left * right;
}
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Divide(Vector2 left, Vector2 right)
{
return left / right;
}
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="divisor">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Divide(Vector2 left, Double divisor)
{
return left / divisor;
}
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Negate(Vector2 value)
{
return -value;
}
#endregion Public operator methods
}
}
-282
View File
@@ -1,282 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
namespace System.DoubleNumerics
{
// This file contains the definitions for all of the JIT intrinsic methods and properties that are recognized by the current x64 JIT compiler.
// The implementation defined here is used in any circumstance where the JIT fails to recognize these members as intrinsic.
// The JIT recognizes these methods and properties by name and signature: if either is changed, the JIT will no longer recognize the member.
// Some methods declared here are not strictly intrinsic, but delegate to an intrinsic method. For example, only one overload of CopyTo()
public partial struct Vector2
{
/// <summary>
/// The X component of the vector.
/// </summary>
public Double X;
/// <summary>
/// The Y component of the vector.
/// </summary>
public Double Y;
#region Constructors
/// <summary>
/// Constructs a vector whose elements are all the single specified value.
/// </summary>
/// <param name="value">The element to fill the vector with.</param>
public Vector2(Double value) : this(value, value) { }
/// <summary>
/// Constructs a vector with the given individual elements.
/// </summary>
/// <param name="x">The X component.</param>
/// <param name="y">The Y component.</param>
public Vector2(Double x, Double y)
{
X = x;
Y = y;
}
#endregion Constructors
#region Public Instance Methods
/// <summary>
/// Copies the contents of the vector into the given array.
/// </summary>
/// <param name="array">The destination array.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Double[] array)
{
CopyTo(array, 0);
}
/// <summary>
/// Copies the contents of the vector into the given array, starting from the given index.
/// </summary>
/// <exception cref="ArgumentNullException">If array is null.</exception>
/// <exception cref="RankException">If array is multidimensional.</exception>
/// <exception cref="ArgumentOutOfRangeException">If index is greater than end of the array or index is less than zero.</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array
/// or if there are not enough elements to copy.</exception>
public void CopyTo(Double[] array, int index)
{
if (array == null)
{
// Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull.
throw new NullReferenceException(Strings.Arg_NullArgumentNullRef);
}
if (index < 0 || index >= array.Length)
{
throw new ArgumentOutOfRangeException(nameof(index), String.Format(Strings.Arg_ArgumentOutOfRangeException, index));
}
if ((array.Length - index) < 2)
{
throw new ArgumentException(String.Format(Strings.Arg_ElementsInSourceIsGreaterThanDestination, index));
}
array[index] = X;
array[index + 1] = Y;
}
/// <summary>
/// Returns a boolean indicating whether the given Vector2 is equal to this Vector2 instance.
/// </summary>
/// <param name="other">The Vector2 to compare this instance to.</param>
/// <returns>True if the other Vector2 is equal to this instance; False otherwise.</returns>
public bool Equals(Vector2 other)
{
return this.X == other.X && this.Y == other.Y;
}
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the dot product of two vectors.
/// </summary>
/// <param name="value1">The first vector.</param>
/// <param name="value2">The second vector.</param>
/// <returns>The dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Vector2 value1, Vector2 value2)
{
return value1.X * value2.X +
value1.Y * value2.Y;
}
/// <summary>
/// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The minimized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Min(Vector2 value1, Vector2 value2)
{
return new Vector2(
(value1.X < value2.X) ? value1.X : value2.X,
(value1.Y < value2.Y) ? value1.Y : value2.Y);
}
/// <summary>
/// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors
/// </summary>
/// <param name="value1">The first source vector</param>
/// <param name="value2">The second source vector</param>
/// <returns>The maximized vector</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Max(Vector2 value1, Vector2 value2)
{
return new Vector2(
(value1.X > value2.X) ? value1.X : value2.X,
(value1.Y > value2.Y) ? value1.Y : value2.Y);
}
/// <summary>
/// Returns a vector whose elements are the absolute values of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The absolute value vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Abs(Vector2 value)
{
return new Vector2(Math.Abs(value.X), Math.Abs(value.Y));
}
/// <summary>
/// Returns a vector whose elements are the square root of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The square root vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 SquareRoot(Vector2 value)
{
return new Vector2((Double)Math.Sqrt(value.X), (Double)Math.Sqrt(value.Y));
}
#endregion Public Static Methods
#region Public Static Operators
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator +(Vector2 left, Vector2 right)
{
return new Vector2(left.X + right.X, left.Y + right.Y);
}
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator -(Vector2 left, Vector2 right)
{
return new Vector2(left.X - right.X, left.Y - right.Y);
}
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(Vector2 left, Vector2 right)
{
return new Vector2(left.X * right.X, left.Y * right.Y);
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(Double left, Vector2 right)
{
return new Vector2(left, left) * right;
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(Vector2 left, Double right)
{
return left * new Vector2(right, right);
}
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator /(Vector2 left, Vector2 right)
{
return new Vector2(left.X / right.X, left.Y / right.Y);
}
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator /(Vector2 value1, double value2)
{
double invDiv = 1.0 / value2;
return new Vector2(
value1.X * invDiv,
value1.Y * invDiv);
}
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator -(Vector2 value)
{
return Zero - value;
}
/// <summary>
/// Returns a boolean indicating whether the two given vectors are equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are equal; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector2 left, Vector2 right)
{
return left.Equals(right);
}
/// <summary>
/// Returns a boolean indicating whether the two given vectors are not equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are not equal; False if they are equal.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vector2 left, Vector2 right)
{
return !(left == right);
}
#endregion Public Static Operators
}
}
-415
View File
@@ -1,415 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Common.System.Numerics.Hashing;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
namespace System.DoubleNumerics
{
/// <summary>
/// A structure encapsulating three single precision floating point values and provides hardware accelerated methods.
/// </summary>
public partial struct Vector3 : IEquatable<Vector3>, IFormattable
{
#region Public Static Properties
/// <summary>
/// Returns the vector (0,0,0).
/// </summary>
public static Vector3 Zero { get { return new Vector3(); } }
/// <summary>
/// Returns the vector (1,1,1).
/// </summary>
public static Vector3 One { get { return new Vector3(1.0, 1.0, 1.0); } }
/// <summary>
/// Returns the vector (1,0,0).
/// </summary>
public static Vector3 UnitX { get { return new Vector3(1.0, 0.0, 0.0); } }
/// <summary>
/// Returns the vector (0,1,0).
/// </summary>
public static Vector3 UnitY { get { return new Vector3(0.0, 1.0, 0.0); } }
/// <summary>
/// Returns the vector (0,0,1).
/// </summary>
public static Vector3 UnitZ { get { return new Vector3(0.0, 0.0, 1.0); } }
#endregion Public Static Properties
#region Public Instance Methods
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
int hash = this.X.GetHashCode();
hash = HashHelpers.Combine(hash, this.Y.GetHashCode());
hash = HashHelpers.Combine(hash, this.Z.GetHashCode());
return hash;
}
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this Vector3 instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this Vector3; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (!(obj is Vector3))
return false;
return Equals((Vector3)obj);
}
/// <summary>
/// Returns a String representing this Vector3 instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
return ToString("G", CultureInfo.CurrentCulture);
}
/// <summary>
/// Returns a String representing this Vector3 instance, using the specified format to format individual elements.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string format)
{
return ToString(format, CultureInfo.CurrentCulture);
}
/// <summary>
/// Returns a String representing this Vector3 instance, using the specified format to format individual elements
/// and the given IFormatProvider.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <param name="formatProvider">The format provider to use when formatting elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string format, IFormatProvider formatProvider)
{
StringBuilder sb = new StringBuilder();
string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
sb.Append('<');
sb.Append(((IFormattable)this.X).ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(((IFormattable)this.Y).ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(((IFormattable)this.Z).ToString(format, formatProvider));
sb.Append('>');
return sb.ToString();
}
/// <summary>
/// Returns the length of the vector.
/// </summary>
/// <returns>The vector's length.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Length()
{
double ls = X * X + Y * Y + Z * Z;
return (double)global::System.Math.Sqrt(ls);
}
/// <summary>
/// Returns the length of the vector squared. This operation is cheaper than Length().
/// </summary>
/// <returns>The vector's length squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double LengthSquared()
{
return X * X + Y * Y + Z * Z;
}
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the Euclidean distance between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Distance(Vector3 value1, Vector3 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double dz = value1.Z - value2.Z;
double ls = dx * dx + dy * dy + dz * dz;
return (double)global::System.Math.Sqrt((double)ls);
}
/// <summary>
/// Returns the Euclidean distance squared between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DistanceSquared(Vector3 value1, Vector3 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double dz = value1.Z - value2.Z;
return dx * dx + dy * dy + dz * dz;
}
/// <summary>
/// Returns a vector with the same direction as the given vector, but with a length of 1.
/// </summary>
/// <param name="value">The vector to normalize.</param>
/// <returns>The normalized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Normalize(Vector3 value)
{
double ls = value.X * value.X + value.Y * value.Y + value.Z * value.Z;
double length = (double)global::System.Math.Sqrt(ls);
return new Vector3(value.X / length, value.Y / length, value.Z / length);
}
/// <summary>
/// Computes the cross product of two vectors.
/// </summary>
/// <param name="vector1">The first vector.</param>
/// <param name="vector2">The second vector.</param>
/// <returns>The cross product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Cross(Vector3 vector1, Vector3 vector2)
{
return new Vector3(
vector1.Y * vector2.Z - vector1.Z * vector2.Y,
vector1.Z * vector2.X - vector1.X * vector2.Z,
vector1.X * vector2.Y - vector1.Y * vector2.X);
}
/// <summary>
/// Returns the reflection of a vector off a surface that has the specified normal.
/// </summary>
/// <param name="vector">The source vector.</param>
/// <param name="normal">The normal of the surface being reflected off.</param>
/// <returns>The reflected vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Reflect(Vector3 vector, Vector3 normal)
{
double dot = vector.X * normal.X + vector.Y * normal.Y + vector.Z * normal.Z;
double tempX = normal.X * dot * 2;
double tempY = normal.Y * dot * 2;
double tempZ = normal.Z * dot * 2;
return new Vector3(vector.X - tempX, vector.Y - tempY, vector.Z - tempZ);
}
/// <summary>
/// Restricts a vector between a min and max value.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <returns>The restricted vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max)
{
// This compare order is very important!!!
// We must follow HLSL behavior in the case user specified min value is bigger than max value.
double x = value1.X;
x = (x > max.X) ? max.X : x;
x = (x < min.X) ? min.X : x;
double y = value1.Y;
y = (y > max.Y) ? max.Y : y;
y = (y < min.Y) ? min.Y : y;
double z = value1.Z;
z = (z > max.Z) ? max.Z : z;
z = (z < min.Z) ? min.Z : z;
return new Vector3(x, y, z);
}
/// <summary>
/// Linearly interpolates between two vectors based on the given weighting.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <param name="amount">Value between 0 and 1 indicating the weight of the second source vector.</param>
/// <returns>The interpolated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Lerp(Vector3 value1, Vector3 value2, double amount)
{
return new Vector3(
value1.X + (value2.X - value1.X) * amount,
value1.Y + (value2.Y - value1.Y) * amount,
value1.Z + (value2.Z - value1.Z) * amount);
}
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="position">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Transform(Vector3 position, Matrix4x4 matrix)
{
return new Vector3(
position.X * matrix.M11 + position.Y * matrix.M21 + position.Z * matrix.M31 + matrix.M41,
position.X * matrix.M12 + position.Y * matrix.M22 + position.Z * matrix.M32 + matrix.M42,
position.X * matrix.M13 + position.Y * matrix.M23 + position.Z * matrix.M33 + matrix.M43);
}
/// <summary>
/// Transforms a vector normal by the given matrix.
/// </summary>
/// <param name="normal">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 TransformNormal(Vector3 normal, Matrix4x4 matrix)
{
return new Vector3(
normal.X * matrix.M11 + normal.Y * matrix.M21 + normal.Z * matrix.M31,
normal.X * matrix.M12 + normal.Y * matrix.M22 + normal.Z * matrix.M32,
normal.X * matrix.M13 + normal.Y * matrix.M23 + normal.Z * matrix.M33);
}
/// <summary>
/// Transforms a vector by the given Quaternion rotation value.
/// </summary>
/// <param name="value">The source vector to be rotated.</param>
/// <param name="rotation">The rotation to apply.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Transform(Vector3 value, Quaternion rotation)
{
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wx2 = rotation.W * x2;
double wy2 = rotation.W * y2;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double xz2 = rotation.X * z2;
double yy2 = rotation.Y * y2;
double yz2 = rotation.Y * z2;
double zz2 = rotation.Z * z2;
return new Vector3(
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2),
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2) + value.Z * (yz2 - wx2),
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2) + value.Z * (1.0 - xx2 - yy2));
}
#endregion Public Static Methods
#region Public operator methods
// All these methods should be inlined as they are implemented
// over JIT intrinsics
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Add(Vector3 left, Vector3 right)
{
return left + right;
}
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Subtract(Vector3 left, Vector3 right)
{
return left - right;
}
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Multiply(Vector3 left, Vector3 right)
{
return left * right;
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Multiply(Vector3 left, Double right)
{
return left * right;
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Multiply(Double left, Vector3 right)
{
return left * right;
}
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Divide(Vector3 left, Vector3 right)
{
return left / right;
}
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="divisor">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Divide(Vector3 left, Double divisor)
{
return left / divisor;
}
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Negate(Vector3 value)
{
return -value;
}
#endregion Public operator methods
}
}
-306
View File
@@ -1,306 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
namespace System.DoubleNumerics
{
// This file contains the definitions for all of the JIT intrinsic methods and properties that are recognized by the current x64 JIT compiler.
// The implementation defined here is used in any circumstance where the JIT fails to recognize these members as intrinsic.
// The JIT recognizes these methods and properties by name and signature: if either is changed, the JIT will no longer recognize the member.
// Some methods declared here are not strictly intrinsic, but delegate to an intrinsic method. For example, only one overload of CopyTo()
// is actually recognized by the JIT, but both are here for simplicity.
public partial struct Vector3
{
/// <summary>
/// The X component of the vector.
/// </summary>
public Double X;
/// <summary>
/// The Y component of the vector.
/// </summary>
public Double Y;
/// <summary>
/// The Z component of the vector.
/// </summary>
public Double Z;
#region Constructors
/// <summary>
/// Constructs a vector whose elements are all the single specified value.
/// </summary>
/// <param name="value">The element to fill the vector with.</param>
public Vector3(Double value) : this(value, value, value) { }
/// <summary>
/// Constructs a Vector3 from the given Vector2 and a third value.
/// </summary>
/// <param name="value">The Vector to extract X and Y components from.</param>
/// <param name="z">The Z component.</param>
public Vector3(Vector2 value, double z) : this(value.X, value.Y, z) { }
/// <summary>
/// Constructs a vector with the given individual elements.
/// </summary>
/// <param name="x">The X component.</param>
/// <param name="y">The Y component.</param>
/// <param name="z">The Z component.</param>
public Vector3(Double x, Double y, Double z)
{
X = x;
Y = y;
Z = z;
}
#endregion Constructors
#region Public Instance Methods
/// <summary>
/// Copies the contents of the vector into the given array.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Double[] array)
{
CopyTo(array, 0);
}
/// <summary>
/// Copies the contents of the vector into the given array, starting from index.
/// </summary>
/// <exception cref="ArgumentNullException">If array is null.</exception>
/// <exception cref="RankException">If array is multidimensional.</exception>
/// <exception cref="ArgumentOutOfRangeException">If index is greater than end of the array or index is less than zero.</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Double[] array, int index)
{
if (array == null)
{
// Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull.
throw new NullReferenceException(Strings.Arg_NullArgumentNullRef);
}
if (index < 0 || index >= array.Length)
{
throw new ArgumentOutOfRangeException(nameof(index), String.Format(Strings.Arg_ArgumentOutOfRangeException, index));
}
if ((array.Length - index) < 3)
{
throw new ArgumentException(String.Format(Strings.Arg_ElementsInSourceIsGreaterThanDestination, index));
}
array[index] = X;
array[index + 1] = Y;
array[index + 2] = Z;
}
/// <summary>
/// Returns a boolean indicating whether the given Vector3 is equal to this Vector3 instance.
/// </summary>
/// <param name="other">The Vector3 to compare this instance to.</param>
/// <returns>True if the other Vector3 is equal to this instance; False otherwise.</returns>
public bool Equals(Vector3 other)
{
return X == other.X &&
Y == other.Y &&
Z == other.Z;
}
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the dot product of two vectors.
/// </summary>
/// <param name="vector1">The first vector.</param>
/// <param name="vector2">The second vector.</param>
/// <returns>The dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Vector3 vector1, Vector3 vector2)
{
return vector1.X * vector2.X +
vector1.Y * vector2.Y +
vector1.Z * vector2.Z;
}
/// <summary>
/// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The minimized vector.</returns>
public static Vector3 Min(Vector3 value1, Vector3 value2)
{
return new Vector3(
(value1.X < value2.X) ? value1.X : value2.X,
(value1.Y < value2.Y) ? value1.Y : value2.Y,
(value1.Z < value2.Z) ? value1.Z : value2.Z);
}
/// <summary>
/// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The maximized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Max(Vector3 value1, Vector3 value2)
{
return new Vector3(
(value1.X > value2.X) ? value1.X : value2.X,
(value1.Y > value2.Y) ? value1.Y : value2.Y,
(value1.Z > value2.Z) ? value1.Z : value2.Z);
}
/// <summary>
/// Returns a vector whose elements are the absolute values of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The absolute value vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Abs(Vector3 value)
{
return new Vector3(Math.Abs(value.X), Math.Abs(value.Y), Math.Abs(value.Z));
}
/// <summary>
/// Returns a vector whose elements are the square root of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The square root vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 SquareRoot(Vector3 value)
{
return new Vector3((Double)Math.Sqrt(value.X), (Double)Math.Sqrt(value.Y), (Double)Math.Sqrt(value.Z));
}
#endregion Public Static Methods
#region Public Static Operators
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator +(Vector3 left, Vector3 right)
{
return new Vector3(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
}
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator -(Vector3 left, Vector3 right)
{
return new Vector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
}
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(Vector3 left, Vector3 right)
{
return new Vector3(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(Vector3 left, Double right)
{
return left * new Vector3(right);
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(Double left, Vector3 right)
{
return new Vector3(left) * right;
}
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator /(Vector3 left, Vector3 right)
{
return new Vector3(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
}
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator /(Vector3 value1, double value2)
{
double invDiv = 1.0 / value2;
return new Vector3(
value1.X * invDiv,
value1.Y * invDiv,
value1.Z * invDiv);
}
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator -(Vector3 value)
{
return Zero - value;
}
/// <summary>
/// Returns a boolean indicating whether the two given vectors are equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are equal; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector3 left, Vector3 right)
{
return (left.X == right.X &&
left.Y == right.Y &&
left.Z == right.Z);
}
/// <summary>
/// Returns a boolean indicating whether the two given vectors are not equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are not equal; False if they are equal.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vector3 left, Vector3 right)
{
return (left.X != right.X ||
left.Y != right.Y ||
left.Z != right.Z);
}
#endregion Public Static Operators
}
}
-482
View File
@@ -1,482 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Common.System.Numerics.Hashing;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
namespace System.DoubleNumerics
{
/// <summary>
/// A structure encapsulating four single precision floating point values and provides hardware accelerated methods.
/// </summary>
public partial struct Vector4 : IEquatable<Vector4>, IFormattable
{
#region Public Static Properties
/// <summary>
/// Returns the vector (0,0,0,0).
/// </summary>
public static Vector4 Zero { get { return new Vector4(); } }
/// <summary>
/// Returns the vector (1,1,1,1).
/// </summary>
public static Vector4 One { get { return new Vector4(1.0, 1.0, 1.0, 1.0); } }
/// <summary>
/// Returns the vector (1,0,0,0).
/// </summary>
public static Vector4 UnitX { get { return new Vector4(1.0, 0.0, 0.0, 0.0); } }
/// <summary>
/// Returns the vector (0,1,0,0).
/// </summary>
public static Vector4 UnitY { get { return new Vector4(0.0, 1.0, 0.0, 0.0); } }
/// <summary>
/// Returns the vector (0,0,1,0).
/// </summary>
public static Vector4 UnitZ { get { return new Vector4(0.0, 0.0, 1.0, 0.0); } }
/// <summary>
/// Returns the vector (0,0,0,1).
/// </summary>
public static Vector4 UnitW { get { return new Vector4(0.0, 0.0, 0.0, 1.0); } }
#endregion Public Static Properties
#region Public instance methods
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
int hash = this.X.GetHashCode();
hash = HashHelpers.Combine(hash, this.Y.GetHashCode());
hash = HashHelpers.Combine(hash, this.Z.GetHashCode());
hash = HashHelpers.Combine(hash, this.W.GetHashCode());
return hash;
}
/// <summary>
/// Returns a boolean indicating whether the given Object is equal to this Vector4 instance.
/// </summary>
/// <param name="obj">The Object to compare against.</param>
/// <returns>True if the Object is equal to this Vector4; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
if (!(obj is Vector4))
return false;
return Equals((Vector4)obj);
}
/// <summary>
/// Returns a String representing this Vector4 instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
return ToString("G", CultureInfo.CurrentCulture);
}
/// <summary>
/// Returns a String representing this Vector4 instance, using the specified format to format individual elements.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string format)
{
return ToString(format, CultureInfo.CurrentCulture);
}
/// <summary>
/// Returns a String representing this Vector4 instance, using the specified format to format individual elements
/// and the given IFormatProvider.
/// </summary>
/// <param name="format">The format of individual elements.</param>
/// <param name="formatProvider">The format provider to use when formatting elements.</param>
/// <returns>The string representation.</returns>
public string ToString(string format, IFormatProvider formatProvider)
{
StringBuilder sb = new StringBuilder();
string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
sb.Append('<');
sb.Append(this.X.ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(this.Y.ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(this.Z.ToString(format, formatProvider));
sb.Append(separator);
sb.Append(' ');
sb.Append(this.W.ToString(format, formatProvider));
sb.Append('>');
return sb.ToString();
}
/// <summary>
/// Returns the length of the vector. This operation is cheaper than Length().
/// </summary>
/// <returns>The vector's length.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double Length()
{
double ls = X * X + Y * Y + Z * Z + W * W;
return (double)Math.Sqrt((double)ls);
}
/// <summary>
/// Returns the length of the vector squared.
/// </summary>
/// <returns>The vector's length squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double LengthSquared()
{
return X * X + Y * Y + Z * Z + W * W;
}
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the Euclidean distance between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Distance(Vector4 value1, Vector4 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double dz = value1.Z - value2.Z;
double dw = value1.W - value2.W;
double ls = dx * dx + dy * dy + dz * dz + dw * dw;
return (double)Math.Sqrt((double)ls);
}
/// <summary>
/// Returns the Euclidean distance squared between the two given points.
/// </summary>
/// <param name="value1">The first point.</param>
/// <param name="value2">The second point.</param>
/// <returns>The distance squared.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double DistanceSquared(Vector4 value1, Vector4 value2)
{
double dx = value1.X - value2.X;
double dy = value1.Y - value2.Y;
double dz = value1.Z - value2.Z;
double dw = value1.W - value2.W;
return dx * dx + dy * dy + dz * dz + dw * dw;
}
/// <summary>
/// Returns a vector with the same direction as the given vector, but with a length of 1.
/// </summary>
/// <param name="vector">The vector to normalize.</param>
/// <returns>The normalized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Normalize(Vector4 vector)
{
double ls = vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z + vector.W * vector.W;
double invNorm = 1.0 / (double)Math.Sqrt((double)ls);
return new Vector4(
vector.X * invNorm,
vector.Y * invNorm,
vector.Z * invNorm,
vector.W * invNorm);
}
/// <summary>
/// Restricts a vector between a min and max value.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <returns>The restricted vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Clamp(Vector4 value1, Vector4 min, Vector4 max)
{
// This compare order is very important!!!
// We must follow HLSL behavior in the case user specified min value is bigger than max value.
double x = value1.X;
x = (x > max.X) ? max.X : x;
x = (x < min.X) ? min.X : x;
double y = value1.Y;
y = (y > max.Y) ? max.Y : y;
y = (y < min.Y) ? min.Y : y;
double z = value1.Z;
z = (z > max.Z) ? max.Z : z;
z = (z < min.Z) ? min.Z : z;
double w = value1.W;
w = (w > max.W) ? max.W : w;
w = (w < min.W) ? min.W : w;
return new Vector4(x, y, z, w);
}
/// <summary>
/// Linearly interpolates between two vectors based on the given weighting.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <param name="amount">Value between 0 and 1 indicating the weight of the second source vector.</param>
/// <returns>The interpolated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Lerp(Vector4 value1, Vector4 value2, double amount)
{
return new Vector4(
value1.X + (value2.X - value1.X) * amount,
value1.Y + (value2.Y - value1.Y) * amount,
value1.Z + (value2.Z - value1.Z) * amount,
value1.W + (value2.W - value1.W) * amount);
}
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="position">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector2 position, Matrix4x4 matrix)
{
return new Vector4(
position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M41,
position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M42,
position.X * matrix.M13 + position.Y * matrix.M23 + matrix.M43,
position.X * matrix.M14 + position.Y * matrix.M24 + matrix.M44);
}
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="position">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector3 position, Matrix4x4 matrix)
{
return new Vector4(
position.X * matrix.M11 + position.Y * matrix.M21 + position.Z * matrix.M31 + matrix.M41,
position.X * matrix.M12 + position.Y * matrix.M22 + position.Z * matrix.M32 + matrix.M42,
position.X * matrix.M13 + position.Y * matrix.M23 + position.Z * matrix.M33 + matrix.M43,
position.X * matrix.M14 + position.Y * matrix.M24 + position.Z * matrix.M34 + matrix.M44);
}
/// <summary>
/// Transforms a vector by the given matrix.
/// </summary>
/// <param name="vector">The source vector.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector4 vector, Matrix4x4 matrix)
{
return new Vector4(
vector.X * matrix.M11 + vector.Y * matrix.M21 + vector.Z * matrix.M31 + vector.W * matrix.M41,
vector.X * matrix.M12 + vector.Y * matrix.M22 + vector.Z * matrix.M32 + vector.W * matrix.M42,
vector.X * matrix.M13 + vector.Y * matrix.M23 + vector.Z * matrix.M33 + vector.W * matrix.M43,
vector.X * matrix.M14 + vector.Y * matrix.M24 + vector.Z * matrix.M34 + vector.W * matrix.M44);
}
/// <summary>
/// Transforms a vector by the given Quaternion rotation value.
/// </summary>
/// <param name="value">The source vector to be rotated.</param>
/// <param name="rotation">The rotation to apply.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector2 value, Quaternion rotation)
{
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wx2 = rotation.W * x2;
double wy2 = rotation.W * y2;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double xz2 = rotation.X * z2;
double yy2 = rotation.Y * y2;
double yz2 = rotation.Y * z2;
double zz2 = rotation.Z * z2;
return new Vector4(
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2),
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2),
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2),
1.0);
}
/// <summary>
/// Transforms a vector by the given Quaternion rotation value.
/// </summary>
/// <param name="value">The source vector to be rotated.</param>
/// <param name="rotation">The rotation to apply.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector3 value, Quaternion rotation)
{
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wx2 = rotation.W * x2;
double wy2 = rotation.W * y2;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double xz2 = rotation.X * z2;
double yy2 = rotation.Y * y2;
double yz2 = rotation.Y * z2;
double zz2 = rotation.Z * z2;
return new Vector4(
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2),
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2) + value.Z * (yz2 - wx2),
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2) + value.Z * (1.0 - xx2 - yy2),
1.0);
}
/// <summary>
/// Transforms a vector by the given Quaternion rotation value.
/// </summary>
/// <param name="value">The source vector to be rotated.</param>
/// <param name="rotation">The rotation to apply.</param>
/// <returns>The transformed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Transform(Vector4 value, Quaternion rotation)
{
double x2 = rotation.X + rotation.X;
double y2 = rotation.Y + rotation.Y;
double z2 = rotation.Z + rotation.Z;
double wx2 = rotation.W * x2;
double wy2 = rotation.W * y2;
double wz2 = rotation.W * z2;
double xx2 = rotation.X * x2;
double xy2 = rotation.X * y2;
double xz2 = rotation.X * z2;
double yy2 = rotation.Y * y2;
double yz2 = rotation.Y * z2;
double zz2 = rotation.Z * z2;
return new Vector4(
value.X * (1.0 - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2),
value.X * (xy2 + wz2) + value.Y * (1.0 - xx2 - zz2) + value.Z * (yz2 - wx2),
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2) + value.Z * (1.0 - xx2 - yy2),
value.W);
}
#endregion Public Static Methods
#region Public operator methods
// All these methods should be inlines as they are implemented
// over JIT intrinsics
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Add(Vector4 left, Vector4 right)
{
return left + right;
}
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Subtract(Vector4 left, Vector4 right)
{
return left - right;
}
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Multiply(Vector4 left, Vector4 right)
{
return left * right;
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Multiply(Vector4 left, Double right)
{
return left * new Vector4(right, right, right, right);
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Multiply(Double left, Vector4 right)
{
return new Vector4(left, left, left, left) * right;
}
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Divide(Vector4 left, Vector4 right)
{
return left / right;
}
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="divisor">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Divide(Vector4 left, Double divisor)
{
return left / divisor;
}
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Negate(Vector4 value)
{
return -value;
}
#endregion Public operator methods
}
}
-337
View File
@@ -1,337 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
namespace System.DoubleNumerics
{
// This file contains the definitions for all of the JIT intrinsic methods and properties that are recognized by the current x64 JIT compiler.
// The implementation defined here is used in any circumstance where the JIT fails to recognize these members as intrinsic.
// The JIT recognizes these methods and properties by name and signature: if either is changed, the JIT will no longer recognize the member.
// Some methods declared here are not strictly intrinsic, but delegate to an intrinsic method. For example, only one overload of CopyTo()
public partial struct Vector4
{
/// <summary>
/// The X component of the vector.
/// </summary>
public Double X;
/// <summary>
/// The Y component of the vector.
/// </summary>
public Double Y;
/// <summary>
/// The Z component of the vector.
/// </summary>
public Double Z;
/// <summary>
/// The W component of the vector.
/// </summary>
public Double W;
#region Constructors
/// <summary>
/// Constructs a vector whose elements are all the single specified value.
/// </summary>
/// <param name="value">The element to fill the vector with.</param>
public Vector4(Double value)
: this(value, value, value, value)
{
}
/// <summary>
/// Constructs a vector with the given individual elements.
/// </summary>
/// <param name="w">W component.</param>
/// <param name="x">X component.</param>
/// <param name="y">Y component.</param>
/// <param name="z">Z component.</param>
public Vector4(Double x, Double y, Double z, Double w)
{
W = w;
X = x;
Y = y;
Z = z;
}
/// <summary>
/// Constructs a Vector4 from the given Vector2 and a Z and W component.
/// </summary>
/// <param name="value">The vector to use as the X and Y components.</param>
/// <param name="z">The Z component.</param>
/// <param name="w">The W component.</param>
public Vector4(Vector2 value, Double z, Double w)
{
X = value.X;
Y = value.Y;
Z = z;
W = w;
}
/// <summary>
/// Constructs a Vector4 from the given Vector3 and a W component.
/// </summary>
/// <param name="value">The vector to use as the X, Y, and Z components.</param>
/// <param name="w">The W component.</param>
public Vector4(Vector3 value, Double w)
{
X = value.X;
Y = value.Y;
Z = value.Z;
W = w;
}
#endregion Constructors
#region Public Instance Methods
/// <summary>
/// Copies the contents of the vector into the given array.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Double[] array)
{
CopyTo(array, 0);
}
/// <summary>
/// Copies the contents of the vector into the given array, starting from index.
/// </summary>
/// <exception cref="ArgumentNullException">If array is null.</exception>
/// <exception cref="RankException">If array is multidimensional.</exception>
/// <exception cref="ArgumentOutOfRangeException">If index is greater than end of the array or index is less than zero.</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Double[] array, int index)
{
if (array == null)
{
// Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull.
throw new NullReferenceException(Strings.Arg_NullArgumentNullRef);
}
if (index < 0 || index >= array.Length)
{
throw new ArgumentOutOfRangeException(nameof(index), String.Format(Strings.Arg_ArgumentOutOfRangeException, index));
}
if ((array.Length - index) < 4)
{
throw new ArgumentException(String.Format(Strings.Arg_ElementsInSourceIsGreaterThanDestination, index));
}
array[index] = X;
array[index + 1] = Y;
array[index + 2] = Z;
array[index + 3] = W;
}
/// <summary>
/// Returns a boolean indicating whether the given Vector4 is equal to this Vector4 instance.
/// </summary>
/// <param name="other">The Vector4 to compare this instance to.</param>
/// <returns>True if the other Vector4 is equal to this instance; False otherwise.</returns>
public bool Equals(Vector4 other)
{
return this.X == other.X
&& this.Y == other.Y
&& this.Z == other.Z
&& this.W == other.W;
}
#endregion Public Instance Methods
#region Public Static Methods
/// <summary>
/// Returns the dot product of two vectors.
/// </summary>
/// <param name="vector1">The first vector.</param>
/// <param name="vector2">The second vector.</param>
/// <returns>The dot product.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static double Dot(Vector4 vector1, Vector4 vector2)
{
return vector1.X * vector2.X +
vector1.Y * vector2.Y +
vector1.Z * vector2.Z +
vector1.W * vector2.W;
}
/// <summary>
/// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The minimized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Min(Vector4 value1, Vector4 value2)
{
return new Vector4(
(value1.X < value2.X) ? value1.X : value2.X,
(value1.Y < value2.Y) ? value1.Y : value2.Y,
(value1.Z < value2.Z) ? value1.Z : value2.Z,
(value1.W < value2.W) ? value1.W : value2.W);
}
/// <summary>
/// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors.
/// </summary>
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The maximized vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Max(Vector4 value1, Vector4 value2)
{
return new Vector4(
(value1.X > value2.X) ? value1.X : value2.X,
(value1.Y > value2.Y) ? value1.Y : value2.Y,
(value1.Z > value2.Z) ? value1.Z : value2.Z,
(value1.W > value2.W) ? value1.W : value2.W);
}
/// <summary>
/// Returns a vector whose elements are the absolute values of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The absolute value vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Abs(Vector4 value)
{
return new Vector4(Math.Abs(value.X), Math.Abs(value.Y), Math.Abs(value.Z), Math.Abs(value.W));
}
/// <summary>
/// Returns a vector whose elements are the square root of each of the source vector's elements.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The square root vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 SquareRoot(Vector4 value)
{
return new Vector4((Double)Math.Sqrt(value.X), (Double)Math.Sqrt(value.Y), (Double)Math.Sqrt(value.Z), (Double)Math.Sqrt(value.W));
}
#endregion Public Static Methods
#region Public static operators
/// <summary>
/// Adds two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator +(Vector4 left, Vector4 right)
{
return new Vector4(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W);
}
/// <summary>
/// Subtracts the second vector from the first.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator -(Vector4 left, Vector4 right)
{
return new Vector4(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W);
}
/// <summary>
/// Multiplies two vectors together.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator *(Vector4 left, Vector4 right)
{
return new Vector4(left.X * right.X, left.Y * right.Y, left.Z * right.Z, left.W * right.W);
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator *(Vector4 left, Double right)
{
return left * new Vector4(right);
}
/// <summary>
/// Multiplies a vector by the given scalar.
/// </summary>
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator *(Double left, Vector4 right)
{
return new Vector4(left) * right;
}
/// <summary>
/// Divides the first vector by the second.
/// </summary>
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator /(Vector4 left, Vector4 right)
{
return new Vector4(left.X / right.X, left.Y / right.Y, left.Z / right.Z, left.W / right.W);
}
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
/// <param name="value1">The source vector.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the division.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator /(Vector4 value1, double value2)
{
double invDiv = 1.0 / value2;
return new Vector4(
value1.X * invDiv,
value1.Y * invDiv,
value1.Z * invDiv,
value1.W * invDiv);
}
/// <summary>
/// Negates a given vector.
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The negated vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator -(Vector4 value)
{
return Zero - value;
}
/// <summary>
/// Returns a boolean indicating whether the two given vectors are equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are equal; False otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector4 left, Vector4 right)
{
return left.Equals(right);
}
/// <summary>
/// Returns a boolean indicating whether the two given vectors are not equal.
/// </summary>
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are not equal; False if they are equal.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vector4 left, Vector4 right)
{
return !(left == right);
}
#endregion Public static operators
}
}
-3
View File
@@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/></startup></configuration>
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FAKE" version="4.29.2" targetFramework="net461" />
<package id="NuGet.CommandLine" version="3.4.3" targetFramework="net461" developmentDependency="true" />
<package id="PackProj" version="0.2.2" targetFramework="net461" developmentDependency="true" />
</packages>
-12
View File
@@ -1,12 +0,0 @@
{
"supports": {},
"dependencies": {
"Microsoft.NETCore.Portable.Compatibility": "1.0.1",
"NETStandard.Library": "1.6.0",
"System.Resources.ResourceManager": "4.0.1",
"System.Runtime": "4.1.0"
},
"frameworks": {
"netstandard1.3": {}
}
}
Binary file not shown.
-48
View File
@@ -1,48 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Numerics.Vectors.Tests", "tests\System.Numerics.Vectors.Tests.csproj", "{A7074928-82C3-4739-88FE-9B528977950C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Numerics.Vectors.Performance.Tests", "tests\Performance\System.Numerics.Vectors.Performance.Tests.csproj", "{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.DoubleNumerics", "System.DoubleNumerics\System.DoubleNumerics.csproj", "{18483631-763C-48A4-9045-A3C3F93D23F9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
net46_Debug|Any CPU = net46_Debug|Any CPU
net46_Release|Any CPU = net46_Release|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A7074928-82C3-4739-88FE-9B528977950C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A7074928-82C3-4739-88FE-9B528977950C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A7074928-82C3-4739-88FE-9B528977950C}.net46_Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A7074928-82C3-4739-88FE-9B528977950C}.net46_Debug|Any CPU.Build.0 = Debug|Any CPU
{A7074928-82C3-4739-88FE-9B528977950C}.net46_Release|Any CPU.ActiveCfg = Release|Any CPU
{A7074928-82C3-4739-88FE-9B528977950C}.net46_Release|Any CPU.Build.0 = Release|Any CPU
{A7074928-82C3-4739-88FE-9B528977950C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A7074928-82C3-4739-88FE-9B528977950C}.Release|Any CPU.Build.0 = Release|Any CPU
{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}.net46_Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}.net46_Debug|Any CPU.Build.0 = Debug|Any CPU
{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}.net46_Release|Any CPU.ActiveCfg = Release|Any CPU
{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}.net46_Release|Any CPU.Build.0 = Release|Any CPU
{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}.Release|Any CPU.Build.0 = Release|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.net46_Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.net46_Debug|Any CPU.Build.0 = Debug|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.net46_Release|Any CPU.ActiveCfg = Release|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.net46_Release|Any CPU.Build.0 = Release|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18483631-763C-48A4-9045-A3C3F93D23F9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+3
View File
@@ -0,0 +1,3 @@
$ErrorActionPreference = "Stop";
dotnet run --project build/build.csproj -- $args
Executable
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -euo pipefail
dotnet run --project build/build.csproj -- "$@"
+66
View File
@@ -0,0 +1,66 @@
using GlobExpressions;
using static Bullseye.Targets;
using static SimpleExec.Command;
const string CLEAN = "clean";
const string FORMAT = "format";
const string RESTORE_TOOLS = "restore-tools";
const string RESTORE = "restore";
const string BUILD = "build";
const string TEST = "test";
const string PACK = "pack";
Target(
CLEAN,
ForEach("**/output"),
dir =>
{
IEnumerable<string> GetDirectories(string d)
{
return Glob.Directories(".", d);
}
void RemoveDirectory(string d)
{
if (Directory.Exists(d))
{
Console.WriteLine(d);
Directory.Delete(d, true);
}
}
foreach (var d in GetDirectories(dir))
{
RemoveDirectory(d);
}
}
);
Target(RESTORE_TOOLS, () => RunAsync("dotnet", "tool restore"));
Target(FORMAT, DependsOn(RESTORE_TOOLS), () => RunAsync("dotnet", "csharpier --check ."));
Target(RESTORE, () => RunAsync("dotnet", "restore Speckle.DoubleNumerics.sln --locked-mode"));
Target(BUILD, DependsOn(RESTORE), () => RunAsync("dotnet", "build Speckle.DoubleNumerics.sln -c Release --no-restore"));
Target(
TEST,
DependsOn(BUILD),
Glob.Files(".", "**/*.Tests.csproj"),
async file =>
{
await RunAsync("dotnet", $"test {file} -c Release --no-build --verbosity=normal");
}
);
Target(
PACK,
DependsOn(TEST),
() => RunAsync("dotnet", "pack Speckle.DoubleNumerics.sln -c Release -o output --no-build")
);
Target("default", DependsOn(FORMAT, TEST), () => Console.WriteLine("Done!"));
await RunTargetsAndExitAsync(args).ConfigureAwait(true);
+12
View File
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Bullseye" />
<PackageReference Include="Glob" />
<PackageReference Include="SimpleExec" />
</ItemGroup>
</Project>
+57
View File
@@ -0,0 +1,57 @@
{
"version": 2,
"dependencies": {
"net8.0": {
"Bullseye": {
"type": "Direct",
"requested": "[5.0.0, )",
"resolved": "5.0.0",
"contentHash": "bqyt+m17ym+5aN45C5oZRAjuLDt8jKiCm/ys1XfymIXSkrTFwvI/QsbY3ucPSHDz7SF7uON7B57kXFv5H2k1ew=="
},
"Glob": {
"type": "Direct",
"requested": "[1.1.9, )",
"resolved": "1.1.9",
"contentHash": "AfK5+ECWYTP7G3AAdnU8IfVj+QpGjrh9GC2mpdcJzCvtQ4pnerAGwHsxJ9D4/RnhDUz2DSzd951O/lQjQby2Sw=="
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"MinVer": {
"type": "Direct",
"requested": "[5.0.0, )",
"resolved": "5.0.0",
"contentHash": "ybkgpQMtt0Fo91l5rYtE3TZtD+Nmy5Ko091xvfXXOosQdMi30XO2EZ2+ShZt89gdu7RMmJqZaJ+e1q6d+6+KNw=="
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
},
"SimpleExec": {
"type": "Direct",
"requested": "[12.0.0, )",
"resolved": "12.0.0",
"contentHash": "ptxlWtxC8vM6Y6e3h9ZTxBBkOWnWrm/Sa1HT+2i1xcXY3Hx2hmKDZP5RShPf8Xr9D+ivlrXNy57ktzyH8kyt+Q=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
}
}
}
}
+6
View File
@@ -0,0 +1,6 @@
{
"sdk": {
"version": "8.0.100",
"rollForward": "latestMinor"
}
}
Binary file not shown.
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<Project Include="System.Numerics.Vectors.pkgproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
</Project>
-183
View File
@@ -1,183 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Xunit;
namespace System.Numerics.Tests.Common.System
{
public static class PlatformDetection
{
public static bool IsWindows { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public static bool IsWindows7 { get; } = IsWindows && GetWindowsVersion() == 6 && GetWindowsMinorVersion() == 1;
public static bool IsOSX { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
public static bool IsNetBSD { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD"));
public static bool IsNotWindowsNanoServer { get; } = (IsWindows &&
File.Exists(Path.Combine(Environment.GetEnvironmentVariable("windir"), "regedit.exe")));
public static bool IsWindows10Version1607OrGreater { get; } = IsWindows &&
GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildNumber() >= 14393;
public static int WindowsVersion { get; } = GetWindowsVersion();
private static Lazy<bool> m_isWindowsSubsystemForLinux = new Lazy<bool>(GetIsWindowsSubsystemForLinux);
public static bool IsWindowsSubsystemForLinux => m_isWindowsSubsystemForLinux.Value;
public static bool IsNotWindowsSubsystemForLinux => !IsWindowsSubsystemForLinux;
private static bool GetIsWindowsSubsystemForLinux()
{
// https://github.com/Microsoft/BashOnWindows/issues/423#issuecomment-221627364
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
const string versionFile = "/proc/version";
if (File.Exists(versionFile))
{
var s = File.ReadAllText(versionFile);
if (s.Contains("Microsoft") || s.Contains("WSL"))
{
return true;
}
}
}
return false;
}
public static bool IsDebian8 { get; } = IsDistroAndVersion("debian", "8");
public static bool IsUbuntu1510 { get; } = IsDistroAndVersion("ubuntu", "15.10");
public static bool IsUbuntu1604 { get; } = IsDistroAndVersion("ubuntu", "16.04");
public static bool IsFedora23 { get; } = IsDistroAndVersion("fedora", "23");
private static bool IsDistroAndVersion(string distroId, string versionId)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
IdVersionPair v = ParseOsReleaseFile();
if (v.Id == distroId && v.VersionId == versionId)
{
return true;
}
}
return false;
}
public static Version OSXKernelVersion { get; } = GetOSXKernelVersion();
private static IdVersionPair ParseOsReleaseFile()
{
Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Linux));
IdVersionPair ret = new IdVersionPair();
ret.Id = "";
ret.VersionId = "";
if (File.Exists("/etc/os-release"))
{
foreach (string line in File.ReadLines("/etc/os-release"))
{
if (line.StartsWith("ID=", global::System.StringComparison.Ordinal))
{
ret.Id = line.Substring("ID=".Length);
}
else if (line.StartsWith("VERSION_ID=", global::System.StringComparison.Ordinal))
{
ret.VersionId = line.Substring("VERSION_ID=".Length);
}
}
}
string versionId = ret.VersionId;
if (versionId.Length >= 2 && versionId[0] == '"' && versionId[versionId.Length - 1] == '"')
{
// Remove Quotes.
ret.VersionId = versionId.Substring(1, versionId.Length - 2);
}
return ret;
}
private struct IdVersionPair
{
public string Id { get; set; }
public string VersionId { get; set; }
}
private static int GetWindowsVersion()
{
if (IsWindows)
{
RTL_OSVERSIONINFOEX osvi = new RTL_OSVERSIONINFOEX();
osvi.dwOSVersionInfoSize = (uint)Marshal.SizeOf(osvi);
Assert.Equal(0, RtlGetVersion(out osvi));
return (int)osvi.dwMajorVersion;
}
return -1;
}
private static int GetWindowsMinorVersion()
{
if (IsWindows)
{
RTL_OSVERSIONINFOEX osvi = new RTL_OSVERSIONINFOEX();
osvi.dwOSVersionInfoSize = (uint)Marshal.SizeOf(osvi);
Assert.Equal(0, RtlGetVersion(out osvi));
return (int)osvi.dwMinorVersion;
}
return -1;
}
private static int GetWindowsBuildNumber()
{
if (IsWindows)
{
RTL_OSVERSIONINFOEX osvi = new RTL_OSVERSIONINFOEX();
osvi.dwOSVersionInfoSize = (uint)Marshal.SizeOf(osvi);
Assert.Equal(0, RtlGetVersion(out osvi));
return (int)osvi.dwBuildNumber;
}
return -1;
}
private static Version GetOSXKernelVersion()
{
if (IsOSX)
{
byte[] bytes = new byte[256];
IntPtr bytesLength = new IntPtr(bytes.Length);
Assert.Equal(0, sysctlbyname("kern.osrelease", bytes, ref bytesLength, null, IntPtr.Zero));
string versionString = Encoding.UTF8.GetString(bytes);
return Version.Parse(versionString);
}
return new Version(0, 0, 0);
}
[DllImport("libc", SetLastError = true)]
private static extern int sysctlbyname(string ctlName, byte[] oldp, ref IntPtr oldpLen, byte[] newp, IntPtr newpLen);
[DllImport("ntdll.dll")]
private static extern int RtlGetVersion(out RTL_OSVERSIONINFOEX lpVersionInformation);
[StructLayout(LayoutKind.Sequential)]
private struct RTL_OSVERSIONINFOEX
{
internal uint dwOSVersionInfoSize;
internal uint dwMajorVersion;
internal uint dwMinorVersion;
internal uint dwBuildNumber;
internal uint dwPlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
internal string szCSDVersion;
}
}
}
-142
View File
@@ -1,142 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
namespace System.DoubleNumerics
{
internal class ConstantHelper
{
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Byte GetByteWithAllBitsSet()
{
Byte value = 0;
unsafe
{
unchecked
{
*((Byte*)&value) = (Byte)0xff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static SByte GetSByteWithAllBitsSet()
{
SByte value = 0;
unsafe
{
unchecked
{
*((SByte*)&value) = (SByte)0xff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static UInt16 GetUInt16WithAllBitsSet()
{
UInt16 value = 0;
unsafe
{
unchecked
{
*((UInt16*)&value) = (UInt16)0xffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Int16 GetInt16WithAllBitsSet()
{
Int16 value = 0;
unsafe
{
unchecked
{
*((Int16*)&value) = (Int16)0xffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static UInt32 GetUInt32WithAllBitsSet()
{
UInt32 value = 0;
unsafe
{
unchecked
{
*((UInt32*)&value) = (UInt32)0xffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Int32 GetInt32WithAllBitsSet()
{
Int32 value = 0;
unsafe
{
unchecked
{
*((Int32*)&value) = (Int32)0xffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static UInt64 GetUInt64WithAllBitsSet()
{
UInt64 value = 0;
unsafe
{
unchecked
{
*((UInt64*)&value) = (UInt64)0xffffffffffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Int64 GetInt64WithAllBitsSet()
{
Int64 value = 0;
unsafe
{
unchecked
{
*((Int64*)&value) = (Int64)0xffffffffffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Double GetDoubleWithAllBitsSet()
{
Double value = 0;
unsafe
{
unchecked
{
*((Int32*)&value) = (Int32)0xffffffffffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Single GetSingleWithAllBitsSet()
{
Single value = 0;
unsafe
{
unchecked
{
*((Single*)&value) = (Single)0xffffffff;
}
}
return value;
}
}
}
-76
View File
@@ -1,76 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.DoubleNumerics;
namespace System.Numerics.Tests
{
static class MathHelper
{
public const double Pi = (double)Math.PI;
public const double PiOver2 = Pi / 2f;
public const double PiOver4 = Pi / 4f;
// Angle conversion helper.
public static double ToRadians(double degrees)
{
return degrees * Pi / 180f;
}
// Comparison helpers with small tolerance to allow for floating point rounding during computations.
public static bool Equal(double a, double b)
{
return (Math.Abs(a - b) < 1e-5);
}
public static bool Equal(Vector2 a, Vector2 b)
{
return Equal(a.X, b.X) && Equal(a.Y, b.Y);
}
public static bool Equal(Vector3 a, Vector3 b)
{
return Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z);
}
public static bool Equal(Vector4 a, Vector4 b)
{
return Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z) && Equal(a.W, b.W);
}
public static bool Equal(Matrix4x4 a, Matrix4x4 b)
{
return
Equal(a.M11, b.M11) && Equal(a.M12, b.M12) && Equal(a.M13, b.M13) && Equal(a.M14, b.M14) &&
Equal(a.M21, b.M21) && Equal(a.M22, b.M22) && Equal(a.M23, b.M23) && Equal(a.M24, b.M24) &&
Equal(a.M31, b.M31) && Equal(a.M32, b.M32) && Equal(a.M33, b.M33) && Equal(a.M34, b.M34) &&
Equal(a.M41, b.M41) && Equal(a.M42, b.M42) && Equal(a.M43, b.M43) && Equal(a.M44, b.M44);
}
public static bool Equal(Matrix3x2 a, Matrix3x2 b)
{
return
Equal(a.M11, b.M11) && Equal(a.M12, b.M12) &&
Equal(a.M21, b.M21) && Equal(a.M22, b.M22) &&
Equal(a.M31, b.M31) && Equal(a.M32, b.M32);
}
public static bool Equal(Plane a, Plane b)
{
return Equal(a.Normal, b.Normal) && Equal(a.D, b.D);
}
public static bool Equal(Quaternion a, Quaternion b)
{
return Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z) && Equal(a.W, b.W);
}
public static bool EqualRotation(Quaternion a, Quaternion b)
{
return Equal(a, b) || Equal(a, -b);
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,56 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.IO;
using System.Runtime.CompilerServices;
namespace System.Numerics.Performance.Tests.Common.System
{
/// <summary>Static helper class for performance tests</summary>
public class PerfUtils
{
private Random _rand;
/// <summary>
/// Initializes a new PerfUtils object with the default random seed.
/// </summary>
public PerfUtils()
{
_rand = new Random(1234132);
}
/// <summary>
/// Initializes a new PerfUtils object with the given seed. Use this if also
/// using MemberData that was created using PerfUtils to avoid possible collision
/// errors.
/// </summary>
public PerfUtils(int seed)
{
_rand = new Random(seed);
}
/// <summary>
/// Helper method to create a string containing a number of random
/// characters equal to the specified length
/// </summary>
public string CreateString(int length)
{
byte[] bytes = new byte[length];
_rand.NextBytes(bytes);
return Convert.ToBase64String(bytes);
}
/// <summary>Gets a test file full path that is associated with the call site.</summary>
/// <param name="index">An optional index value to use as a suffix on the file name. Typically a loop index.</param>
/// <param name="memberName">The member name of the function calling this method.</param>
/// <param name="lineNumber">The line number of the function calling this method.</param>
public string GetTestFilePath(int? index = null, [CallerMemberName] string memberName = null, [CallerLineNumber] int lineNumber = 0)
{
return Path.Combine(Path.GetTempPath(), string.Format(
index.HasValue ? "{0}_{1}_{2}_{3}" : "{0}_{1}_{2}",
memberName ?? "TestBase", lineNumber, Path.GetRandomFileName(),
index.GetValueOrDefault()));
}
}
}
-142
View File
@@ -1,142 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
namespace System.DoubleNumerics
{
internal class ConstantHelper
{
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Byte GetByteWithAllBitsSet()
{
Byte value = 0;
unsafe
{
unchecked
{
*((Byte*)&value) = (Byte)0xff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static SByte GetSByteWithAllBitsSet()
{
SByte value = 0;
unsafe
{
unchecked
{
*((SByte*)&value) = (SByte)0xff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static UInt16 GetUInt16WithAllBitsSet()
{
UInt16 value = 0;
unsafe
{
unchecked
{
*((UInt16*)&value) = (UInt16)0xffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Int16 GetInt16WithAllBitsSet()
{
Int16 value = 0;
unsafe
{
unchecked
{
*((Int16*)&value) = (Int16)0xffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static UInt32 GetUInt32WithAllBitsSet()
{
UInt32 value = 0;
unsafe
{
unchecked
{
*((UInt32*)&value) = (UInt32)0xffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Int32 GetInt32WithAllBitsSet()
{
Int32 value = 0;
unsafe
{
unchecked
{
*((Int32*)&value) = (Int32)0xffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static UInt64 GetUInt64WithAllBitsSet()
{
UInt64 value = 0;
unsafe
{
unchecked
{
*((UInt64*)&value) = (UInt64)0xffffffffffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Int64 GetInt64WithAllBitsSet()
{
Int64 value = 0;
unsafe
{
unchecked
{
*((Int64*)&value) = (Int64)0xffffffffffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Double GetDoubleWithAllBitsSet()
{
Double value = 0;
unsafe
{
unchecked
{
*((Int32*)&value) = (Int32)0xffffffffffffffff;
}
}
return value;
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Single GetSingleWithAllBitsSet()
{
Single value = 0;
unsafe
{
unchecked
{
*((Single*)&value) = (Single)0xffffffff;
}
}
return value;
}
}
}
-31
View File
@@ -1,31 +0,0 @@
//using Microsoft.Xunit.Performance;
namespace System.Numerics.Performance.Tests
{
public static class HashCodeTest
{
/*
[Benchmark(InnerIterationCount = 100000000)]
public static void HashTest()
{
Random rand = new Random(84329);
Vector4 vector4 = new Vector4(
Convert.ToSingle(rand.NextDouble()),
Convert.ToSingle(rand.NextDouble()),
Convert.ToSingle(rand.NextDouble()),
Convert.ToSingle(rand.NextDouble()));
foreach (var iteration in Benchmark.Iterations)
{
using (iteration.StartMeasurement())
{
for (int i = 0; i < Benchmark.InnerIterationCount; i++)
{
vector4.GetHashCode();
}
}
}
}
*/
}
}
-101
View File
@@ -1,101 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//using Microsoft.Xunit.Performance;
using System.Collections.Generic;
using System.DoubleNumerics;
namespace System.Numerics.Performance.Tests
{
public class Perf_Vector2
{
public static IEnumerable<object[]> TestOperations()
{
foreach (Operations op in Enum.GetValues(typeof(Operations)))
yield return new object[] { op };
}
/*
[Benchmark]
[MemberData(nameof(TestOperations))]
public void Operation(Operations operation)
{
Random rand = new Random(84329);
Vector2 v1 = new Vector2(Convert.ToSingle(rand.NextDouble()), Convert.ToSingle(rand.NextDouble()));
Vector2 v2 = new Vector2(Convert.ToSingle(rand.NextDouble()), Convert.ToSingle(rand.NextDouble()));
foreach (var iteration in Benchmark.Iterations)
using (iteration.StartMeasurement())
ExecuteTest(operation, 1000000, v1, v2);
}
*/
public void ExecuteTest(Operations operation, int innerIterations, Vector2 v1, Vector2 v2)
{
Vector2 res;
switch (operation)
{
case Operations.Add_Operator:
for (int i = 0; i < innerIterations; i++)
{ res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; }
break;
case Operations.Add_Function:
for (int i = 0; i < innerIterations; i++)
{ Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); }
break;
case Operations.Sub_Operator:
for (int i = 0; i < innerIterations; i++)
{ res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; }
break;
case Operations.Sub_Function:
for (int i = 0; i < innerIterations; i++)
{ Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); }
break;
case Operations.Mul_Operator:
for (int i = 0; i < innerIterations; i++)
{ res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; }
break;
case Operations.Mul_Function:
for (int i = 0; i < innerIterations; i++)
{ Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); }
break;
case Operations.Dot:
for (int i = 0; i < innerIterations; i++)
{ Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); }
break;
case Operations.SquareRoot:
for (int i = 0; i < innerIterations; i++)
{ Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); }
break;
case Operations.Length_Squared:
for (int i = 0; i < innerIterations; i++)
{ v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); }
break;
case Operations.Normalize:
for (int i = 0; i < innerIterations; i++)
{ Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); }
break;
case Operations.Distance_Squared:
for (int i = 0; i < innerIterations; i++)
{ Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); }
break;
}
}
public enum Operations
{
Add_Operator = 1,
Add_Function = 2,
Sub_Operator = 3,
Sub_Function = 4,
Mul_Operator = 5,
Mul_Function = 6,
Dot = 7,
SquareRoot = 8,
Length_Squared = 9,
Normalize = 10,
Distance_Squared = 11
}
}
}
-3
View File
@@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/></startup></configuration>
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="xunit" version="2.1.0" targetFramework="net461" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net461" />
<package id="xunit.assert" version="2.1.0" targetFramework="net461" />
<package id="xunit.core" version="2.1.0" targetFramework="net461" />
<package id="xunit.extensibility.core" version="2.1.0" targetFramework="net461" />
<package id="xunit.extensibility.execution" version="2.1.0" targetFramework="net461" />
</packages>
-381
View File
@@ -1,381 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.DoubleNumerics;
using System.Globalization;
using System.Runtime.InteropServices;
using Xunit;
namespace System.Numerics.Tests
{
public class PlaneTests
{
// A test for Equals (Plane)
[Fact]
public void PlaneEqualsTest1()
{
Plane a = new Plane(1.0, 2.0, 3.0, 4.0);
Plane b = new Plane(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
bool expected = true;
bool actual = a.Equals(b);
Assert.Equal(expected, actual);
// case 2: compare between different values
b.Normal = new Vector3(10.0, b.Normal.Y, b.Normal.Z);
expected = false;
actual = a.Equals(b);
Assert.Equal(expected, actual);
}
// A test for Equals (object)
[Fact]
public void PlaneEqualsTest()
{
Plane a = new Plane(1.0, 2.0, 3.0, 4.0);
Plane b = new Plane(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
object obj = b;
bool expected = true;
bool actual = a.Equals(obj);
Assert.Equal(expected, actual);
// case 2: compare between different values
b.Normal = new Vector3(10.0, b.Normal.Y, b.Normal.Z);
obj = b;
expected = false;
actual = a.Equals(obj);
Assert.Equal(expected, actual);
// case 3: compare between different types.
obj = new Quaternion();
expected = false;
actual = a.Equals(obj);
Assert.Equal(expected, actual);
// case 3: compare against null.
obj = null;
expected = false;
actual = a.Equals(obj);
Assert.Equal(expected, actual);
}
// A test for operator != (Plane, Plane)
[Fact]
public void PlaneInequalityTest()
{
Plane a = new Plane(1.0, 2.0, 3.0, 4.0);
Plane b = new Plane(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
bool expected = false;
bool actual = a != b;
Assert.Equal(expected, actual);
// case 2: compare between different values
b.Normal = new Vector3(10.0, b.Normal.Y, b.Normal.Z);
expected = true;
actual = a != b;
Assert.Equal(expected, actual);
}
// A test for operator == (Plane, Plane)
[Fact]
public void PlaneEqualityTest()
{
Plane a = new Plane(1.0, 2.0, 3.0, 4.0);
Plane b = new Plane(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
bool expected = true;
bool actual = a == b;
Assert.Equal(expected, actual);
// case 2: compare between different values
b.Normal = new Vector3(10.0, b.Normal.Y, b.Normal.Z);
expected = false;
actual = a == b;
Assert.Equal(expected, actual);
}
// A test for GetHashCode ()
[Fact]
public void PlaneGetHashCodeTest()
{
Plane target = new Plane(1.0, 2.0, 3.0, 4.0);
int expected = target.Normal.GetHashCode() + target.D.GetHashCode();
int actual = target.GetHashCode();
Assert.Equal(expected, actual);
}
// A test for Plane (double, double, double, double)
[Fact]
public void PlaneConstructorTest1()
{
double a = 1.0, b = 2.0, c = 3.0, d = 4.0;
Plane target = new Plane(a, b, c, d);
Assert.True(
target.Normal.X == a && target.Normal.Y == b && target.Normal.Z == c && target.D == d,
"Plane.cstor did not return the expected value.");
}
// A test for Plane.CreateFromVertices
[Fact]
public void PlaneCreateFromVerticesTest()
{
Vector3 point1 = new Vector3(0.0, 1.0, 1.0);
Vector3 point2 = new Vector3(0.0, 0.0, 1.0);
Vector3 point3 = new Vector3(1.0, 0.0, 1.0);
Plane target = Plane.CreateFromVertices(point1, point2, point3);
Plane expected = new Plane(new Vector3(0, 0, 1), -1.0);
Assert.Equal(target, expected);
}
// A test for Plane.CreateFromVertices
[Fact]
public void PlaneCreateFromVerticesTest2()
{
Vector3 point1 = new Vector3(0.0, 0.0, 1.0);
Vector3 point2 = new Vector3(1.0, 0.0, 0.0);
Vector3 point3 = new Vector3(1.0, 1.0, 0.0);
Plane target = Plane.CreateFromVertices(point1, point2, point3);
double invRoot2 = (double)(1 / Math.Sqrt(2));
Plane expected = new Plane(new Vector3(invRoot2, 0, invRoot2), -invRoot2);
Assert.True(MathHelper.Equal(target, expected), "Plane.cstor did not return the expected value.");
}
// A test for Plane (Vector3, double)
[Fact]
public void PlaneConstructorTest3()
{
Vector3 normal = new Vector3(1, 2, 3);
double d = 4;
Plane target = new Plane(normal, d);
Assert.True(
target.Normal == normal && target.D == d,
"Plane.cstor did not return the expected value.");
}
// A test for Plane (Vector4)
[Fact]
public void PlaneConstructorTest()
{
Vector4 value = new Vector4(1.0, 2.0, 3.0, 4.0);
Plane target = new Plane(value);
Assert.True(
target.Normal.X == value.X && target.Normal.Y == value.Y && target.Normal.Z == value.Z && target.D == value.W,
"Plane.cstor did not return the expected value.");
}
[Fact]
public void PlaneDotTest()
{
Plane target = new Plane(2, 3, 4, 5);
Vector4 value = new Vector4(5, 4, 3, 2);
double expected = 10 + 12 + 12 + 10;
double actual = Plane.Dot(target, value);
Assert.True(MathHelper.Equal(expected, actual), "Plane.Dot returns unexpected value.");
}
[Fact]
public void PlaneDotCoordinateTest()
{
Plane target = new Plane(2, 3, 4, 5);
Vector3 value = new Vector3(5, 4, 3);
double expected = 10 + 12 + 12 + 5;
double actual = Plane.DotCoordinate(target, value);
Assert.True(MathHelper.Equal(expected, actual), "Plane.DotCoordinate returns unexpected value.");
}
[Fact]
public void PlaneDotNormalTest()
{
Plane target = new Plane(2, 3, 4, 5);
Vector3 value = new Vector3(5, 4, 3);
double expected = 10 + 12 + 12;
double actual = Plane.DotNormal(target, value);
Assert.True(MathHelper.Equal(expected, actual), "Plane.DotCoordinate returns unexpected value.");
}
[Fact]
public void PlaneNormalizeTest()
{
Plane target = new Plane(1, 2, 3, 4);
double f = target.Normal.LengthSquared();
double invF = 1.0 / (double)Math.Sqrt(f);
Plane expected = new Plane(target.Normal * invF, target.D * invF);
Plane actual = Plane.Normalize(target);
Assert.True(MathHelper.Equal(expected, actual), "Plane.Normalize returns unexpected value.");
// normalize, normalized normal.
actual = Plane.Normalize(actual);
Assert.True(MathHelper.Equal(expected, actual), "Plane.Normalize returns unexpected value.");
}
[Fact]
// Transform by matrix
public void PlaneTransformTest1()
{
Plane target = new Plane(1, 2, 3, 4);
target = Plane.Normalize(target);
Matrix4x4 m =
Matrix4x4.CreateRotationX(MathHelper.ToRadians(30.0)) *
Matrix4x4.CreateRotationY(MathHelper.ToRadians(30.0)) *
Matrix4x4.CreateRotationZ(MathHelper.ToRadians(30.0));
m.M41 = 10.0;
m.M42 = 20.0;
m.M43 = 30.0;
Plane expected = new Plane();
Matrix4x4 inv;
Matrix4x4.Invert(m, out inv);
Matrix4x4 itm = Matrix4x4.Transpose(inv);
double x = target.Normal.X, y = target.Normal.Y, z = target.Normal.Z, w = target.D;
expected.Normal = new Vector3(
x * itm.M11 + y * itm.M21 + z * itm.M31 + w * itm.M41,
x * itm.M12 + y * itm.M22 + z * itm.M32 + w * itm.M42,
x * itm.M13 + y * itm.M23 + z * itm.M33 + w * itm.M43);
expected.D = x * itm.M14 + y * itm.M24 + z * itm.M34 + w * itm.M44;
Plane actual;
actual = Plane.Transform(target, m);
Assert.True(MathHelper.Equal(expected, actual), "Plane.Transform did not return the expected value.");
}
[Fact]
// Transform by quaternion
public void PlaneTransformTest2()
{
Plane target = new Plane(1, 2, 3, 4);
target = Plane.Normalize(target);
Matrix4x4 m =
Matrix4x4.CreateRotationX(MathHelper.ToRadians(30.0)) *
Matrix4x4.CreateRotationY(MathHelper.ToRadians(30.0)) *
Matrix4x4.CreateRotationZ(MathHelper.ToRadians(30.0));
Quaternion q = Quaternion.CreateFromRotationMatrix(m);
Plane expected = new Plane();
double x = target.Normal.X, y = target.Normal.Y, z = target.Normal.Z, w = target.D;
expected.Normal = new Vector3(
x * m.M11 + y * m.M21 + z * m.M31 + w * m.M41,
x * m.M12 + y * m.M22 + z * m.M32 + w * m.M42,
x * m.M13 + y * m.M23 + z * m.M33 + w * m.M43);
expected.D = x * m.M14 + y * m.M24 + z * m.M34 + w * m.M44;
Plane actual;
actual = Plane.Transform(target, q);
Assert.True(MathHelper.Equal(expected, actual), "Plane.Transform did not return the expected value.");
}
// A test for Plane comparison involving NaN values
[Fact]
public void PlaneEqualsNanTest()
{
Plane a = new Plane(double.NaN, 0, 0, 0);
Plane b = new Plane(0, double.NaN, 0, 0);
Plane c = new Plane(0, 0, double.NaN, 0);
Plane d = new Plane(0, 0, 0, double.NaN);
Assert.False(a == new Plane(0, 0, 0, 0));
Assert.False(b == new Plane(0, 0, 0, 0));
Assert.False(c == new Plane(0, 0, 0, 0));
Assert.False(d == new Plane(0, 0, 0, 0));
Assert.True(a != new Plane(0, 0, 0, 0));
Assert.True(b != new Plane(0, 0, 0, 0));
Assert.True(c != new Plane(0, 0, 0, 0));
Assert.True(d != new Plane(0, 0, 0, 0));
Assert.False(a.Equals(new Plane(0, 0, 0, 0)));
Assert.False(b.Equals(new Plane(0, 0, 0, 0)));
Assert.False(c.Equals(new Plane(0, 0, 0, 0)));
Assert.False(d.Equals(new Plane(0, 0, 0, 0)));
// Counterintuitive result - IEEE rules for NaN comparison are weird!
Assert.False(a.Equals(a));
Assert.False(b.Equals(b));
Assert.False(c.Equals(c));
Assert.False(d.Equals(d));
}
/* Enable when size of Vector3 is correct
// A test to make sure these types are blittable directly into GPU buffer memory layouts
[Fact]
public unsafe void PlaneSizeofTest()
{
Assert.Equal(16, sizeof(Plane));
Assert.Equal(32, sizeof(Plane_2x));
Assert.Equal(20, sizeof(PlanePlusFloat));
Assert.Equal(40, sizeof(PlanePlusFloat_2x));
}
*/
[Fact]
public void PlaneToStringTest()
{
Plane target = new Plane(1, 2, 3, 4);
string expected = string.Format(
CultureInfo.CurrentCulture,
"{{Normal:{0:G} D:{1}}}",
target.Normal,
target.D);
Assert.Equal(expected, target.ToString());
}
[StructLayout(LayoutKind.Sequential)]
struct Plane_2x
{
private Plane _a;
private Plane _b;
}
[StructLayout(LayoutKind.Sequential)]
struct PlanePlusFloat
{
private Plane _v;
private double _f;
}
[StructLayout(LayoutKind.Sequential)]
struct PlanePlusFloat_2x
{
private PlanePlusFloat _a;
private PlanePlusFloat _b;
}
// A test to make sure the fields are laid out how we expect
[Fact]
public unsafe void PlaneFieldOffsetTest()
{
Plane plane = new Plane();
double* basePtr = &plane.Normal.X; // Take address of first element
Plane* planePtr = &plane; // Take address of whole Plane
Assert.Equal(new IntPtr(basePtr), new IntPtr(planePtr));
Assert.Equal(new IntPtr(basePtr + 0), new IntPtr(&plane.Normal));
Assert.Equal(new IntPtr(basePtr + 3), new IntPtr(&plane.D));
}
}
}
-988
View File
@@ -1,988 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.DoubleNumerics;
using System.Globalization;
using System.Runtime.InteropServices;
using Xunit;
namespace System.Numerics.Tests
{
public class QuaternionTests
{
// A test for Dot (Quaternion, Quaternion)
[Fact]
public void QuaternionDotTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion b = new Quaternion(5.0, 6.0, 7.0, 8.0);
double expected = 70.0;
double actual;
actual = Quaternion.Dot(a, b);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Dot did not return the expected value.");
}
// A test for Length ()
[Fact]
public void QuaternionLengthTest()
{
Vector3 v = new Vector3(1.0, 2.0, 3.0);
double w = 4.0;
Quaternion target = new Quaternion(v, w);
double expected = 5.477226;
double actual;
actual = target.Length();
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Length did not return the expected value.");
}
// A test for LengthSquared ()
[Fact]
public void QuaternionLengthSquaredTest()
{
Vector3 v = new Vector3(1.0, 2.0, 3.0);
double w = 4.0;
Quaternion target = new Quaternion(v, w);
double expected = 30.0;
double actual;
actual = target.LengthSquared();
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.LengthSquared did not return the expected value.");
}
// A test for Lerp (Quaternion, Quaternion, double)
[Fact]
public void QuaternionLerpTest()
{
Vector3 axis = Vector3.Normalize(new Vector3(1.0, 2.0, 3.0));
Quaternion a = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(10.0));
Quaternion b = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(30.0));
double t = 0.5;
Quaternion expected = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(20.0));
Quaternion actual;
actual = Quaternion.Lerp(a, b, t);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Lerp did not return the expected value.");
// Case a and b are same.
expected = a;
actual = Quaternion.Lerp(a, a, t);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Lerp did not return the expected value.");
}
// A test for Lerp (Quaternion, Quaternion, double)
// Lerp test when t = 0
[Fact]
public void QuaternionLerpTest1()
{
Vector3 axis = Vector3.Normalize(new Vector3(1.0, 2.0, 3.0));
Quaternion a = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(10.0));
Quaternion b = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(30.0));
double t = 0.0;
Quaternion expected = new Quaternion(a.X, a.Y, a.Z, a.W);
Quaternion actual = Quaternion.Lerp(a, b, t);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Lerp did not return the expected value.");
}
// A test for Lerp (Quaternion, Quaternion, double)
// Lerp test when t = 1
[Fact]
public void QuaternionLerpTest2()
{
Vector3 axis = Vector3.Normalize(new Vector3(1.0, 2.0, 3.0));
Quaternion a = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(10.0));
Quaternion b = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(30.0));
double t = 1.0;
Quaternion expected = new Quaternion(b.X, b.Y, b.Z, b.W);
Quaternion actual = Quaternion.Lerp(a, b, t);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Lerp did not return the expected value.");
}
// A test for Lerp (Quaternion, Quaternion, double)
// Lerp test when the two quaternions are more than 90 degree (dot product <0)
[Fact]
public void QuaternionLerpTest3()
{
Vector3 axis = Vector3.Normalize(new Vector3(1.0, 2.0, 3.0));
Quaternion a = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(10.0));
Quaternion b = Quaternion.Negate(a);
double t = 1.0;
Quaternion actual = Quaternion.Lerp(a, b, t);
// Note that in quaternion world, Q == -Q. In the case of quaternions dot product is zero,
// one of the quaternion will be flipped to compute the shortest distance. When t = 1, we
// expect the result to be the same as quaternion b but flipped.
Assert.True(actual == a, "Quaternion.Lerp did not return the expected value.");
}
// A test for Conjugate(Quaternion)
[Fact]
public void QuaternionConjugateTest1()
{
Quaternion a = new Quaternion(1, 2, 3, 4);
Quaternion expected = new Quaternion(-1, -2, -3, 4);
Quaternion actual;
actual = Quaternion.Conjugate(a);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Conjugate did not return the expected value.");
}
// A test for Normalize (Quaternion)
[Fact]
public void QuaternionNormalizeTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion expected = new Quaternion(0.182574168, 0.365148336, 0.5477225, 0.7302967);
Quaternion actual;
actual = Quaternion.Normalize(a);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Normalize did not return the expected value.");
}
// A test for Normalize (Quaternion)
// Normalize zero length quaternion
[Fact]
public void QuaternionNormalizeTest1()
{
Quaternion a = new Quaternion(0.0, 0.0, -0.0, 0.0);
Quaternion actual = Quaternion.Normalize(a);
Assert.True(double.IsNaN(actual.X) && double.IsNaN(actual.Y) && double.IsNaN(actual.Z) && double.IsNaN(actual.W)
, "Quaternion.Normalize did not return the expected value.");
}
// A test for Concatenate(Quaternion, Quaternion)
[Fact]
public void QuaternionConcatenateTest1()
{
Quaternion b = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion a = new Quaternion(5.0, 6.0, 7.0, 8.0);
Quaternion expected = new Quaternion(24.0, 48.0, 48.0, -6.0);
Quaternion actual;
actual = Quaternion.Concatenate(a, b);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Concatenate did not return the expected value.");
}
// A test for operator - (Quaternion, Quaternion)
[Fact]
public void QuaternionSubtractionTest()
{
Quaternion a = new Quaternion(1.0, 6.0, 7.0, 4.0);
Quaternion b = new Quaternion(5.0, 2.0, 3.0, 8.0);
Quaternion expected = new Quaternion(-4.0, 4.0, 4.0, -4.0);
Quaternion actual;
actual = a - b;
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator - did not return the expected value.");
}
// A test for operator * (Quaternion, double)
[Fact]
public void QuaternionMultiplyTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
double factor = 0.5;
Quaternion expected = new Quaternion(0.5, 1.0, 1.5, 2.0);
Quaternion actual;
actual = a * factor;
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator * did not return the expected value.");
}
// A test for operator * (Quaternion, Quaternion)
[Fact]
public void QuaternionMultiplyTest1()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion b = new Quaternion(5.0, 6.0, 7.0, 8.0);
Quaternion expected = new Quaternion(24.0, 48.0, 48.0, -6.0);
Quaternion actual;
actual = a * b;
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator * did not return the expected value.");
}
// A test for operator / (Quaternion, Quaternion)
[Fact]
public void QuaternionDivisionTest1()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion b = new Quaternion(5.0, 6.0, 7.0, 8.0);
Quaternion expected = new Quaternion(-0.045977015, -0.09195402, -7.450581E-9, 0.402298868);
Quaternion actual;
actual = a / b;
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator / did not return the expected value.");
}
// A test for operator + (Quaternion, Quaternion)
[Fact]
public void QuaternionAdditionTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion b = new Quaternion(5.0, 6.0, 7.0, 8.0);
Quaternion expected = new Quaternion(6.0, 8.0, 10.0, 12.0);
Quaternion actual;
actual = a + b;
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator + did not return the expected value.");
}
// A test for Quaternion (double, double, double, double)
[Fact]
public void QuaternionConstructorTest()
{
double x = 1.0;
double y = 2.0;
double z = 3.0;
double w = 4.0;
Quaternion target = new Quaternion(x, y, z, w);
Assert.True(MathHelper.Equal(target.X, x) && MathHelper.Equal(target.Y, y) && MathHelper.Equal(target.Z, z) && MathHelper.Equal(target.W, w),
"Quaternion.constructor (x,y,z,w) did not return the expected value.");
}
// A test for Quaternion (Vector3, double)
[Fact]
public void QuaternionConstructorTest1()
{
Vector3 v = new Vector3(1.0, 2.0, 3.0);
double w = 4.0;
Quaternion target = new Quaternion(v, w);
Assert.True(MathHelper.Equal(target.X, v.X) && MathHelper.Equal(target.Y, v.Y) && MathHelper.Equal(target.Z, v.Z) && MathHelper.Equal(target.W, w),
"Quaternion.constructor (Vector3,w) did not return the expected value.");
}
// A test for CreateFromAxisAngle (Vector3, double)
[Fact]
public void QuaternionCreateFromAxisAngleTest()
{
Vector3 axis = Vector3.Normalize(new Vector3(1.0, 2.0, 3.0));
double angle = MathHelper.ToRadians(30.0);
Quaternion expected = new Quaternion(0.0691723, 0.1383446, 0.207516879, 0.9659258);
Quaternion actual;
actual = Quaternion.CreateFromAxisAngle(axis, angle);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.CreateFromAxisAngle did not return the expected value.");
}
// A test for CreateFromAxisAngle (Vector3, double)
// CreateFromAxisAngle of zero vector
[Fact]
public void QuaternionCreateFromAxisAngleTest1()
{
Vector3 axis = new Vector3();
double angle = MathHelper.ToRadians(-30.0);
double cos = (double)Math.Cos(angle / 2.0);
Quaternion actual = Quaternion.CreateFromAxisAngle(axis, angle);
Assert.True(actual.X == 0.0 && actual.Y == 0.0 && actual.Z == 0.0 && MathHelper.Equal(cos, actual.W)
, "Quaternion.CreateFromAxisAngle did not return the expected value.");
}
// A test for CreateFromAxisAngle (Vector3, double)
// CreateFromAxisAngle of angle = 30 && 750
[Fact]
public void QuaternionCreateFromAxisAngleTest2()
{
Vector3 axis = new Vector3(1, 0, 0);
double angle1 = MathHelper.ToRadians(30.0);
double angle2 = MathHelper.ToRadians(750.0);
Quaternion actual1 = Quaternion.CreateFromAxisAngle(axis, angle1);
Quaternion actual2 = Quaternion.CreateFromAxisAngle(axis, angle2);
Assert.True(MathHelper.Equal(actual1, actual2), "Quaternion.CreateFromAxisAngle did not return the expected value.");
}
// A test for CreateFromAxisAngle (Vector3, double)
// CreateFromAxisAngle of angle = 30 && 390
[Fact]
public void QuaternionCreateFromAxisAngleTest3()
{
Vector3 axis = new Vector3(1, 0, 0);
double angle1 = MathHelper.ToRadians(30.0);
double angle2 = MathHelper.ToRadians(390.0);
Quaternion actual1 = Quaternion.CreateFromAxisAngle(axis, angle1);
Quaternion actual2 = Quaternion.CreateFromAxisAngle(axis, angle2);
actual1.X = -actual1.X;
actual1.W = -actual1.W;
Assert.True(MathHelper.Equal(actual1, actual2), "Quaternion.CreateFromAxisAngle did not return the expected value.");
}
[Fact]
public void QuaternionCreateFromYawPitchRollTest1()
{
double yawAngle = MathHelper.ToRadians(30.0);
double pitchAngle = MathHelper.ToRadians(40.0);
double rollAngle = MathHelper.ToRadians(50.0);
Quaternion yaw = Quaternion.CreateFromAxisAngle(Vector3.UnitY, yawAngle);
Quaternion pitch = Quaternion.CreateFromAxisAngle(Vector3.UnitX, pitchAngle);
Quaternion roll = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, rollAngle);
Quaternion expected = yaw * pitch * roll;
Quaternion actual = Quaternion.CreateFromYawPitchRoll(yawAngle, pitchAngle, rollAngle);
Assert.True(MathHelper.Equal(expected, actual));
}
// Covers more numeric rigions
[Fact]
public void QuaternionCreateFromYawPitchRollTest2()
{
const double step = 35.0;
for (double yawAngle = -720.0; yawAngle <= 720.0; yawAngle += step)
{
for (double pitchAngle = -720.0; pitchAngle <= 720.0; pitchAngle += step)
{
for (double rollAngle = -720.0; rollAngle <= 720.0; rollAngle += step)
{
double yawRad = MathHelper.ToRadians(yawAngle);
double pitchRad = MathHelper.ToRadians(pitchAngle);
double rollRad = MathHelper.ToRadians(rollAngle);
Quaternion yaw = Quaternion.CreateFromAxisAngle(Vector3.UnitY, yawRad);
Quaternion pitch = Quaternion.CreateFromAxisAngle(Vector3.UnitX, pitchRad);
Quaternion roll = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, rollRad);
Quaternion expected = yaw * pitch * roll;
Quaternion actual = Quaternion.CreateFromYawPitchRoll(yawRad, pitchRad, rollRad);
Assert.True(MathHelper.Equal(expected, actual), String.Format("Yaw:{0} Pitch:{1} Roll:{2}", yawAngle, pitchAngle, rollAngle));
}
}
}
}
// A test for Slerp (Quaternion, Quaternion, double)
[Fact]
public void QuaternionSlerpTest()
{
Vector3 axis = Vector3.Normalize(new Vector3(1.0, 2.0, 3.0));
Quaternion a = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(10.0));
Quaternion b = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(30.0));
double t = 0.5;
Quaternion expected = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(20.0));
Quaternion actual;
actual = Quaternion.Slerp(a, b, t);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Slerp did not return the expected value.");
// Case a and b are same.
expected = a;
actual = Quaternion.Slerp(a, a, t);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Slerp did not return the expected value.");
}
// A test for Slerp (Quaternion, Quaternion, double)
// Slerp test where t = 0
[Fact]
public void QuaternionSlerpTest1()
{
Vector3 axis = Vector3.Normalize(new Vector3(1.0, 2.0, 3.0));
Quaternion a = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(10.0));
Quaternion b = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(30.0));
double t = 0.0;
Quaternion expected = new Quaternion(a.X, a.Y, a.Z, a.W);
Quaternion actual = Quaternion.Slerp(a, b, t);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Slerp did not return the expected value.");
}
// A test for Slerp (Quaternion, Quaternion, double)
// Slerp test where t = 1
[Fact]
public void QuaternionSlerpTest2()
{
Vector3 axis = Vector3.Normalize(new Vector3(1.0, 2.0, 3.0));
Quaternion a = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(10.0));
Quaternion b = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(30.0));
double t = 1.0;
Quaternion expected = new Quaternion(b.X, b.Y, b.Z, b.W);
Quaternion actual = Quaternion.Slerp(a, b, t);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Slerp did not return the expected value.");
}
// A test for Slerp (Quaternion, Quaternion, double)
// Slerp test where dot product is < 0
[Fact]
public void QuaternionSlerpTest3()
{
Vector3 axis = Vector3.Normalize(new Vector3(1.0, 2.0, 3.0));
Quaternion a = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(10.0));
Quaternion b = -a;
double t = 1.0;
Quaternion expected = a;
Quaternion actual = Quaternion.Slerp(a, b, t);
// Note that in quaternion world, Q == -Q. In the case of quaternions dot product is zero,
// one of the quaternion will be flipped to compute the shortest distance. When t = 1, we
// expect the result to be the same as quaternion b but flipped.
Assert.True(actual == expected, "Quaternion.Slerp did not return the expected value.");
}
// A test for Slerp (Quaternion, Quaternion, double)
// Slerp test where the quaternion is flipped
[Fact]
public void QuaternionSlerpTest4()
{
Vector3 axis = Vector3.Normalize(new Vector3(1.0, 2.0, 3.0));
Quaternion a = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(10.0));
Quaternion b = -Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(30.0));
double t = 0.0;
Quaternion expected = new Quaternion(a.X, a.Y, a.Z, a.W);
Quaternion actual = Quaternion.Slerp(a, b, t);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Slerp did not return the expected value.");
}
// A test for operator - (Quaternion)
[Fact]
public void QuaternionUnaryNegationTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion expected = new Quaternion(-1.0, -2.0, -3.0, -4.0);
Quaternion actual;
actual = -a;
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator - did not return the expected value.");
}
// A test for Inverse (Quaternion)
[Fact]
public void QuaternionInverseTest()
{
Quaternion a = new Quaternion(5.0, 6.0, 7.0, 8.0);
Quaternion expected = new Quaternion(-0.028735632183908046,-0.034482758620689655, -0.040229885057471264 ,0.045977011494252873);
Quaternion actual;
actual = Quaternion.Inverse(a);
Assert.Equal(expected, actual);
}
// A test for Inverse (Quaternion)
// Invert zero length quaternion
[Fact]
public void QuaternionInverseTest1()
{
Quaternion a = new Quaternion();
Quaternion actual = Quaternion.Inverse(a);
Assert.True(double.IsNaN(actual.X) && double.IsNaN(actual.Y) && double.IsNaN(actual.Z) && double.IsNaN(actual.W)
);
}
// A test for ToString ()
[Fact]
public void QuaternionToStringTest()
{
Quaternion target = new Quaternion(-1.0, 2.2, 3.3, -4.4);
string expected = string.Format(CultureInfo.CurrentCulture
, "{{X:{0} Y:{1} Z:{2} W:{3}}}"
, -1.0, 2.2, 3.3, -4.4);
string actual = target.ToString();
Assert.Equal(expected, actual);
}
// A test for Add (Quaternion, Quaternion)
[Fact]
public void QuaternionAddTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion b = new Quaternion(5.0, 6.0, 7.0, 8.0);
Quaternion expected = new Quaternion(6.0, 8.0, 10.0, 12.0);
Quaternion actual;
actual = Quaternion.Add(a, b);
Assert.Equal(expected, actual);
}
// A test for Divide (Quaternion, Quaternion)
[Fact]
public void QuaternionDivideTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion b = new Quaternion(5.0, 6.0, 7.0, 8.0);
Quaternion expected = new Quaternion(-0.045977015, -0.09195402, -7.450581E-9, 0.402298868);
Quaternion actual;
actual = Quaternion.Divide(a, b);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Divide did not return the expected value.");
}
// A test for Equals (object)
[Fact]
public void QuaternionEqualsTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion b = new Quaternion(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
object obj = b;
bool expected = true;
bool actual = a.Equals(obj);
Assert.Equal(expected, actual);
// case 2: compare between different values
b.X = 10.0;
obj = b;
expected = false;
actual = a.Equals(obj);
Assert.Equal(expected, actual);
// case 3: compare between different types.
obj = new Vector4();
expected = false;
actual = a.Equals(obj);
Assert.Equal(expected, actual);
// case 3: compare against null.
obj = null;
expected = false;
actual = a.Equals(obj);
Assert.Equal(expected, actual);
}
// A test for GetHashCode ()
[Fact]
public void QuaternionGetHashCodeTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
int expected = a.X.GetHashCode() + a.Y.GetHashCode() + a.Z.GetHashCode() + a.W.GetHashCode();
int actual = a.GetHashCode();
Assert.Equal(expected, actual);
}
// A test for Multiply (Quaternion, double)
[Fact]
public void QuaternionMultiplyTest2()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
double factor = 0.5;
Quaternion expected = new Quaternion(0.5, 1.0, 1.5, 2.0);
Quaternion actual;
actual = Quaternion.Multiply(a, factor);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Multiply did not return the expected value.");
}
// A test for Multiply (Quaternion, Quaternion)
[Fact]
public void QuaternionMultiplyTest3()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion b = new Quaternion(5.0, 6.0, 7.0, 8.0);
Quaternion expected = new Quaternion(24.0, 48.0, 48.0, -6.0);
Quaternion actual;
actual = Quaternion.Multiply(a, b);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Multiply did not return the expected value.");
}
// A test for Negate (Quaternion)
[Fact]
public void QuaternionNegateTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion expected = new Quaternion(-1.0, -2.0, -3.0, -4.0);
Quaternion actual;
actual = Quaternion.Negate(a);
Assert.Equal(expected, actual);
}
// A test for Subtract (Quaternion, Quaternion)
[Fact]
public void QuaternionSubtractTest()
{
Quaternion a = new Quaternion(1.0, 6.0, 7.0, 4.0);
Quaternion b = new Quaternion(5.0, 2.0, 3.0, 8.0);
Quaternion expected = new Quaternion(-4.0, 4.0, 4.0, -4.0);
Quaternion actual;
actual = Quaternion.Subtract(a, b);
Assert.Equal(expected, actual);
}
// A test for operator != (Quaternion, Quaternion)
[Fact]
public void QuaternionInequalityTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion b = new Quaternion(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
bool expected = false;
bool actual = a != b;
Assert.Equal(expected, actual);
// case 2: compare between different values
b.X = 10.0;
expected = true;
actual = a != b;
Assert.Equal(expected, actual);
}
// A test for operator == (Quaternion, Quaternion)
[Fact]
public void QuaternionEqualityTest()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion b = new Quaternion(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
bool expected = true;
bool actual = a == b;
Assert.Equal(expected, actual);
// case 2: compare between different values
b.X = 10.0;
expected = false;
actual = a == b;
Assert.Equal(expected, actual);
}
// A test for CreateFromRotationMatrix (Matrix4x4)
// Convert Identity matrix test
[Fact]
public void QuaternionFromRotationMatrixTest1()
{
Matrix4x4 matrix = Matrix4x4.Identity;
Quaternion expected = new Quaternion(0.0, 0.0, 0.0, 1.0);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.Equal(expected, actual), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
}
// A test for CreateFromRotationMatrix (Matrix4x4)
// Convert X axis rotation matrix
[Fact]
public void QuaternionFromRotationMatrixTest2()
{
for (double angle = 0.0; angle < 720.0; angle += 10.0)
{
Matrix4x4 matrix = Matrix4x4.CreateRotationX(angle);
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitX, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.EqualRotation(expected, actual),
string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
angle.ToString(), expected.ToString(), actual.ToString()));
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2),
string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
angle.ToString(), matrix.ToString(), m2.ToString()));
}
}
// A test for CreateFromRotationMatrix (Matrix4x4)
// Convert Y axis rotation matrix
[Fact]
public void QuaternionFromRotationMatrixTest3()
{
for (double angle = 0.0; angle < 720.0; angle += 10.0)
{
Matrix4x4 matrix = Matrix4x4.CreateRotationY(angle);
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitY, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.EqualRotation(expected, actual),
string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0}",
angle.ToString()));
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2),
string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0}",
angle.ToString()));
}
}
// A test for CreateFromRotationMatrix (Matrix4x4)
// Convert Z axis rotation matrix
[Fact]
public void QuaternionFromRotationMatrixTest4()
{
for (double angle = 0.0; angle < 720.0; angle += 10.0)
{
Matrix4x4 matrix = Matrix4x4.CreateRotationZ(angle);
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.EqualRotation(expected, actual),
string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
angle.ToString(), expected.ToString(), actual.ToString()));
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2),
string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
angle.ToString(), matrix.ToString(), m2.ToString()));
}
}
// A test for CreateFromRotationMatrix (Matrix4x4)
// Convert XYZ axis rotation matrix
[Fact]
public void QuaternionFromRotationMatrixTest5()
{
for (double angle = 0.0; angle < 720.0; angle += 10.0)
{
Matrix4x4 matrix = Matrix4x4.CreateRotationX(angle) * Matrix4x4.CreateRotationY(angle) * Matrix4x4.CreateRotationZ(angle);
Quaternion expected =
Quaternion.CreateFromAxisAngle(Vector3.UnitZ, angle) *
Quaternion.CreateFromAxisAngle(Vector3.UnitY, angle) *
Quaternion.CreateFromAxisAngle(Vector3.UnitX, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.EqualRotation(expected, actual),
string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
angle.ToString(), expected.ToString(), actual.ToString()));
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2),
string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
angle.ToString(), matrix.ToString(), m2.ToString()));
}
}
// A test for CreateFromRotationMatrix (Matrix4x4)
// X axis is most large axis case
[Fact]
public void QuaternionFromRotationMatrixWithScaledMatrixTest1()
{
double angle = MathHelper.ToRadians(180.0);
Matrix4x4 matrix = Matrix4x4.CreateRotationY(angle) * Matrix4x4.CreateRotationZ(angle);
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, angle) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.EqualRotation(expected, actual), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
}
// A test for CreateFromRotationMatrix (Matrix4x4)
// Y axis is most large axis case
[Fact]
public void QuaternionFromRotationMatrixWithScaledMatrixTest2()
{
double angle = MathHelper.ToRadians(180.0);
Matrix4x4 matrix = Matrix4x4.CreateRotationX(angle) * Matrix4x4.CreateRotationZ(angle);
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, angle) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.EqualRotation(expected, actual), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
}
// A test for CreateFromRotationMatrix (Matrix4x4)
// Z axis is most large axis case
[Fact]
public void QuaternionFromRotationMatrixWithScaledMatrixTest3()
{
double angle = MathHelper.ToRadians(180.0);
Matrix4x4 matrix = Matrix4x4.CreateRotationX(angle) * Matrix4x4.CreateRotationY(angle);
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitY, angle) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.EqualRotation(expected, actual), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
}
// A test for Equals (Quaternion)
[Fact]
public void QuaternionEqualsTest1()
{
Quaternion a = new Quaternion(1.0, 2.0, 3.0, 4.0);
Quaternion b = new Quaternion(1.0, 2.0, 3.0, 4.0);
// case 1: compare between same values
bool expected = true;
bool actual = a.Equals(b);
Assert.Equal(expected, actual);
// case 2: compare between different values
b.X = 10.0;
expected = false;
actual = a.Equals(b);
Assert.Equal(expected, actual);
}
// A test for Identity
[Fact]
public void QuaternionIdentityTest()
{
Quaternion val = new Quaternion(0, 0, 0, 1);
Assert.Equal(val, Quaternion.Identity);
}
// A test for IsIdentity
[Fact]
public void QuaternionIsIdentityTest()
{
Assert.True(Quaternion.Identity.IsIdentity);
Assert.True(new Quaternion(0, 0, 0, 1).IsIdentity);
Assert.False(new Quaternion(1, 0, 0, 1).IsIdentity);
Assert.False(new Quaternion(0, 1, 0, 1).IsIdentity);
Assert.False(new Quaternion(0, 0, 1, 1).IsIdentity);
Assert.False(new Quaternion(0, 0, 0, 0).IsIdentity);
}
// A test for Quaternion comparison involving NaN values
[Fact]
public void QuaternionEqualsNanTest()
{
Quaternion a = new Quaternion(double.NaN, 0, 0, 0);
Quaternion b = new Quaternion(0, double.NaN, 0, 0);
Quaternion c = new Quaternion(0, 0, double.NaN, 0);
Quaternion d = new Quaternion(0, 0, 0, double.NaN);
Assert.False(a == new Quaternion(0, 0, 0, 0));
Assert.False(b == new Quaternion(0, 0, 0, 0));
Assert.False(c == new Quaternion(0, 0, 0, 0));
Assert.False(d == new Quaternion(0, 0, 0, 0));
Assert.True(a != new Quaternion(0, 0, 0, 0));
Assert.True(b != new Quaternion(0, 0, 0, 0));
Assert.True(c != new Quaternion(0, 0, 0, 0));
Assert.True(d != new Quaternion(0, 0, 0, 0));
Assert.False(a.Equals(new Quaternion(0, 0, 0, 0)));
Assert.False(b.Equals(new Quaternion(0, 0, 0, 0)));
Assert.False(c.Equals(new Quaternion(0, 0, 0, 0)));
Assert.False(d.Equals(new Quaternion(0, 0, 0, 0)));
Assert.False(a.IsIdentity);
Assert.False(b.IsIdentity);
Assert.False(c.IsIdentity);
Assert.False(d.IsIdentity);
// Counterintuitive result - IEEE rules for NaN comparison are weird!
Assert.False(a.Equals(a));
Assert.False(b.Equals(b));
Assert.False(c.Equals(c));
Assert.False(d.Equals(d));
}
// A test to make sure these types are blittable directly into GPU buffer memory layouts
[Fact]
public unsafe void QuaternionSizeofTest()
{
Assert.Equal(16*2, sizeof(Quaternion));
Assert.Equal(32*2, sizeof(Quaternion_2x));
Assert.Equal(20*2, sizeof(QuaternionPlusFloat));
Assert.Equal(40*2, sizeof(QuaternionPlusFloat_2x));
}
[StructLayout(LayoutKind.Sequential)]
struct Quaternion_2x
{
private Quaternion _a;
private Quaternion _b;
}
[StructLayout(LayoutKind.Sequential)]
struct QuaternionPlusFloat
{
private Quaternion _v;
private double _f;
}
[StructLayout(LayoutKind.Sequential)]
struct QuaternionPlusFloat_2x
{
private QuaternionPlusFloat _a;
private QuaternionPlusFloat _b;
}
// A test to make sure the fields are laid out how we expect
[Fact]
public unsafe void QuaternionFieldOffsetTest()
{
Quaternion quat = new Quaternion();
double* basePtr = &quat.X; // Take address of first element
Quaternion* quatPtr = &quat; // Take address of whole Quaternion
Assert.Equal(new IntPtr(basePtr), new IntPtr(quatPtr));
Assert.Equal(new IntPtr(basePtr + 0), new IntPtr(&quat.X));
Assert.Equal(new IntPtr(basePtr + 1), new IntPtr(&quat.Y));
Assert.Equal(new IntPtr(basePtr + 2), new IntPtr(&quat.Z));
Assert.Equal(new IntPtr(basePtr + 3), new IntPtr(&quat.W));
}
}
}
@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<Project Include="System.Numerics.Vectors.Tests.csproj"/>
<Project Include="System.Numerics.Vectors.Tests.csproj">
<TestTFMs>netcore50;net46</TestTFMs>
<OSGroup>Windows_NT</OSGroup>
</Project>
<Project Include="Performance\System.Numerics.Vectors.Performance.Tests.csproj"/>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
</Project>
@@ -1,88 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A7074928-82C3-4739-88FE-9B528977950C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>System.Numerics.Tests</RootNamespace>
<AssemblyName>System.Numerics.Vectors.Tests</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NuGetPackageImportStamp>11f13d9c</NuGetPackageImportStamp>
<NugetTargetMoniker>.NETStandard,Version=v1.3</NugetTargetMoniker>
<OutputPath>bin\$(Configuration)\</OutputPath>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<TargetFrameworkProfile />
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Compile Include="Common\System\PlatDetect.cs" />
<Compile Include="ConstantHelper.cs" />
<Compile Include="Util.cs" />
<Compile Include="Vector2Tests.cs" />
<Compile Include="Vector3Tests.cs" />
<Compile Include="Vector4Tests.cs" />
<Compile Include="MathHelper.cs" />
<Compile Include="Matrix3x2Tests.cs" />
<Compile Include="Matrix4x4Tests.cs" />
<Compile Include="PlaneTests.cs" />
<Compile Include="QuaternionTests.cs" />
</ItemGroup>
<ItemGroup>
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<None Include="..\src\System\Numerics\GenerationConfig.ttinclude">
<Link>GenerationConfig.ttinclude</Link>
</None>
<None Include="GenericVectorTests.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>GenericVectorTests.cs</LastGenOutput>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)packages\System.Runtime.InteropServices.RuntimeInformation.4.0.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.assert, Version=2.2.0.3300, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)packages\xunit.assert.2.2.0-beta2-build3300\lib\netstandard1.0\xunit.assert.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.core, Version=2.2.0.3300, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)packages\xunit.extensibility.core.2.2.0-beta2-build3300\lib\net45\xunit.core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="xunit.execution.desktop, Version=2.2.0.3300, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)packages\xunit.extensibility.execution.2.2.0-beta2-build3300\lib\net45\xunit.execution.desktop.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\System.DoubleNumerics\System.DoubleNumerics.csproj">
<Project>{18483631-763c-48a4-9045-a3c3f93d23f9}</Project>
<Name>System.DoubleNumerics</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
-211
View File
@@ -1,211 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Linq;
namespace System.Numerics.Tests
{
public static class Util
{
private static Random s_random = new Random();
public static void SetRandomSeed(int seed)
{
s_random = new Random(seed);
}
/// <summary>
/// Generates random floats between 0 and 100.
/// </summary>
/// <param name="numValues">The number of values to generate</param>
/// <returns>An array containing the random floats</returns>
public static double[] GenerateRandomFloats(int numValues)
{
double[] values = new double[numValues];
for (int g = 0; g < numValues; g++)
{
values[g] = (double)(s_random.NextDouble() * 99 + 1);
}
return values;
}
/// <summary>
/// Generates random ints between 0 and 99, inclusive.
/// </summary>
/// <param name="numValues">The number of values to generate</param>
/// <returns>An array containing the random ints</returns>
public static int[] GenerateRandomInts(int numValues)
{
int[] values = new int[numValues];
for (int g = 0; g < numValues; g++)
{
values[g] = s_random.Next(1, 100);
}
return values;
}
/// <summary>
/// Generates random doubles between 0 and 100.
/// </summary>
/// <param name="numValues">The number of values to generate</param>
/// <returns>An array containing the random doubles</returns>
public static double[] GenerateRandomDoubles(int numValues)
{
double[] values = new double[numValues];
for (int g = 0; g < numValues; g++)
{
values[g] = s_random.NextDouble() * 99 + 1;
}
return values;
}
/// <summary>
/// Generates random doubles between 1 and 100.
/// </summary>
/// <param name="numValues">The number of values to generate</param>
/// <returns>An array containing the random doubles</returns>
public static long[] GenerateRandomLongs(int numValues)
{
long[] values = new long[numValues];
for (int g = 0; g < numValues; g++)
{
values[g] = s_random.Next(1, 100) * (long.MaxValue / int.MaxValue);
}
return values;
}
public static T[] GenerateRandomValues<T>(int numValues, int min = 1, int max = 100) where T : struct
{
T[] values = new T[numValues];
for (int g = 0; g < numValues; g++)
{
values[g] = GenerateSingleValue<T>(min, max);
}
return values;
}
public static T GenerateSingleValue<T>(int min = 1, int max = 100) where T : struct
{
var randomRange = s_random.Next(min, max);
T value = (T)(dynamic)randomRange;
return value;
}
public static T Abs<T>(T value) where T : struct
{
Type[] unsignedTypes = new[] { typeof(Byte), typeof(UInt16), typeof(UInt32), typeof(UInt64) };
if (unsignedTypes.Contains(typeof(T)))
{
return value;
}
dynamic dyn = (dynamic)value;
var abs = Math.Abs(dyn);
T ret = (T)abs;
return ret;
}
public static T Sqrt<T>(T value) where T : struct
{
return (T)(dynamic)(Math.Sqrt((dynamic)value));
}
public static T Multiply<T>(T left, T right) where T : struct
{
return (T)((dynamic)left * right);
}
public static T Divide<T>(T left, T right) where T : struct
{
return (T)((dynamic)left / right);
}
public static T Add<T>(T left, T right) where T : struct
{
return (T)((dynamic)left + right);
}
public static T Subtract<T>(T left, T right) where T : struct
{
return (T)((dynamic)left - right);
}
public static T Xor<T>(T left, T right) where T : struct
{
return (T)((dynamic)left ^ right);
}
public static T AndNot<T>(T left, T right) where T : struct
{
return (T)((dynamic)left & ~(dynamic)right);
}
public static T OnesComplement<T>(T left) where T : struct
{
return (T)(~(dynamic)left);
}
public static double Clamp(double value, double min, double max)
{
return value > max ? max : value < min ? min : value;
}
public static T Zero<T>() where T : struct
{
return (T)(dynamic)0;
}
public static T One<T>() where T : struct
{
return (T)(dynamic)1;
}
public static bool GreaterThan<T>(T left, T right) where T : struct
{
var result = (dynamic)left > right;
return (bool)result;
}
public static bool GreaterThanOrEqual<T>(T left, T right) where T : struct
{
var result = (dynamic)left >= right;
return (bool)result;
}
public static bool LessThan<T>(T left, T right) where T : struct
{
var result = (dynamic)left < right;
return (bool)result;
}
public static bool LessThanOrEqual<T>(T left, T right) where T : struct
{
var result = (dynamic)left <= right;
return (bool)result;
}
public static bool AnyEqual<T>(T[] left, T[] right) where T : struct
{
for (int g = 0; g < left.Length; g++)
{
if (((IEquatable<T>)left[g]).Equals(right[g]))
{
return true;
}
}
return false;
}
public static bool AllEqual<T>(T[] left, T[] right) where T : struct
{
for (int g = 0; g < left.Length; g++)
{
if (!((IEquatable<T>)left[g]).Equals(right[g]))
{
return false;
}
}
return true;
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More