├── .editorconfig
├── .github
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ ├── build-test.yml
│ ├── deploy.yaml
│ └── greetings.yaml
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
└── tasks.json
├── CHANGELOG.md
├── LICENSE
├── Paramdigma.Core.sln
├── Paramdigma.Core.sln.DotSettings
├── README.md
├── coverage
└── cobertura.xml
├── docfx_project
├── .gitignore
├── api
│ ├── .gitignore
│ └── index.md
├── articles
│ ├── intro.md
│ └── toc.yml
├── docfx.json
├── index.md
└── toc.yml
├── src
├── Collections
│ ├── Interval.cs
│ └── Matrix{T}.cs
├── Curves
│ ├── Geodesics.cs
│ └── LevelSets.cs
├── Data
│ └── Settings.json
├── Exceptions
│ └── UnsetGeometryException.cs
├── Extensions
│ └── Lists.cs
├── Geometry
│ ├── Base
│ │ ├── BaseCurve.cs
│ │ ├── BasePoint.cs
│ │ └── InvalidCurveException.cs
│ ├── Box.cs
│ ├── Circle.cs
│ ├── Cylinder.cs
│ ├── Interfaces
│ │ ├── ICurve.cs
│ │ ├── ISurface.cs
│ │ └── IVector.cs
│ ├── Intersect
│ │ ├── Intersect.cs
│ │ └── IntersectErrors.cs
│ ├── Line.cs
│ ├── Line2d.cs
│ ├── Mesh.cs
│ ├── MeshCorner.cs
│ ├── MeshEdge.cs
│ ├── MeshFace.cs
│ ├── MeshGeometry.cs
│ ├── MeshHalfEdge.cs
│ ├── MeshPoint.cs
│ ├── MeshTopology.cs
│ ├── MeshVertex.cs
│ ├── NurbsCalculator.cs
│ ├── NurbsCurve.cs
│ ├── NurbsSurface.cs
│ ├── Plane.cs
│ ├── Point2d.cs
│ ├── Point3d.cs
│ ├── Point4d.cs
│ ├── Polyline.cs
│ ├── Polyline2d.cs
│ ├── Ray.cs
│ ├── Ray2d.cs
│ ├── Rectangle2d.cs
│ ├── Sphere.cs
│ ├── Torus.cs
│ ├── Vector2d.cs
│ ├── Vector3d.cs
│ └── VectorNd.cs
├── IO
│ ├── CSVReader.cs
│ ├── CSVWritter.cs
│ ├── OBJMeshData.cs
│ ├── OBJReader.cs
│ ├── OBJWritter.cs
│ ├── OFFMeshData.cs
│ ├── OFFReader.cs
│ ├── OFFResult.cs
│ └── OffWriter.cs
├── LinearAlgebra
│ ├── Complex.cs
│ ├── LeastSquaresLinearFit.cs
│ └── Triplet.cs
├── Optimization
│ ├── GradientDescent.cs
│ ├── GradientDescentOptions.cs
│ ├── GradientDescentResult.cs
│ ├── KMeansCluster.cs
│ └── KMeansClustering.cs
├── Paramdigma.Core.Rules.ruleset
├── Paramdigma.Core.csproj
├── Spatial
│ ├── Delaunay.cs
│ ├── DelaunayEdge.cs
│ ├── DelaunayPoint.cs
│ ├── DelaunayTriangle.cs
│ ├── Octree.cs
│ ├── PointCloud.cs
│ ├── PointCloudMember.cs
│ └── Quadtree.cs
└── Utility
│ ├── Convert.cs
│ └── Settings.cs
└── tests
├── Collections
└── IntervalTests.cs
├── Curves
└── LevelSetsTests.cs
├── Data
└── meshes
│ ├── cube.off
│ ├── parabolicCyclide.off
│ ├── sphere.off
│ └── test.off
├── Extensions
└── ListExtensionsTests.cs
├── Geometry
├── 2D
│ ├── DelaunayTests.cs
│ ├── Line2dTests.cs
│ ├── Point2dTests.cs
│ ├── Polyline2dTests.cs
│ ├── Ray2dTests.cs
│ └── Vector2dTests.cs
├── 3D
│ ├── BoxTests.cs
│ ├── CircleTests.cs
│ ├── CurveBaseTests.cs
│ ├── CylinderTests.cs
│ ├── Intersect3dTests.cs
│ ├── LineTests.cs
│ ├── MeshCornerTests.cs
│ ├── MeshFaceTests.cs
│ ├── MeshGeometryTests.cs
│ ├── MeshPointTests.cs
│ ├── MeshTests.cs
│ ├── MeshTopologyTests.cs
│ ├── MeshVertexTests.cs
│ ├── NurbsCurveData.cs
│ ├── NurbsCurveTests.cs
│ ├── NurbsSurfaceTests.cs
│ ├── PlaneTests.cs
│ ├── Point3dData.cs
│ ├── Point3dTests.cs
│ ├── Point4dTests.cs
│ ├── Polyline3dTests.cs
│ ├── Ray3dTests.cs
│ ├── SphereTests.cs
│ ├── Vector3dTests.cs
│ ├── VectorEntity_Tests.cs
│ └── VectorNd_Tests.cs
└── SpatialStructures
│ └── QuadTreeTests.cs
├── Optimization
├── GradientDescentOptionsTests.cs
├── GradientDescentTests.cs
└── KMeansClusteringTests.cs
├── Paramdigma.Core.Tests.csproj
├── RhinoConversions.cs
└── Utilities
├── JsonFileDataAttribute.cs
└── ResourcesTests.cs
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Global owners
2 | * @AlanRynne
3 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at alan@rynne.es. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: your_title
5 | labels: your_label
6 | assignees: your_username
7 | ---
8 |
9 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 |
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 |
15 | 1. Go to '...'
16 | 2. Run '...'
17 | 3. See error
18 |
19 | **Expected behavior**
20 | A clear and concise description of what you expected to happen.
21 |
22 | **Screenshots**
23 | If applicable, add screenshots to help explain your problem.s
24 |
25 | **Additional context**
26 | Add any other context about the problem here.
27 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: Feature Request
5 | labels: your_labels
6 | assignees: your_username
7 | ---
8 |
9 | **Is your feature request related to a problem? Please describe.**
10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11 |
12 | **Describe the solution you'd like**
13 | A clear and concise description of what you want to happen.
14 |
15 | **Describe alternatives you've considered**
16 | A clear and concise description of any alternative solutions or features you've considered.
17 |
18 | **Additional context**
19 | Add any other context or screenshots about the feature request here.
20 |
--------------------------------------------------------------------------------
/.github/workflows/build-test.yml:
--------------------------------------------------------------------------------
1 | name: .NET Core
2 |
3 | on:
4 | push:
5 | branches: [ master, develop, ci/* ]
6 | pull_request:
7 | branches: [ master, develop ]
8 |
9 | jobs:
10 | build:
11 |
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - name: 🛎 Checkout repo
16 | uses: actions/checkout@v2
17 | - name: 🚧 Setup .NET Core
18 | uses: actions/setup-dotnet@v1
19 | with:
20 | dotnet-version: 3.1.101
21 | - name: ⚙️ Install dependencies
22 | run: dotnet restore
23 | - name: 🏗 Build
24 | run: dotnet build --configuration Release --no-restore
25 | - name: 🧪 Test
26 | run: dotnet test --no-restore /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput=../coverage/opencover.xml
27 | - name: 📚 Push to Codecov.io
28 | uses: codecov/codecov-action@v1
29 | with:
30 | file: coverage/opencover.xml
31 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yaml:
--------------------------------------------------------------------------------
1 | name: Deploy docs
2 |
3 | on:
4 | push:
5 | # Sequence of patterns matched against refs/tags
6 | tags:
7 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
8 |
9 | jobs:
10 | build_and_publish:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: 🛎 Checkout repo
14 | uses: actions/checkout@v2
15 |
16 | - name: 🚧 Setup .NET Core
17 | uses: actions/setup-dotnet@v1
18 | with:
19 | dotnet-version: 3.1.101
20 | source-url: https://nuget.pkg.github.com/paramdigma/index.json
21 | env:
22 | NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
23 |
24 | - name: ⚙️ Install dependencies
25 | run: dotnet restore
26 |
27 | - name: 🏗 Build
28 | run: dotnet build --configuration Release --no-restore
29 |
30 | - name: 🧪 Test
31 | run: dotnet test --no-restore
32 |
33 | - name: 🗜 Compress build files # This would actually build your project, using zip for an example artifact
34 | run: zip --junk-paths ./Paramdigma.Core.zip ./src/bin/Release/netstandard2.0/*
35 |
36 | - name: 📘 Create Release
37 | id: create_release
38 | uses: actions/create-release@v1
39 | env:
40 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41 | with:
42 | tag_name: ${{ github.ref }}
43 | release_name: Release ${{ github.ref }}
44 | draft: false
45 | prerelease: true
46 | - name: 📜 Upload Release Asset
47 | id: upload-release-asset
48 | uses: actions/upload-release-asset@v1
49 | env:
50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51 | with:
52 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
53 | asset_path: ./Paramdigma.Core.zip
54 | asset_name: Paramdigma.Core.zip
55 | asset_content_type: application/zip
56 |
57 | - name: 📦 Create the package
58 | run: dotnet pack --configuration Release src/Paramdigma.Core.csproj
59 | - name: 🚀 Publish the package to GPR
60 | run: dotnet nuget push src/bin/Release/*.nupkg -k ${PUSH_TOKEN}
61 | env:
62 | PUSH_TOKEN: ${{secrets.GITHUB_TOKEN}}
63 |
64 | deploy_docs:
65 | runs-on: ubuntu-latest
66 | name: Docs build & deploy
67 | needs: build_and_publish
68 | steps:
69 | - uses: actions/checkout@v2
70 | name: 🛎 Checkout
71 | - run: "rm .gitignore && ls ."
72 | name: 🗑 Remove .gitignore file
73 | - uses: nikeee/docfx-action@master
74 | name: 📚 Build Docs
75 | with:
76 | args: docfx_project/docfx.json
77 | - name: 🚀 Deploy
78 | uses: JamesIves/github-pages-deploy-action@releases/v3
79 | with:
80 | BRANCH: gh-pages # The branch the action should deploy to.
81 | FOLDER: docs/ # The folder the action should deploy.
82 |
--------------------------------------------------------------------------------
/.github/workflows/greetings.yaml:
--------------------------------------------------------------------------------
1 | name: Greet first-time contributors
2 |
3 | on: [pull_request, issues]
4 |
5 | jobs:
6 | greeting:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/first-interaction@v1
10 | with:
11 | repo-token: ${{ secrets.GITHUB_TOKEN }}
12 | issue-message: 'This is your first issue! Thanks for taking the time to do this!!'
13 | pr-message: 'This is your first PR! Thanks for making Paramdigma.Core a little better!'
14 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4 |
5 | // List of extensions which should be recommended for users of this workspace.
6 | "recommendations": [
7 | "ban.spellright",
8 | "ms-dotnettools.csharp",
9 | "Gruntfuggly.todo-tree",
10 | "brainfit.vscode-coverage-highlighter",
11 | "josefpihrt-vscode.snippetica-csharp",
12 | ],
13 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
14 | "unwantedRecommendations": [
15 |
16 | ]
17 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to find out which attributes exist for C# debugging
3 | // Use hover for the description of the existing attributes
4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
5 | "version": "0.2.0",
6 | "configurations": [{
7 | "name": "Run Tests",
8 | "type": "coreclr",
9 | "request": "launch",
10 | "preLaunchTask": "build",
11 | // If you have changed target frameworks, make sure to update the program path.
12 | "program": "dotnet",
13 | "args": [
14 | "test",
15 | "/p:CollectCoverage=true",
16 | "/p:CoverletOutputFormat=cobertura",
17 | "/p:CoverletOutput=../coverage/cobertura.xml",
18 | ],
19 | "cwd": "${workspaceFolder}/tests",
20 | "console": "internalConsole",
21 | "stopAtEntry": false,
22 | "logging": {
23 | "engineLogging": false,
24 | "moduleLoad": false,
25 | "browserStdOut": false
26 | }
27 | }]
28 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [{
4 | "label": "build",
5 | "command": "dotnet",
6 | "type": "process",
7 | "args": [
8 | "build",
9 | "${workspaceFolder}/tests/Paramdigma.Core.Tests.csproj"
10 | ],
11 | "problemMatcher": []
12 | },
13 | {
14 | "label": "build-docs",
15 | "command": "docfx",
16 | "type": "shell",
17 | "args": [
18 | "docfx_project/docfx.json"
19 | ],
20 | },
21 | {
22 | "label": "serve-docs",
23 | "command": "docfx",
24 | "type": "shell",
25 | "args": [
26 | "docfx_project/docfx.json",
27 | "--serve"
28 | ],
29 | "isBackground": true,
30 | "problemMatcher": []
31 | },
32 | ]
33 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [0.1.1] - 21-Nov-2020
9 |
10 | Leftover change caused CI pipeline to crash. This should fix it!
11 |
12 | ## [0.1.0] - 21-Nov-2020
13 |
14 | So... another couple of release notes missing! 😅 What's important?
15 |
16 | - Added NURBS support in curves and surfaces.
17 | - Added some spatial search algorithms.
18 | - Improved testing and coverage.
19 |
20 | ## [0.0.6] - 14-June-2020
21 |
22 | Yup! Versioning is hard... I didn't do a good job of keeping track of the changes, so version `0.0.2 -> 0.0.6` will go under the *"major improvements"* category. I promise to do better next time! 🤞🏻
23 |
24 | ## [0.0.1] - 10-Feb-2020
25 |
26 | Initial beta release with many many many things pending implementation still. Just main structure and functionality in place.
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Alan Rynne
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Paramdigma.Core.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26124.0
5 | MinimumVisualStudioVersion = 15.0.26124.0
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Paramdigma.Core", "src\Paramdigma.Core.csproj", "{FD765C61-21BE-47EF-A9D0-3098534472F2}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Paramdigma.Core.Tests", "tests\Paramdigma.Core.Tests.csproj", "{C2382EC6-F096-4E84-8057-A1507E62310F}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|x64 = Debug|x64
14 | Debug|x86 = Debug|x86
15 | Release|Any CPU = Release|Any CPU
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Debug|x64.ActiveCfg = Debug|Any CPU
26 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Debug|x64.Build.0 = Debug|Any CPU
27 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Debug|x86.ActiveCfg = Debug|Any CPU
28 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Debug|x86.Build.0 = Debug|Any CPU
29 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Release|Any CPU.Build.0 = Release|Any CPU
31 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Release|x64.ActiveCfg = Release|Any CPU
32 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Release|x64.Build.0 = Release|Any CPU
33 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Release|x86.ActiveCfg = Release|Any CPU
34 | {FD765C61-21BE-47EF-A9D0-3098534472F2}.Release|x86.Build.0 = Release|Any CPU
35 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Debug|x64.ActiveCfg = Debug|Any CPU
38 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Debug|x64.Build.0 = Debug|Any CPU
39 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Debug|x86.ActiveCfg = Debug|Any CPU
40 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Debug|x86.Build.0 = Debug|Any CPU
41 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Release|Any CPU.ActiveCfg = Release|Any CPU
42 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Release|Any CPU.Build.0 = Release|Any CPU
43 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Release|x64.ActiveCfg = Release|Any CPU
44 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Release|x64.Build.0 = Release|Any CPU
45 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Release|x86.ActiveCfg = Release|Any CPU
46 | {C2382EC6-F096-4E84-8057-A1507E62310F}.Release|x86.Build.0 = Release|Any CPU
47 | EndGlobalSection
48 | EndGlobal
49 |
--------------------------------------------------------------------------------
/Paramdigma.Core.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
4 | True
5 | True
6 |
7 |
8 | True
9 | True
10 | True
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Architectrual Geometry Library for .Net
2 |
3 | 
4 | [](https://docs.microsoft.com/en-us/dotnet/standard/net-standard)
5 | [](https://github.com/Paramdigma/Core/blob/master/LICENSE)
6 |
7 | 
8 | 
9 | 
10 |
11 | **Paramdigma.Core** is _(or will be)_ an independent and open source library for **_Architectural Geometry_** algorithms developed by @AlanRynne.
12 |
13 | The core idea is to create a complete package of 3D entities and functions that could be easily connected to different software solutions, via secondary projects that will act as wrappers for the library.
14 |
15 | Currently, we are starting development of:
16 |
17 | - [McNeel Rhinoceros/Grasshopper](https://github.com/paramdigma/core.grasshopper)
18 | - [Autodesk Revit/Dynamo](https://github.com/paramdigma/core.dynamo)
19 |
20 | If you are looking for just a geometry library to plug into a project we also provide a NuGet package.
21 | - [Paramdigma.Core NuGet Package (GPR hosted)](https://github.com/Paramdigma/Core/packages/268763)
22 |
23 | > Github Package Registry is kind of new... If you don't know how to setup GPR for your projects, follow the first step in [THIS GUIDE](https://help.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-dotnet-cli-for-use-with-github-packages#authenticating-with-a-personal-access-token). Once that is done, you are good to go! 🚀
24 |
25 | ## Status
26 |
27 | | | `master` | `develop` |
28 | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
29 | | _CI Status_ | [](https://travis-ci.com/Paramdigma/Core) | [](https://travis-ci.com/Paramdigma/Core) |
30 | | _Code Quality_ | [](https://www.codefactor.io/repository/github/Paramdigma/Core/overview/master) | [](https://www.codefactor.io/repository/github/Paramdigma/Core/overview/develop) |
31 | | _Test Coverage_ | [](https://codecov.io/gh/Paramdigma/Core/branch/master) | [](https://codecov.io/gh/Paramdigma/Core/branch/develop) |
32 |
33 | ## Usage
34 |
35 | > This section will be written very shortly!
36 |
37 | ## Documentation
38 |
39 | You can find the Docfx built documentation for the latest release on the 'master' branch at:
40 |
41 | [https://paramdigma.com/Core/](https://paramdigma.com/Core/)
42 |
43 | > I'm planning on supporting multiple versions on the docs in the future, for now, only the latest release will be documented.
44 | >
45 | > For previous releases, you can always build the docs locally with DocFx.
46 |
47 | ## Contributing
48 |
49 | I haven't developed any contributing guidelines, although the `master` branch is _push protected_ and is connected to Travis-CI so all contributions should pass build tests.
50 |
51 | If you want to contribute to this library, feel free to fork this repo and create a pull request with any modifications.
52 |
53 | The makes heavy use of GitHub Actions automation capabilities to test and deploy the library. Reach out to @AlanRynne for any doubts on this.
--------------------------------------------------------------------------------
/docfx_project/.gitignore:
--------------------------------------------------------------------------------
1 | ###############
2 | # folder #
3 | ###############
4 | /**/DROP/
5 | /**/TEMP/
6 | /**/packages/
7 | /**/bin/
8 | /**/obj/
9 | docs
10 |
--------------------------------------------------------------------------------
/docfx_project/api/.gitignore:
--------------------------------------------------------------------------------
1 | ###############
2 | # temp file #
3 | ###############
4 | *.yml
5 | .manifest
6 |
--------------------------------------------------------------------------------
/docfx_project/api/index.md:
--------------------------------------------------------------------------------
1 | # PLACEHOLDER
2 | TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*!
3 |
--------------------------------------------------------------------------------
/docfx_project/articles/intro.md:
--------------------------------------------------------------------------------
1 | # Add your introductions here!
2 |
--------------------------------------------------------------------------------
/docfx_project/articles/toc.yml:
--------------------------------------------------------------------------------
1 | - name: Introduction
2 | href: intro.md
3 |
--------------------------------------------------------------------------------
/docfx_project/docfx.json:
--------------------------------------------------------------------------------
1 | {
2 | "metadata": [
3 | {
4 | "src": [
5 | {
6 | "files": [
7 | "**.csproj"
8 | ],
9 | "src": "../src/"
10 | }
11 | ],
12 | "dest": "api",
13 | "disableGitFeatures": false,
14 | "disableDefaultFilter": false
15 | }
16 | ],
17 | "build": {
18 | "content": [
19 | {
20 | "files": [
21 | "api/**.yml",
22 | "api/index.md"
23 | ]
24 | },
25 | {
26 | "files": [
27 | "articles/**.md",
28 | "articles/**/toc.yml",
29 | "toc.yml",
30 | "*.md"
31 | ]
32 | }
33 | ],
34 | "resource": [
35 | {
36 | "files": [
37 | "images/**"
38 | ]
39 | }
40 | ],
41 | "overwrite": [
42 | {
43 | "files": [
44 | "apidoc/**.md"
45 | ],
46 | "exclude": [
47 | "obj/**",
48 | "docs/**"
49 | ]
50 | }
51 | ],
52 | "dest": "../docs",
53 | "globalMetadataFiles": [],
54 | "fileMetadataFiles": [],
55 | "template": [
56 | "statictoc"
57 | ],
58 | "postProcessors": [],
59 | "markdownEngineName": "markdig",
60 | "noLangKeyword": false,
61 | "keepFileLink": false,
62 | "cleanupCacheHistory": false,
63 | "disableGitFeatures": false
64 | }
65 | }
--------------------------------------------------------------------------------
/docfx_project/index.md:
--------------------------------------------------------------------------------
1 | # Architectrual Geometry Library for .Net
2 |
3 | 
4 | 
5 | [](https://github.com/Paramdigma/Core/blob/development/LICENSE)
6 |
7 | 
8 | 
9 | 
10 | 
11 |
12 | **Paramdigma.Core** is _(or will be)_ an independent and open source library for **_Architectural Geometry_** algorithms developed by @AlanRynne.
13 |
14 | The core idea is to create a complete package of 3D entities and functions that could be easily connected to different software solutions, via secondary projects that will act as wrappers for the library.
15 |
16 | Currently, we are starting development of:
17 |
18 | - [McNeel Rhinoceros/Grasshopper](https://github.com/paramdigma/core.grasshopper)
19 | - [Autodesk Revit/Dynamo](https://github.com/paramdigma/core.dynamo)
20 |
21 | If you are looking for just a geometry library to plug into a project we also provide a NuGet package.
22 | - [Paramdigma.Core NuGet Package (GPR hosted)](https://github.com/Paramdigma/Core/packages/268763)
23 |
24 | > Github Package Registry is kind of new... If you don't know how to setup GPR for your projects, follow the first step in [THIS GUIDE](https://help.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-dotnet-cli-for-use-with-github-packages#authenticating-with-a-personal-access-token). Once that is done, you are good to go! 🚀
25 |
26 | ## Status
27 |
28 | | | `master` | `develop` |
29 | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
30 | | _CI Status_ | [](https://travis-ci.com/Paramdigma/Core) | [](https://travis-ci.com/Paramdigma/Core) |
31 | | _Code Quality_ | [](https://www.codefactor.io/repository/github/Paramdigma/Core/overview/master) | [](https://www.codefactor.io/repository/github/Paramdigma/Core/overview/develop) |
32 | | _Test Coverage_ | [](https://codecov.io/gh/Paramdigma/Core/branch/master) | [](https://codecov.io/gh/Paramdigma/Core/branch/develop) |
33 |
34 | ## Usage
35 |
36 | > This section will be written very shortly!
37 |
38 | ## Documentation
39 |
40 | You can find the Docfx built documentation for the latest relase on the 'master' branch at:
41 |
42 | [https://paramdigma.com/Core/](https://paramdigma.com/Core/)
43 |
44 | > I'm planning on supporting multiple versions on the docs in the future, for now, only the latest release will be documented.
45 | >
46 | > For previous releases, you can always build the docs locally with DocFx.
47 |
48 | ## Contributing
49 |
50 | I haven't developed any contributing guidelines, although the `master` branch is _push protected_ and is connected to Travis-CI so all contributions should pass build tests.
51 |
52 | If you want to contribute to this library, feel free to fork this repo and create a pull request with any modifications.
53 |
54 | The makes heavy use of GitHub Actions automation capabilities to test and deploy the library. Reach out to @AlanRynne for any doubts on this.
--------------------------------------------------------------------------------
/docfx_project/toc.yml:
--------------------------------------------------------------------------------
1 | - name: Articles
2 | href: articles/
3 | - name: Api Documentation
4 | href: api/
5 | homepage: api/index.md
6 |
--------------------------------------------------------------------------------
/src/Curves/Geodesics.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Paramdigma.Core.Geometry;
3 |
4 | namespace Paramdigma.Core.Curves
5 | {
6 | ///
7 | /// Static class to compute geodeesics on triangular meshes.
8 | ///
9 | public static class Geodesics
10 | {
11 | ///
12 | /// Computes a geodesic on a mesh given a starting point and an initial direction.
13 | /// Returns true if successfull and false if something went wrong.
14 | ///
15 | /// Point.
16 | /// Direction.
17 | /// Mesh.
18 | /// Maximum iterations.
19 | /// Geodesic curves.
20 | /// True if successful.
21 | public static bool StartDir(
22 | MeshPoint meshPoint,
23 | Vector3d vector,
24 | Mesh mesh,
25 | int maxIter,
26 | out List geodesic)
27 | {
28 | // Get initial face on the mesh
29 | var initialFace = mesh.Faces[meshPoint.FaceIndex];
30 |
31 | // Start iteration
32 | // Create variables for current iteration step
33 | var thisFace = initialFace;
34 | var thisPoint = new Point3d();
35 | var thisDirection = vector;
36 |
37 | var iter = 0;
38 | var geodPoints = new List();
39 | do
40 | {
41 | var ray = new Ray(thisPoint, thisDirection);
42 |
43 | // Find intersection between ray and boundary
44 | Intersect3D.RayFacePerimeter(ray, thisFace, out var nextPoint, out var halfEdge);
45 |
46 | // Intersection method should check for correct direction using sign of dot product
47 |
48 | // Add point to pointlist
49 | geodPoints.Add(nextPoint);
50 |
51 | // Walk to next face
52 | var nextFace = halfEdge.Twin.Face;
53 |
54 | // Flip vector to next face
55 | var perpVector = Vector3d.CrossProduct(
56 | thisDirection,
57 | MeshGeometry.FaceNormal(thisFace));
58 | var nextVector = Vector3d.CrossProduct(
59 | MeshGeometry.FaceNormal(nextFace),
60 | perpVector);
61 |
62 | // Assign iteration variables to current
63 | thisPoint = nextPoint;
64 | thisFace = nextFace;
65 | thisDirection = nextVector;
66 |
67 | // Increase counter
68 | iter++;
69 | } while (iter < maxIter);
70 |
71 | // Assign outputs
72 | geodesic = geodPoints;
73 | return true;
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/src/Data/Settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "DefaultTesselation": 10,
3 | "Tolerance": 0.0000001
4 | }
--------------------------------------------------------------------------------
/src/Exceptions/UnsetGeometryException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Paramdigma.Core.Exceptions
4 | {
5 | ///
6 | /// Represents errors that ocur when using a geometry that has the 'isUnset' flag set to true.
7 | ///
8 | public class UnsetGeometryException : Exception
9 | {
10 | ///
11 | public UnsetGeometryException() { }
12 |
13 |
14 | ///
15 | public UnsetGeometryException(string message) : base(message) { }
16 |
17 |
18 | ///
19 | public UnsetGeometryException(string message, Exception innerException) : base(
20 | message,
21 | innerException) { }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Extensions/Lists.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace Paramdigma.Core.Extensions
5 | {
6 | ///
7 | /// Static class holding some utility methods regarding object collections.
8 | ///
9 | public static class Lists
10 | {
11 | ///
12 | /// Initializes a new list full of objects initialized with their default constructor.
13 | ///
14 | /// Number of objects in the list.
15 | /// Type of object in the list.
16 | /// //TODO.
17 | public static List RepeatedDefault(int count) => Repeated(default(T), count);
18 |
19 |
20 | ///
21 | /// Initializes a new list full of objects initialized the values of the specified instance of T.
22 | ///
23 | /// Object to insert on every index of the list.
24 | /// Number of objects in the list.
25 | /// Type of object in the list.
26 | /// //TODO.
27 | public static List Repeated(T value, int count)
28 | {
29 | var repeated = new List(count);
30 | repeated.AddRange(Enumerable.Repeat(value, count));
31 | return repeated;
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/src/Geometry/Base/BaseCurve.cs:
--------------------------------------------------------------------------------
1 | using Paramdigma.Core.Collections;
2 |
3 | #pragma warning disable 1591
4 |
5 | namespace Paramdigma.Core.Geometry
6 | {
7 | ///
8 | /// Represents a generic curve. This class is abstract and all curve classes should inherit from
9 | /// it.
10 | ///
11 | public abstract class BaseCurve
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | protected BaseCurve() => this.Domain = Interval.Unit;
17 | // Public properties
18 |
19 |
20 | ///
21 | /// Gets or sets the curve's domain.
22 | ///
23 | public Interval Domain { get; set; }
24 |
25 | ///
26 | /// Gets a value indicating whether the curve is valid.
27 | ///
28 | /// True if Valid.
29 | public bool IsValid => this.CheckValidity();
30 |
31 | public double Length => this.ComputeLength();
32 |
33 |
34 | ///
35 | /// Compute a point along the curve at a specified parameter.
36 | ///
37 | /// Parameter.
38 | /// Point at the parameter specified.
39 | public abstract Point3d PointAt(double t);
40 |
41 |
42 | ///
43 | /// Compute the tangent vector along the curve at a specified parameter.
44 | ///
45 | /// Parameter.
46 | /// Tangent vector at the parameter specified.
47 | public abstract Vector3d TangentAt(double t);
48 |
49 |
50 | ///
51 | /// Compute normal vector along the curve at a specified parameter.
52 | ///
53 | /// Parameter.
54 | /// Normal vector at the parameter specified.
55 | public abstract Vector3d NormalAt(double t);
56 |
57 |
58 | ///
59 | /// Compute a binormal vector along the curve at a specified parameter.
60 | ///
61 | /// Parameter.
62 | /// Binormal vector at the parameter specified.
63 | public abstract Vector3d BinormalAt(double t);
64 |
65 |
66 | ///
67 | /// Compute the perpendicular frame along the curve at a specified parameter.
68 | ///
69 | /// Parameter.
70 | /// Perpendicular plane at the parameter specified.
71 | public abstract Plane FrameAt(double t);
72 |
73 |
74 | ///
75 | /// Checks the validity of the curve.
76 | ///
77 | /// True if valid.
78 | public abstract bool CheckValidity();
79 |
80 |
81 | ///
82 | /// Computes the length of the curve.
83 | ///
84 | /// Length as number.
85 | protected abstract double ComputeLength();
86 | }
87 | }
--------------------------------------------------------------------------------
/src/Geometry/Base/InvalidCurveException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Paramdigma.Core.Geometry
4 | {
5 | ///
6 | /// Exception for invalid curve.
7 | ///
8 | public class InvalidCurveException : Exception
9 | {
10 | ///
11 | public InvalidCurveException() { }
12 |
13 |
14 | ///
15 | public InvalidCurveException(string message)
16 | : base(message) { }
17 |
18 |
19 | ///
20 | public InvalidCurveException(string message, Exception innerException)
21 | : base(message, innerException) { }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Geometry/Box.cs:
--------------------------------------------------------------------------------
1 | using Paramdigma.Core.Collections;
2 |
3 | namespace Paramdigma.Core.Geometry
4 | {
5 | ///
6 | /// Represents a 3D box.
7 | ///
8 | public class Box
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// Base plane of the box.
14 | /// Range of values in the X axis.
15 | /// Range of values in the Y axis.
16 | /// Range of values in the Z axis.
17 | public Box(Plane plane, Interval domainX, Interval domainY, Interval domainZ)
18 | {
19 | this.Plane = plane;
20 | this.DomainX = domainX;
21 | this.DomainY = domainY;
22 | this.DomainZ = domainZ;
23 | }
24 |
25 |
26 | ///
27 | /// Initializes a new instance of the class from 2 corners. Both corners will
28 | /// form the diagonal of
29 | /// the box.
30 | ///
31 | /// Lower left corner point.
32 | /// Upper right corner point.
33 | public Box(Point3d lower, Point3d upper)
34 | {
35 | this.Plane = Plane.WorldXY;
36 | this.DomainX = new Interval(lower.X, upper.X);
37 | this.DomainY = new Interval(lower.Y, upper.Y);
38 | this.DomainZ = new Interval(lower.Z, upper.Z);
39 | }
40 |
41 |
42 | ///
43 | /// Gets or sets the box's base plane.
44 | ///
45 | /// .
46 | public Plane Plane { get; set; }
47 |
48 | ///
49 | /// Gets or sets the box's X axis domain.
50 | ///
51 | /// .
52 | public Interval DomainX { get; set; }
53 |
54 | ///
55 | /// Gets or sets the box's Y axis domain.
56 | ///
57 | /// .
58 | public Interval DomainY { get; set; }
59 |
60 | ///
61 | /// Gets or sets the box's Z axis domain.
62 | ///
63 | /// .
64 | public Interval DomainZ { get; set; }
65 |
66 | ///
67 | /// Gets the corner point with lowest values.
68 | ///
69 | /// .
70 | public Point3d Min => new Point3d(
71 | this.DomainX.Start,
72 | this.DomainY.Start,
73 | this.DomainZ.Start);
74 |
75 | ///
76 | /// Gets the corner point with highest values.
77 | ///
78 | /// .
79 | public Point3d Max => new Point3d(this.DomainX.End, this.DomainY.End, this.DomainZ.End);
80 |
81 | ///
82 | /// Gets the center point of the box.
83 | ///
84 | /// .
85 | public Point3d Center => new Point3d(
86 | this.DomainX.RemapFromUnit(0.5),
87 | this.DomainY.RemapFromUnit(0.5),
88 | this.DomainZ.RemapFromUnit(0.5));
89 | }
90 | }
--------------------------------------------------------------------------------
/src/Geometry/Circle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Paramdigma.Core.Geometry.Interfaces;
3 |
4 | namespace Paramdigma.Core.Geometry
5 | {
6 | ///
7 | /// Represents a planar circle curve.
8 | ///
9 | public class Circle : ICurve
10 | {
11 | ///
12 | /// The base plane for the circle.
13 | ///
14 | public Plane Plane;
15 |
16 | ///
17 | /// The radius of the circle.
18 | ///
19 | public double Radius;
20 |
21 |
22 | ///
23 | /// Initializes a new instance of by it's plane and radius.
24 | ///
25 | /// The plane to draw the circle at.
26 | /// The desired radius of the circle.
27 | public Circle(Plane plane, double radius)
28 | {
29 | this.Plane = plane;
30 | this.Radius = radius;
31 | }
32 |
33 |
34 | ///
35 | public Point3d PointAt(double t)
36 | {
37 | var radians = t * 2 * Math.PI;
38 | var x = this.Radius * Math.Cos(radians);
39 | var y = this.Radius * Math.Sin(radians);
40 | return this.Plane.PointAt(x, y, 0);
41 | }
42 |
43 |
44 | ///
45 | public Vector3d TangentAt(double t) => this.NormalAt(t).Cross(this.Plane.ZAxis);
46 |
47 |
48 | ///
49 | public Vector3d NormalAt(double t) => (this.Plane.Origin - this.PointAt(t)).Unit();
50 |
51 |
52 | ///
53 | public Vector3d BinormalAt(double t) => this.TangentAt(t).Cross(this.NormalAt(t));
54 |
55 |
56 | ///
57 | public Plane FrameAt(double t) => new Plane(
58 | this.PointAt(t),
59 | this.NormalAt(t),
60 | this.BinormalAt(t),
61 | this.TangentAt(t));
62 | }
63 | }
--------------------------------------------------------------------------------
/src/Geometry/Cylinder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Paramdigma.Core.Collections;
3 | using Paramdigma.Core.Geometry.Interfaces;
4 |
5 | namespace Paramdigma.Core.Geometry
6 | {
7 | ///
8 | /// Represents a cylindrical surface.
9 | ///
10 | public class Cylinder : ISurface
11 | {
12 | ///
13 | /// Initializes a new instance of the class from it's individual
14 | /// components.
15 | ///
16 | /// The plane of the cylinder.
17 | /// The radius of the cylinder.
18 | /// The cylinder height range.
19 | /// Throws when radius is smaller or equal to 0
20 | /// Throws when the height domain is tiny.
21 | /// Throws when the passed plane is null
22 | public Cylinder(Plane plane, double radius, Interval domain)
23 | {
24 | if (radius <= 0)
25 | throw new ArgumentOutOfRangeException(nameof(radius));
26 | if (domain.Length < Settings.Tolerance)
27 | throw new ArgumentException("Height length is tiny.");
28 | this.Plane = plane ?? throw new ArgumentNullException(nameof(plane));
29 | this.Radius = radius;
30 | this.HeightRange = domain;
31 | this.DomainU = Interval.Unit;
32 | this.DomainV = Interval.Unit;
33 | }
34 |
35 |
36 | ///
37 | /// Gets or sets the base plane of the cylinder.
38 | ///
39 | /// .
40 | public Plane Plane { get; set; }
41 |
42 | ///
43 | /// Gets or sets the radius of the cylinder.
44 | ///
45 | /// .
46 | public double Radius { get; set; }
47 |
48 | ///
49 | /// Gets or sets the height range of the cylinder.
50 | ///
51 | /// .
52 | public Interval HeightRange { get; set; }
53 |
54 | ///
55 | /// Gets the cylinder height.
56 | ///
57 | public double Height => this.HeightRange.Length;
58 |
59 | ///
60 | public Interval DomainU { get; set; }
61 |
62 | ///
63 | public Interval DomainV { get; set; }
64 |
65 |
66 | ///
67 | public Plane FrameAt(double u, double v)
68 | {
69 | this.CheckParameters(u, v);
70 | throw new NotImplementedException();
71 | }
72 |
73 |
74 | ///
75 | /// Compute the distance from a point to this cylinder.
76 | ///
77 | /// Point to compute with.
78 | /// Number representing the distance.
79 | public double DistanceTo(Point3d point) => throw new NotImplementedException();
80 |
81 |
82 | ///
83 | /// Compute the closes point of a point in this cylinder.
84 | ///
85 | /// Point to compute with.
86 | /// Point3d instance of the closest point in the cylinder.
87 | public Point3d ClosestPointTo(Point3d point) => throw new NotImplementedException();
88 |
89 |
90 | ///
91 | public Vector3d NormalAt(double u, double v)
92 | {
93 | this.CheckParameters(u, v);
94 | throw new NotImplementedException();
95 | }
96 |
97 |
98 | ///
99 | public Point3d PointAt(double u, double v)
100 | {
101 | this.CheckParameters(u, v);
102 |
103 | double x, y, z;
104 | var rho = this.Radius;
105 | var phi = this.DomainU.Remap(u, new Interval(0, 2 * Math.PI));
106 | x = rho * Math.Cos(phi);
107 | y = rho * Math.Sin(phi);
108 | z = v;
109 | return this.Plane.PointAt(x, y, z);
110 | }
111 |
112 |
113 | private void CheckParameters(double u, double v)
114 | {
115 | if (!this.DomainU.Contains(u))
116 | throw new Exception("Parameter U must be contained inside domain");
117 | if (!this.DomainV.Contains(v))
118 | throw new Exception("Parameter V must be contained inside domain");
119 | }
120 | }
121 | }
--------------------------------------------------------------------------------
/src/Geometry/Interfaces/ICurve.cs:
--------------------------------------------------------------------------------
1 | namespace Paramdigma.Core.Geometry.Interfaces
2 | {
3 | ///
4 | /// Base interface that all curve entities must implement.
5 | ///
6 | public interface ICurve
7 | {
8 | ///
9 | /// Computes the point on the curve at the specified parameter.
10 | ///
11 | /// Parameter.
12 | /// Point on curve.
13 | Point3d PointAt(double t);
14 |
15 |
16 | ///
17 | /// Computes the tangent vector on the curve at the specified parameter.
18 | ///
19 | /// Parameter.
20 | /// Tangent on curve.
21 | Vector3d TangentAt(double t);
22 |
23 |
24 | ///
25 | /// Computes the normal vector on the curve at the specified parameter.
26 | ///
27 | /// Parameter.
28 | /// Normal on curve.
29 | Vector3d NormalAt(double t);
30 |
31 |
32 | ///
33 | /// Computes the binormal vector on the curve at the specified parameter.
34 | ///
35 | /// Parameter.
36 | /// Binormal vector on curve.
37 | Vector3d BinormalAt(double t);
38 |
39 |
40 | ///
41 | /// Computes the perpendicular frame on the curve at the specified parameter.
42 | ///
43 | /// Parameter.
44 | /// Perpendicular frame on curve.
45 | Plane FrameAt(double t);
46 | }
47 | }
--------------------------------------------------------------------------------
/src/Geometry/Interfaces/ISurface.cs:
--------------------------------------------------------------------------------
1 | using Paramdigma.Core.Collections;
2 |
3 | namespace Paramdigma.Core.Geometry.Interfaces
4 | {
5 | ///
6 | /// Base interface that all surface interface must implement.
7 | ///
8 | public interface ISurface
9 | {
10 | ///
11 | /// Gets the domain in the U direction.
12 | ///
13 | /// .
14 | Interval DomainU { get; }
15 |
16 | ///
17 | /// Gets the domain in the V direction.
18 | ///
19 | /// .
20 | Interval DomainV { get; }
21 |
22 |
23 | ///
24 | /// Compute a point at the specified surface coordinates.
25 | ///
26 | /// U coordinate.
27 | /// V coordinate.
28 | /// .
29 | Point3d PointAt(double u, double v);
30 |
31 |
32 | ///
33 | /// Compute the normal at the specified surface coordinates.
34 | ///
35 | /// U coordinate.
36 | /// V coordinate.
37 | /// Normal vector.
38 | Vector3d NormalAt(double u, double v);
39 |
40 |
41 | ///
42 | /// Compute the tangent plane at the specified surface coordinates.
43 | ///
44 | /// U coordinate.
45 | /// V coordinate.
46 | /// Tangent plane.
47 | Plane FrameAt(double u, double v);
48 |
49 |
50 | ///
51 | /// Compute the distance between this surface and a point.
52 | ///
53 | /// Point to compute distance to.
54 | /// Number representing the distance.
55 | double DistanceTo(Point3d point);
56 |
57 |
58 | ///
59 | /// Compute the projection of a point on this surface.
60 | ///
61 | /// Point to compute distance to.
62 | /// Projected 3d point on the surface.
63 | Point3d ClosestPointTo(Point3d point);
64 | }
65 | }
--------------------------------------------------------------------------------
/src/Geometry/Interfaces/IVector.cs:
--------------------------------------------------------------------------------
1 | namespace Paramdigma.Core.Geometry.Interfaces
2 | {
3 | ///
4 | /// Base interface that all vector entities must implement.
5 | ///
6 | public interface IVector { }
7 | }
--------------------------------------------------------------------------------
/src/Geometry/Intersect/IntersectErrors.cs:
--------------------------------------------------------------------------------
1 | using Paramdigma.Core.Geometry;
2 |
3 | #pragma warning disable 1591
4 |
5 | namespace Paramdigma.Core
6 | {
7 | ///
8 | /// Class contains all 3D related intersection methods.
9 | ///
10 | public static partial class Intersect3D
11 | {
12 | public enum LineLineIntersectionStatus
13 | {
14 | NoIntersection, Point, Error
15 | }
16 |
17 | public enum LinePlaneIntersectionStatus
18 | {
19 | NoIntersection, Point, OnPlane
20 | }
21 |
22 | public enum RayFacePerimeterIntersectionStatus
23 | {
24 | NoIntersection, Point, Error
25 | }
26 |
27 | public struct LineLineIntersectionResult
28 | {
29 | public double Distance { get; set; }
30 |
31 | public double ParamA { get; set; }
32 |
33 | public double ParamB { get; set; }
34 |
35 | public Point3d PointA { get; set; }
36 |
37 | public Point3d PointB { get; set; }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/src/Geometry/Line.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Paramdigma.Core.Geometry
4 | {
5 | ///
6 | /// Represents a 3D Line.
7 | ///
8 | public class Line : BaseCurve
9 | {
10 | ///
11 | /// Initializes a new instance of the class from two points.
12 | ///
13 | /// Start point.
14 | /// End point.
15 | public Line(Point3d startPoint, Point3d endPoint)
16 | {
17 | this.StartPoint = startPoint;
18 | this.EndPoint = endPoint;
19 | }
20 |
21 |
22 | ///
23 | /// Initializes a new instance of the class from an origin point, a direction
24 | /// and a specified
25 | /// length.
26 | ///
27 | /// Start point of the line.
28 | /// Direction of the line (length will not be taken into account).
29 | /// Length of the line.
30 | public Line(Point3d origin, Vector3d direction, double length)
31 | {
32 | this.StartPoint = origin;
33 | this.EndPoint = origin + direction.Unit() * length;
34 | }
35 |
36 |
37 | ///
38 | /// Gets or sets the lines's start point.
39 | ///
40 | public Point3d StartPoint { get; set; }
41 |
42 | ///
43 | /// Gets or sets the line's end point.
44 | ///
45 | public Point3d EndPoint { get; set; }
46 |
47 |
48 | ///
49 | /// Checks if line is valid.
50 | ///
51 | /// True if valid.
52 | public override bool CheckValidity() => this.Length >= Settings.Tolerance;
53 |
54 |
55 | ///
56 | /// Computes thepoint at the given parameter.
57 | ///
58 | /// Parameter of the point. Must be between 0 and 1.
59 | /// Point at specified parameter.
60 | public override Point3d PointAt(double t) =>
61 | this.StartPoint + this.Domain.RemapToUnit(t) * (this.EndPoint - this.StartPoint);
62 |
63 |
64 | ///
65 | /// Computes the tangent at the given parameter.
66 | ///
67 | /// Parameter of the tangent. Must be between 0 and 1.
68 | /// Tangent at specified parameter.
69 | public override Vector3d TangentAt(double t)
70 | {
71 | var tangent = this.EndPoint - this.StartPoint;
72 | tangent.Unitize();
73 | return tangent;
74 | }
75 |
76 |
77 | ///
78 | /// Computes the normal at the given parameter.
79 | ///
80 | /// Parameter of the normal vector. Must be between 0 and 1.
81 | /// Normal vector at specified parameter.
82 | public override Vector3d NormalAt(double t)
83 | {
84 | var tangent = this.TangentAt(t);
85 | var v = Math.Abs(tangent.Dot(Vector3d.UnitZ) - 1) < Settings.Tolerance
86 | ? Vector3d.UnitX
87 | : Vector3d.UnitZ;
88 | return tangent.Cross(v);
89 | }
90 |
91 |
92 | ///
93 | /// Computes the bi-normal vector at the given parameter.
94 | ///
95 | /// Parameter of the bi-normal vector. Must be between 0 and 1.
96 | /// Bi-normal vector at specified parameter.
97 | public override Vector3d BinormalAt(double t) =>
98 | Vector3d.CrossProduct(this.TangentAt(t), this.NormalAt(t));
99 |
100 |
101 | ///
102 | /// Computes the perpendicular frame at the given parameter.
103 | ///
104 | /// Parameter of the frame. Must be between 0 and 1.
105 | /// Frame at specified parameter.
106 | public override Plane FrameAt(double t) => new Plane(
107 | this.PointAt(t),
108 | this.TangentAt(t),
109 | this.NormalAt(t),
110 | this.BinormalAt(t));
111 |
112 |
113 | ///
114 | /// Computes the length of the line.
115 | ///
116 | /// Line length.
117 | protected override double ComputeLength() => this.StartPoint.DistanceTo(this.EndPoint);
118 |
119 |
120 | ///
121 | /// Explicitly converts a line to it's vector representation.
122 | ///
123 | /// Line to convert.
124 | /// Vector defining the line direction and length.
125 | public static explicit operator Vector3d(Line line) => line.EndPoint - line.StartPoint;
126 | }
127 | }
--------------------------------------------------------------------------------
/src/Geometry/Line2d.cs:
--------------------------------------------------------------------------------
1 | using Paramdigma.Core.Collections;
2 |
3 | namespace Paramdigma.Core.Geometry
4 | {
5 | ///
6 | /// Represents a 2-dimensional line.
7 | ///
8 | public class Line2d
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// Start point of the line.
14 | /// End point of the line.
15 | public Line2d(Point2d startPoint, Point2d endPoint)
16 | {
17 | this.StartPoint = startPoint;
18 | this.EndPoint = endPoint;
19 | this.Domain = new Interval(0, this.Length);
20 | }
21 |
22 |
23 | ///
24 | /// Initializes a new instance of the class.
25 | ///
26 | /// The start point of the line.
27 | /// Direction. The length of the vector will determine the end point.
28 | /// New 2d line instance.
29 | public Line2d(Point2d startPoint, Vector2d direction)
30 | : this(startPoint, startPoint + direction) { }
31 |
32 |
33 | ///
34 | /// Initializes a new instance of the class.
35 | ///
36 | /// Start point.
37 | /// Direction (length of vector will be disregarded).
38 | /// Desired length of the line.
39 | /// New 2d line instance.
40 | public Line2d(Point2d startPoint, Vector2d direction, double length)
41 | : this(startPoint, direction.Unit() * length) { }
42 |
43 |
44 | ///
45 | /// Gets or sets the start point of the line.
46 | ///
47 | /// 3D Point.
48 | public Point2d StartPoint { get; set; }
49 |
50 | ///
51 | /// Gets or sets the end point of the line.
52 | ///
53 | /// 3D Point.
54 | public Point2d EndPoint { get; set; }
55 |
56 | ///
57 | /// Gets or sets the line's domain.
58 | ///
59 | /// Interval.
60 | public Interval Domain { get; set; }
61 |
62 | ///
63 | /// Gets the vector representation of the line.
64 | ///
65 | public Vector2d Vector =>
66 | this; // Implicit line to vector conversion (this property exists just for convenience and readability)
67 |
68 | ///
69 | /// Gets the length of the line.
70 | ///
71 | public double Length => this.Vector.Length;
72 |
73 |
74 | ///
75 | /// Implicit conversion from line to vector.
76 | ///
77 | /// Line to be transformed into vector.
78 | public static implicit operator Vector2d(Line2d line) => line.EndPoint - line.StartPoint;
79 |
80 |
81 | ///
82 | /// Computes if a given point is at the left, right or on the current line.
83 | ///
84 | /// Point to test.
85 | ///
86 | /// >0 for point left of the line
87 | /// =0 for point on the line
88 | /// bigger 0 for point right of the line.
89 | ///
90 | public double IsLeft(Point2d point)
91 | {
92 | Vector2d v1 = this;
93 | var v2 = point - this.StartPoint;
94 | return v1.PerpProduct(v2);
95 | }
96 | }
97 | }
--------------------------------------------------------------------------------
/src/Geometry/MeshCorner.cs:
--------------------------------------------------------------------------------
1 | namespace Paramdigma.Core.Geometry
2 | {
3 | ///
4 | /// Represents a corner of a given mesh face.
5 | ///
6 | public class MeshCorner
7 | {
8 | ///
9 | /// Initializes a new instance of the class.
10 | ///
11 | public MeshCorner() => this.Index = -1;
12 |
13 |
14 | ///
15 | /// Gets or sets the corner's first half-edge.
16 | ///
17 | public MeshHalfEdge HalfEdge { get; set; }
18 |
19 | ///
20 | /// Gets or sets the index of the mesh corner.
21 | ///
22 | public int Index { get; set; }
23 |
24 | ///
25 | /// Gets the mesh corner vertex.
26 | ///
27 | public MeshVertex Vertex => this.HalfEdge.Prev.Vertex;
28 |
29 | ///
30 | /// Gets the face the mesh corner belongs to.
31 | ///
32 | public MeshFace Face => this.HalfEdge.Face;
33 |
34 | ///
35 | /// Gets the next corner.
36 | ///
37 | public MeshCorner Next => this.HalfEdge.Next.Corner;
38 |
39 | ///
40 | /// Gets the previous corner.
41 | ///
42 | public MeshCorner Prev => this.HalfEdge.Prev.Corner;
43 | }
44 | }
--------------------------------------------------------------------------------
/src/Geometry/MeshEdge.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Paramdigma.Core.Geometry
4 | {
5 | ///
6 | /// Edge class representing a full edge of a half-edge mesh.
7 | /// A full edge contains 2 half-edges.
8 | ///
9 | public class MeshEdge
10 | {
11 | ///
12 | /// Initializes a new instance of the class.
13 | ///
14 | public MeshEdge() => this.Index = -1;
15 |
16 |
17 | ///
18 | /// Gets or sets the half-edge linked to this edge.
19 | ///
20 | public MeshHalfEdge HalfEdge { get; set; }
21 |
22 | ///
23 | /// Gets or sets the index of this Mesh Edge.
24 | ///
25 | public int Index { get; set; }
26 |
27 | ///
28 | /// Gets a value indicating whether the mesh edge lies on a boundary.
29 | ///
30 | public bool OnBoundary => this.HalfEdge.OnBoundary || this.HalfEdge.Twin.OnBoundary;
31 |
32 |
33 | ///
34 | /// Gets the adjacent vertices of this given edge.
35 | ///
36 | ///
37 | public List AdjacentVertices()
38 | {
39 | var vertices = new List {this.HalfEdge.Vertex, this.HalfEdge.Twin.Vertex};
40 | return vertices;
41 | }
42 |
43 |
44 | ///
45 | /// Gets the adjacent faces of this edge.
46 | ///
47 | ///
48 | public List AdjacentFaces()
49 | {
50 | var faces = new List
51 | {
52 | this.HalfEdge.AdjacentFace, this.HalfEdge.Twin.AdjacentFace
53 | };
54 | return faces;
55 | }
56 |
57 |
58 | ///
59 | /// Gets the adjacent edges of this edge.
60 | ///
61 | ///
62 | public List AdjacentEdges()
63 | {
64 | var edges = new List();
65 | edges.AddRange(this.HalfEdge.Vertex.AdjacentEdges());
66 | edges.AddRange(this.HalfEdge.Twin.Vertex.AdjacentEdges());
67 | return edges;
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/src/Geometry/MeshHalfEdge.cs:
--------------------------------------------------------------------------------
1 | namespace Paramdigma.Core.Geometry
2 | {
3 | ///
4 | /// Represents a mesh half-edge.
5 | ///
6 | public class MeshHalfEdge
7 | {
8 | ///
9 | /// Initializes a new instance of the class.
10 | ///
11 | public MeshHalfEdge() => this.Index = -1;
12 |
13 |
14 | ///
15 | /// Gets or sets the vertex linked to this half-edge.
16 | ///
17 | public MeshVertex Vertex { get; set; }
18 |
19 | ///
20 | /// Gets or sets the edge linked to this half-edge.
21 | ///
22 | public MeshEdge Edge { get; set; }
23 |
24 | ///
25 | /// Gets or sets the face linked to this half-edge.
26 | ///
27 | public MeshFace Face { get; set; }
28 |
29 | ///
30 | /// Gets or sets the corner linked to this half-edge.
31 | ///
32 | public MeshCorner Corner { get; set; }
33 |
34 | ///
35 | /// Gets or sets the next half-edge in a face.
36 | ///
37 | public MeshHalfEdge Next { get; set; }
38 |
39 | ///
40 | /// Gets or sets the previous half-edge in a face.
41 | ///
42 | public MeshHalfEdge Prev { get; set; }
43 |
44 | ///
45 | /// Gets or sets the opposite half-edge.
46 | ///
47 | public MeshHalfEdge Twin { get; set; }
48 |
49 | ///
50 | /// Gets or sets a value indicating whether the half-edge lies on a boundary.
51 | ///
52 | public bool OnBoundary { get; set; }
53 |
54 | ///
55 | /// Gets or sets the half-edge index.
56 | ///
57 | public int Index { get; set; }
58 |
59 | ///
60 | /// Gets the previous vertex of the half-edge.
61 | ///
62 | public MeshVertex PreviousVertex => this.Twin.Vertex;
63 |
64 | ///
65 | /// Gets the opposite face of the half-edge.
66 | ///
67 | public MeshFace AdjacentFace => this.Twin.Face;
68 |
69 |
70 | ///
71 | /// Gets the string representation of the half-edge.
72 | ///
73 | ///
74 | public override string ToString() => "Half-edge " + this.Index;
75 | }
76 | }
--------------------------------------------------------------------------------
/src/Geometry/MeshPoint.cs:
--------------------------------------------------------------------------------
1 | namespace Paramdigma.Core.Geometry
2 | {
3 | ///
4 | /// Represents a point on a mesh as it's face index and barycentric coordinatees.
5 | ///
6 | public class MeshPoint
7 | {
8 | ///
9 | /// Initializes a new instance of the class.
10 | ///
11 | /// Face Index.
12 | /// U coordinate.
13 | /// V coordinate.
14 | /// Z coordinate.
15 | public MeshPoint(int faceIndex, double u, double v, double w)
16 | {
17 | this.FaceIndex = faceIndex;
18 | this.U = u;
19 | this.V = v;
20 | this.W = w;
21 | }
22 |
23 |
24 | ///
25 | /// Initializes a new instance of the class.
26 | ///
27 | /// 3D Point.
28 | /// Mesh face.
29 | public MeshPoint(MeshFace face, Point3d point)
30 | {
31 | var adj = face.AdjacentVertices();
32 | var bary = Convert.Point3dToBarycentric(point, adj[0], adj[1], adj[2]);
33 | this.U = bary[0];
34 | this.V = bary[1];
35 | this.W = bary[2];
36 | }
37 |
38 |
39 | ///
40 | /// Gets or sets the index of the face this point lies in.
41 | ///
42 | public int FaceIndex { get; set; }
43 |
44 | ///
45 | /// Gets or sets the U coordinate at the face.
46 | ///
47 | public double U { get; set; }
48 |
49 | ///
50 | /// Gets or sets the V coordinate at the face.
51 | ///
52 | public double V { get; set; }
53 |
54 | ///
55 | /// Gets or sets the W coordinate at the face.
56 | ///
57 | public double W { get; set; }
58 |
59 |
60 | ///
61 | /// Converts a mesh point into a string.
62 | ///
63 | /// String representation of the mesh point.
64 | public override string ToString() =>
65 | "MeshPoint{ " + this.FaceIndex + "; " + this.U + ", " + this.V + ", " + this.W + " }";
66 | }
67 | }
--------------------------------------------------------------------------------
/src/Geometry/NurbsCurve.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace Paramdigma.Core.Geometry
6 | {
7 | ///
8 | ///
9 | public class NurbsCurve : BaseCurve
10 | {
11 | ///
12 | /// The control points of the nurbs curve.
13 | ///
14 | public List ControlPoints;
15 |
16 | ///
17 | /// The degree of the curve.
18 | ///
19 | public int Degree;
20 |
21 | ///
22 | /// The nurbs curve knot vector.
23 | ///
24 | public List Knots;
25 |
26 |
27 | ///
28 | /// Initializes a new instance of by it's control points and degree.
29 | ///
30 | /// The control points to create the curve with.
31 | /// The desired degree of the curve. Degree cannot be > (ControlPoints - 1)
32 | public NurbsCurve(List controlPoints, int degree)
33 | {
34 | this.ControlPoints = controlPoints;
35 | this.Knots = NurbsCalculator.CreateUniformKnotVector(controlPoints.Count, degree)
36 | .ToList();
37 | this.Degree = degree;
38 | }
39 |
40 |
41 | ///
42 | /// Gets the count of the control points - 1.
43 | ///
44 | private int N => this.ControlPoints.Count - 1;
45 |
46 | ///
47 | /// The start point of the curve.
48 | ///
49 | public Point3d StartPoint => this.PointAt(this.Domain.Start);
50 |
51 | ///
52 | /// The end point of the curve.
53 | ///
54 | public Point3d EndPoint => this.PointAt(this.Domain.End);
55 |
56 | ///
57 | /// The tangent vector at the start of the curve.
58 | ///
59 | public Vector3d StartTangent => this.TangentAt(this.Domain.Start);
60 |
61 | ///
62 | /// The tangent vector at the end of the curve.
63 | ///
64 | public Vector3d EndTangent => this.TangentAt(this.Domain.End);
65 |
66 |
67 | ///
68 | /// Computes the specific amount of derivatives on the specified parameter.
69 | ///
70 | /// Parameter to compute derivatives at.
71 | /// Number of derivatives to compute.
72 | /// Array containing the
73 | private IList DerivativesAt(double t, int count) =>
74 | NurbsCalculator.NurbsCurveDerivs(
75 | this.N,
76 | this.Degree,
77 | this.Knots,
78 | this.ControlPoints,
79 | t,
80 | count
81 | );
82 |
83 |
84 | ///
85 | public override Point3d PointAt(double t) =>
86 | NurbsCalculator.CurvePoint(this.N, this.Degree, this.Knots, this.ControlPoints, t);
87 |
88 |
89 | ///
90 | public override Vector3d TangentAt(double t) => this.DerivativesAt(t, 1)[1].Unit();
91 |
92 |
93 | ///
94 | public override Vector3d NormalAt(double t) => this.DerivativesAt(t, 2)[2].Unit();
95 |
96 |
97 | ///
98 | public override Vector3d BinormalAt(double t) => this.DerivativesAt(t, 3)[3].Unit();
99 |
100 |
101 | ///
102 | public override Plane FrameAt(double t)
103 | {
104 | var ders = this.DerivativesAt(t, 3);
105 | return new Plane(( Point3d ) ders[0], ders[1], ders[2], ders[3]);
106 | }
107 |
108 |
109 | ///
110 | public override bool CheckValidity() => true;
111 |
112 |
113 | ///
114 | protected override double ComputeLength() => throw new NotImplementedException();
115 | }
116 | }
--------------------------------------------------------------------------------
/src/Geometry/Ray.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Paramdigma.Core.Geometry
4 | {
5 | ///
6 | /// Infinite 3d ray starting at a point.
7 | ///
8 | public class Ray
9 | {
10 | ///
11 | /// Initializes a new instance of the class with origin and direction.
12 | ///
13 | /// Point representing the origin of the ray.
14 | /// Vector representing the direction of the ray.
15 | public Ray(Point3d origin, Vector3d direction)
16 | {
17 | this.Origin = origin ?? throw new ArgumentNullException(nameof(origin));
18 | this.Direction = direction ?? throw new ArgumentNullException(nameof(direction));
19 | }
20 |
21 |
22 | ///
23 | /// Gets or sets the origin point of the ray.
24 | ///
25 | public Point3d Origin { get; set; }
26 |
27 | ///
28 | /// Gets or sets the direction vector of the ray.
29 | ///
30 | public Vector3d Direction { get; set; }
31 |
32 |
33 | ///
34 | /// Computes a point in the ray at the given parameter.
35 | ///
36 | /// Parameter to obtain point.
37 | /// Returns a point at the specified parameter of the Ray.
38 | public Point3d PointAt(double t) => this.Origin + t * this.Direction;
39 | }
40 | }
--------------------------------------------------------------------------------
/src/Geometry/Ray2d.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Paramdigma.Core.Geometry
4 | {
5 | ///
6 | /// Represents an infinite 2-dimensional ray.
7 | ///
8 | public class Ray2d
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// Origin point.
14 | /// Direction vector.
15 | public Ray2d(Point2d origin, Vector2d direction)
16 | {
17 | this.Origin = origin ?? throw new ArgumentNullException(nameof(origin));
18 | this.Direction = direction ?? throw new ArgumentNullException(nameof(direction));
19 | }
20 |
21 |
22 | ///
23 | /// Gets or sets the origin of the ray.
24 | ///
25 | /// Origin point.
26 | public Point2d Origin { get; set; }
27 |
28 | ///
29 | /// Gets or sets the direction of the ray as a unit vector.
30 | ///
31 | /// Direction vector.
32 | public Vector2d Direction { get; set; }
33 | }
34 | }
--------------------------------------------------------------------------------
/src/Geometry/Sphere.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Paramdigma.Core.Collections;
3 | using Paramdigma.Core.Geometry.Interfaces;
4 |
5 | namespace Paramdigma.Core.Geometry
6 | {
7 | ///
8 | /// Represents a spherical surface.
9 | ///
10 | public class Sphere : ISurface
11 | {
12 | ///
13 | /// Initializes a new instance of given it's base plane and radius.
14 | ///
15 | ///
16 | ///
17 | /// Throws when radius is smaller than 0.
18 | public Sphere(Plane plane, double radius)
19 | {
20 | if (Math.Abs(radius) < Settings.Tolerance)
21 | throw new ArithmeticException("Can't create a sphere of 0 radius.");
22 | this.Plane = plane;
23 | this.Radius = radius;
24 | this.DomainU = Interval.Unit;
25 | this.DomainV = Interval.Unit;
26 | }
27 |
28 |
29 | ///
30 | /// Initializes a new instance of around the World origin with unit radius.
31 | ///
32 | public Sphere() : this(Plane.WorldXY, 1) { }
33 |
34 |
35 | ///
36 | /// Gets or sets the base plane of the sphere.
37 | ///
38 | /// .
39 | public Plane Plane { get; set; }
40 |
41 | ///
42 | /// Gets or sets the radius of the sphere.
43 | ///
44 | /// .
45 | public double Radius { get; set; }
46 |
47 | ///
48 | public Interval DomainU { get; set; }
49 |
50 | ///
51 | public Interval DomainV { get; set; }
52 |
53 |
54 | ///
55 | public double DistanceTo(Point3d point) =>
56 | this.Plane.Origin.DistanceTo(point) - this.Radius;
57 |
58 |
59 | ///
60 | public Point3d ClosestPointTo(Point3d point) =>
61 | this.Plane.Origin + (point - this.Plane.Origin).Unit() * this.Radius;
62 |
63 |
64 | ///
65 | public Plane FrameAt(double u, double v) => throw new NotImplementedException();
66 |
67 |
68 | ///
69 | public Vector3d NormalAt(double u, double v) =>
70 | (this.PointAt(u, v) - this.Plane.Origin).Unit();
71 |
72 |
73 | ///
74 | public Point3d PointAt(double u, double v)
75 | {
76 | double x, y, z;
77 | var tau = new Interval(0, Math.PI).RemapFromUnit(v);
78 | var rho = new Interval(0, 2 * Math.PI).RemapFromUnit(u);
79 | x = this.Radius * Math.Sin(tau) * Math.Cos(rho);
80 | y = this.Radius * Math.Sin(tau) * Math.Sin(rho);
81 | z = this.Radius * Math.Cos(tau);
82 | return this.Plane.PointAt(x, y, z);
83 | }
84 |
85 |
86 | ///
87 | /// Returns the closest point on the sphere as a 2D point containing it's UV coordinates.
88 | ///
89 | /// Point to find closest to
90 | /// UV Parameter of the closest point as a Point2d instance.
91 | public Point2d ClosestParam(Point3d pt)
92 | {
93 | var rho = Math.Atan(pt.Y / pt.X);
94 | var tau = Math.Atan(Math.Sqrt(pt.X * pt.X + pt.Y * pt.Y) / pt.Z);
95 | var u = new Interval(0, 2 * Math.PI).RemapToUnit(rho);
96 | var v = new Interval(0, Math.PI).RemapToUnit(tau);
97 | return new Point2d(u, v);
98 | }
99 |
100 |
101 | ///
102 | /// Computes the point at a specified parameter, provided as a instance.
103 | ///
104 | /// parameter coordinates.
105 | /// instance of the specified point.
106 | public Point3d PointAt(Point2d uvPoint) => this.PointAt(uvPoint.X, uvPoint.Y);
107 | }
108 | }
--------------------------------------------------------------------------------
/src/Geometry/Torus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Paramdigma.Core.Collections;
3 | using Paramdigma.Core.Geometry.Interfaces;
4 |
5 | namespace Paramdigma.Core.Geometry
6 | {
7 | ///
8 | /// Represents a toroidal surface.
9 | ///
10 | public class Torus : ISurface
11 | {
12 | ///
13 | /// Initializes a new instance of the class from a plane and two radii.
14 | ///
15 | /// The torus base plane.
16 | /// The torus major radius.
17 | /// The torus minor radius.
18 | public Torus(Plane plane, double majorRadius, double minorRadius)
19 | {
20 | this.Plane = plane;
21 | this.MajorRadius = majorRadius;
22 | this.MinorRadius = minorRadius;
23 | }
24 |
25 |
26 | ///
27 | /// Gets or sets the torus base plane.
28 | ///
29 | /// .
30 | public Plane Plane { get; set; }
31 |
32 | ///
33 | /// Gets or sets the torus major radius.
34 | ///
35 | /// .
36 | public double MajorRadius { get; set; }
37 |
38 | ///
39 | /// Gets or sets the torus minor radius.
40 | ///
41 | /// .
42 | public double MinorRadius { get; set; }
43 |
44 | ///
45 | public Interval DomainU { get; set; }
46 |
47 | ///
48 | public Interval DomainV { get; set; }
49 |
50 |
51 | ///
52 | public Plane FrameAt(double u, double v) => throw new NotImplementedException();
53 |
54 |
55 | ///
56 | public double DistanceTo(Point3d point) => throw new NotImplementedException();
57 |
58 |
59 | ///
60 | public Point3d ClosestPointTo(Point3d point) => throw new NotImplementedException();
61 |
62 |
63 | ///
64 | public Vector3d NormalAt(double u, double v) => throw new NotImplementedException();
65 |
66 |
67 | ///
68 | public Point3d PointAt(double u, double v) => throw new NotImplementedException();
69 | }
70 | }
--------------------------------------------------------------------------------
/src/IO/CSVReader.cs:
--------------------------------------------------------------------------------
1 | #pragma warning disable 1591
2 |
3 | namespace Paramdigma.Core.IO
4 | {
5 | ///
6 | /// CSV File reader.
7 | ///
8 | public static class CsvReader { }
9 | }
--------------------------------------------------------------------------------
/src/IO/CSVWritter.cs:
--------------------------------------------------------------------------------
1 | #pragma warning disable 1591
2 |
3 | namespace Paramdigma.Core.IO
4 | {
5 | ///
6 | /// CSV File Writter.
7 | ///
8 | public static class CsvWritter { }
9 | }
--------------------------------------------------------------------------------
/src/IO/OBJMeshData.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Paramdigma.Core.Geometry;
3 |
4 | #pragma warning disable 1591
5 |
6 | namespace Paramdigma.Core.IO
7 | {
8 | public struct OBJMeshData
9 | {
10 | public OBJMeshData(
11 | List vertices,
12 | List> faces,
13 | List> edges,
14 | List> textureCoords,
15 | List> faceTextureCoords,
16 | List normals)
17 | {
18 | this.Vertices = vertices;
19 | this.Faces = faces;
20 | this.Edges = edges;
21 | this.TextureCoords = textureCoords;
22 | this.FaceTextureCoords = faceTextureCoords;
23 | this.Normals = normals;
24 | }
25 |
26 |
27 | public List Vertices { get; }
28 |
29 | public List> Faces { get; }
30 |
31 | public List> Edges { get; }
32 |
33 | public List> TextureCoords { get; }
34 |
35 | public List> FaceTextureCoords { get; }
36 |
37 | public List Normals { get; }
38 | }
39 | }
--------------------------------------------------------------------------------
/src/IO/OBJReader.cs:
--------------------------------------------------------------------------------
1 | #pragma warning disable 1591
2 |
3 | namespace Paramdigma.Core.IO
4 | {
5 | ///
6 | /// OBJ File Reader.
7 | ///
8 | public static class ObjReader { }
9 | }
--------------------------------------------------------------------------------
/src/IO/OBJWritter.cs:
--------------------------------------------------------------------------------
1 | #pragma warning disable 1591
2 |
3 | namespace Paramdigma.Core.IO
4 | {
5 | ///
6 | /// OBJ File Writter.
7 | ///
8 | public class ObjWritter { }
9 | }
--------------------------------------------------------------------------------
/src/IO/OFFMeshData.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Paramdigma.Core.Geometry;
3 |
4 | #pragma warning disable 1591
5 |
6 | namespace Paramdigma.Core.IO
7 | {
8 | ///
9 | /// Class containing the resulting mesh data extracted from an .OFF file.
10 | ///
11 | public class OffMeshData
12 | {
13 | ///
14 | /// Gets or sets the mesh vertices.
15 | ///
16 | public List Vertices { get; set; }
17 |
18 | ///
19 | /// Gets or sets the mesh face indices.
20 | ///
21 | public List> Faces { get; set; }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/IO/OFFReader.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using Paramdigma.Core.Geometry;
4 |
5 | #pragma warning disable 1591
6 |
7 | namespace Paramdigma.Core.IO
8 | {
9 | /// OFF Reader class.
10 | public static class OffReader
11 | {
12 | public static OffResult ReadMeshFromFile(string filePath, out OffMeshData data)
13 | {
14 | var lines = File.ReadAllLines(filePath);
15 | data = new OffMeshData();
16 |
17 | // Check if first line states OFF format
18 | if (lines[0] != "OFF")
19 | return OffResult.IncorrectFormat;
20 |
21 | // Get second line and extract number of vertices and faces
22 | var initialData = lines[1].Split(' ');
23 | if (!int.TryParse(initialData[0], out var nVertex))
24 | return OffResult.IncorrectFormat;
25 |
26 | if (!int.TryParse(initialData[1], out var nFaces))
27 | return OffResult.IncorrectFormat;
28 |
29 | // Check if length of lines correct
30 | if (nVertex + nFaces + 2 != lines.Length)
31 | return OffResult.IncorrectFormat;
32 |
33 | // Iterate through all the lines containing the mesh data
34 | const int start = 2;
35 | var vertices = new List();
36 | var faces = new List>();
37 |
38 | for (var i = start; i < lines.Length; i++)
39 | {
40 | if (i < nVertex + start)
41 | {
42 | // Extract vertices
43 | var coords = new List();
44 |
45 | // Iterate over the string fragments and convert them to numbers
46 | foreach (var ptStr in lines[i].Split(' '))
47 | {
48 | if (!double.TryParse(ptStr, out var ptCoord))
49 | return OffResult.IncorrectVertex;
50 | coords.Add(ptCoord);
51 | }
52 |
53 | vertices.Add(new Point3d(coords[0], coords[1], coords[2]));
54 | }
55 | else if (i < nVertex + nFaces + start)
56 | {
57 | // Extract faces
58 | // In OFF, faces come with a first number determining the number of vertices in that face
59 | var vertexIndexes = new List();
60 |
61 | var faceStrings = lines[i].Split(' ');
62 |
63 | // Get first int that represents vertex count of face
64 | if (!int.TryParse(faceStrings[0], out var _))
65 | return OffResult.IncorrectFace;
66 |
67 | for (var f = 1; f < faceStrings.Length; f++)
68 | {
69 | if (!int.TryParse(faceStrings[f], out var vertIndex))
70 | return OffResult.IncorrectFace;
71 |
72 | vertexIndexes.Add(vertIndex);
73 | }
74 |
75 | faces.Add(vertexIndexes);
76 | }
77 | }
78 |
79 | // Set data output
80 | data.Vertices = vertices;
81 | data.Faces = faces;
82 |
83 | return OffResult.Ok;
84 | }
85 | }
86 | }
--------------------------------------------------------------------------------
/src/IO/OFFResult.cs:
--------------------------------------------------------------------------------
1 | #pragma warning disable 1591
2 |
3 | namespace Paramdigma.Core.IO
4 | {
5 | ///
6 | /// Enum containing the result of the OFF conversion.
7 | ///
8 | public enum OffResult
9 | {
10 | Ok,
11 | IncorrectFormat,
12 | IncorrectVertex,
13 | IncorrectFace,
14 | NonMatchingVerticesSize,
15 | NonMatchingFacesSize,
16 | FileNotFound
17 | }
18 | }
--------------------------------------------------------------------------------
/src/IO/OffWriter.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using Paramdigma.Core.Geometry;
3 |
4 | #pragma warning disable 1591
5 |
6 | namespace Paramdigma.Core.IO
7 | {
8 | /// OFF format writer class.
9 | public static class OffWriter
10 | {
11 | ///
12 | /// Write a Half-Edge mesh to a .OFF file.
13 | ///
14 | /// Half-edge mesh to export.
15 | /// Path to save the file to.
16 | ///
17 | public static OffResult WriteMeshToFile(Mesh mesh, string filePath)
18 | {
19 | var offLines = new string[mesh.Vertices.Count + mesh.Faces.Count + 2];
20 |
21 | const string offHead = "OFF";
22 | offLines[0] = offHead;
23 | var offCount = mesh.Vertices.Count + " " + mesh.Faces.Count + " 0";
24 | offLines[1] = offCount;
25 |
26 | var count = 2;
27 | foreach (var vertex in mesh.Vertices)
28 | {
29 | var vText = vertex.X + " " + vertex.Y + " " + vertex.Z;
30 | offLines[count] = vText;
31 | count++;
32 | }
33 |
34 | foreach (var face in mesh.Faces)
35 | {
36 | if (!face.IsBoundaryLoop())
37 | {
38 | var vertices = face.AdjacentVertices();
39 | var faceString = vertices.Count.ToString();
40 |
41 | foreach (var v in face.AdjacentVertices())
42 | faceString = faceString + " " + v.Index;
43 |
44 | offLines[count] = faceString;
45 | count++;
46 | }
47 | }
48 |
49 | File.WriteAllLines(filePath, offLines);
50 | return OffResult.Ok;
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/src/LinearAlgebra/LeastSquaresLinearFit.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Paramdigma.Core.Geometry;
4 |
5 | namespace Paramdigma.Core.LinearAlgebra
6 | {
7 | ///
8 | /// Fit a line through a set of 2-dimensional points.
9 | ///
10 | public static class LeastSquaresLinearFit
11 | {
12 | // Find the least squares linear fit.
13 | // Return the total error.
14 | // Found at: http://csharphelper.com/blog/2014/10/find-a-linear-least-squares-fit-for-a-set-of-points-in-c/
15 |
16 |
17 | ///
18 | /// Find the least squares best fitting line to the given points.
19 | ///
20 | /// The points to fit the line through.
21 | /// Height.
22 | /// Slope.
23 | ///
24 | public static double FindLinearLeastSquaresFit(
25 | List points,
26 | out double m,
27 | out double b)
28 | {
29 | // Perform the calculation.
30 | // Find the values S1, Sx, Sy, Sxx, and Sxy.
31 | double s1 = points.Count;
32 | double sx = 0, sy = 0, sxx = 0, sxy = 0;
33 |
34 | foreach (var pt in points)
35 | {
36 | sx += pt.X;
37 | sy += pt.Y;
38 | sxx += pt.X * pt.X;
39 | sxy += pt.X * pt.Y;
40 | }
41 |
42 | // Solve for m and b.
43 | m = (sxy * s1 - sx * sy) / (sxx * s1 - sx * sx);
44 | b = (sxy * sx - sy * sxx) / (sx * sx - s1 * sxx);
45 |
46 | return Math.Sqrt(ErrorSquared(points, m, b));
47 | }
48 |
49 |
50 | // Return the error squared.
51 | private static double ErrorSquared(List points, double m, double b)
52 | {
53 | double total = 0;
54 | foreach (var pt in points)
55 | {
56 | var dy = pt.Y - (m * pt.X + b);
57 | total += dy * dy;
58 | }
59 |
60 | return total;
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/src/LinearAlgebra/Triplet.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | #pragma warning disable 1591
4 |
5 | namespace Paramdigma.Core.LinearAlgebra
6 | {
7 | ///
8 | /// Represents a set of data in a sparse matrix.
9 | ///
10 | public class Triplet
11 | {
12 | // Constructor
13 | public Triplet(int m, int n)
14 | {
15 | this.M = m;
16 | this.N = n;
17 | this.Values = new List();
18 | }
19 | // Public fields
20 |
21 |
22 | ///
23 | /// Gets values held by this triplet.
24 | ///
25 | ///
26 | public List Values { get; }
27 |
28 | public int M { get; }
29 |
30 | public int N { get; }
31 |
32 |
33 | // Methods
34 | public void AddEntry(double value, int m, int n)
35 | {
36 | var tD = new TripletData {Value = value, Row = m, Column = n};
37 |
38 | this.Values.Add(tD);
39 | }
40 | }
41 |
42 | public struct TripletData
43 | {
44 | public int Row { get; set; }
45 |
46 | public int Column { get; set; }
47 |
48 | public double Value { get; set; }
49 | }
50 | }
--------------------------------------------------------------------------------
/src/Optimization/GradientDescentOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Paramdigma.Core.Optimization
2 | {
3 | ///
4 | /// Contains the different options of a Gradient Descent minimization.
5 | ///
6 | public struct GradientDescentOptions
7 | {
8 | ///
9 | /// Threshold to stop minimization.
10 | ///
11 | public double Limit;
12 |
13 | ///
14 | /// Maximum iterations for the gradient descent.
15 | ///
16 | public int MaxIterations;
17 |
18 | ///
19 | /// Step size to compute partial derivatives.
20 | ///
21 | public double DerivativeStep;
22 |
23 | ///
24 | /// Scaling factor for the gradient. Effectively speeds up or down the minimization.
25 | ///
26 | public double LearningRate;
27 |
28 | ///
29 | /// Minimum error to consider the results acceptable.
30 | ///
31 | public double ErrorThreshold;
32 |
33 |
34 | ///
35 | /// Initializes a new instance of the struct given an
36 | /// existing one.
37 | ///
38 | /// Options to duplicate.
39 | public GradientDescentOptions(GradientDescentOptions options)
40 | {
41 | this.Limit = options.Limit;
42 | this.MaxIterations = options.MaxIterations;
43 | this.DerivativeStep = options.DerivativeStep;
44 | this.LearningRate = options.LearningRate;
45 | this.ErrorThreshold = options.ErrorThreshold;
46 | }
47 |
48 |
49 | // TODO: Fill in this fields!
50 |
51 |
52 | ///
53 | /// Initializes a new instance of the struct given all it's
54 | /// values individually.
55 | ///
56 | ///
57 | ///
58 | ///
59 | ///
60 | ///
61 | public GradientDescentOptions(
62 | double threshold,
63 | int maxIterations,
64 | double derivativeStep,
65 | double learningRate,
66 | double errorThreshold)
67 | {
68 | this.Limit = threshold;
69 | this.MaxIterations = maxIterations;
70 | this.DerivativeStep = derivativeStep;
71 | this.LearningRate = learningRate;
72 | this.ErrorThreshold = errorThreshold;
73 | }
74 |
75 |
76 | ///
77 | /// Gets a GradientDescentOptions instance with the default values.
78 | ///
79 | public static GradientDescentOptions Default =>
80 | new GradientDescentOptions(0.001, 10000, 0.01, 20, .01);
81 |
82 | ///
83 | /// Gets a GradientDescentOptions instance with small values.
84 | ///
85 | ///
86 | public static GradientDescentOptions DefaultSmall =>
87 | new GradientDescentOptions(0.0001, 10000, 0.02, 40, .001);
88 | }
89 | }
--------------------------------------------------------------------------------
/src/Optimization/GradientDescentResult.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Paramdigma.Core.Optimization
4 | {
5 | ///
6 | /// Contains the result values of a Gradient Descent minimization.
7 | ///
8 | public struct GradientDescentResult
9 | {
10 | ///
11 | /// Resulting values after gradient descen minimization.
12 | ///
13 | public List Values;
14 |
15 | ///
16 | /// Final gradient descent error.
17 | ///
18 | public double Error;
19 |
20 | ///
21 | /// Final length of the gradient.
22 | ///
23 | public double GradientLength;
24 | }
25 | }
--------------------------------------------------------------------------------
/src/Optimization/KMeansCluster.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using Paramdigma.Core.Geometry;
4 |
5 | namespace Paramdigma.Core.Optimization
6 | {
7 | ///
8 | /// Represents a vector cluster for the K-Means Clustering Algorithm.
9 | ///
10 | public class KMeansCluster : IList
11 | {
12 | private readonly IList list = new List();
13 |
14 | ///
15 | /// Gets or sets the vector at the given index.
16 | ///
17 | /// Index of the desired object.
18 | public VectorNd this[int index]
19 | {
20 | get => this.list[index];
21 | set => this.list[index] = value;
22 | }
23 |
24 | ///
25 | /// Gets the amount of clusters.
26 | ///
27 | public int Count => this.list.Count;
28 |
29 | ///
30 | /// Gets a value indicating whether the cluster is readOnly.
31 | ///
32 | public bool IsReadOnly => this.list.IsReadOnly;
33 |
34 |
35 | ///
36 | /// Add a new vector to the cluster.
37 | ///
38 | /// Vector to add.
39 | public void Add(VectorNd item) => this.list.Add(item);
40 |
41 |
42 | ///
43 | public void Clear() => this.list.Clear();
44 |
45 |
46 | ///
47 | public bool Contains(VectorNd item) => this.list.Contains(item);
48 |
49 |
50 | ///
51 | public void CopyTo(VectorNd[] array, int arrayIndex) => this.list.CopyTo(array, arrayIndex);
52 |
53 |
54 | ///
55 | public IEnumerator GetEnumerator() => this.list.GetEnumerator();
56 |
57 |
58 | ///
59 | public int IndexOf(VectorNd item) => this.list.IndexOf(item);
60 |
61 |
62 | ///
63 | public void Insert(int index, VectorNd item) => this.list.Insert(index, item);
64 |
65 |
66 | ///
67 | public bool Remove(VectorNd item) => this.list.Remove(item);
68 |
69 |
70 | ///
71 | public void RemoveAt(int index) => this.list.RemoveAt(index);
72 |
73 |
74 | IEnumerator IEnumerable.GetEnumerator() => this.list.GetEnumerator();
75 |
76 |
77 | ///
78 | /// Computes the average of this cluster.
79 | ///
80 | /// Average vector of the current cluster.
81 | public VectorNd Average()
82 | {
83 | if (this.list.Count == 0)
84 | return new VectorNd(0);
85 | if (this.list.Count == 1)
86 | return this.list[0];
87 |
88 | var result = new VectorNd(this.list[0].Dimension);
89 | foreach (var vector in this.list)
90 | result += vector;
91 |
92 | result /= this.list.Count;
93 | return result;
94 | }
95 |
96 |
97 | ///
98 | public override string ToString() => "Paramdigma.Core.Cluster[" + this.Count + "]";
99 | }
100 | }
--------------------------------------------------------------------------------
/src/Paramdigma.Core.Rules.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | c
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/Paramdigma.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Computational Geometry library for .NET
7 | netstandard2.0
8 | Paramdigma Core
9 | https://paramdigma.com/Core/
10 | https://github.com/Paramdigma/Core/blob/master/LICENSE
11 | git
12 | 8
13 | 0.1.2
14 |
15 |
16 |
17 | Paramdigma.Core
18 | 0.1.1
19 | Alan Rynne
20 | Paramdigma
21 | Computational Geometry library for .Net
22 | https://github.com/Paramdigma/Core
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | true
44 | Paramdigma.Core.Rules.ruleset
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/Spatial/Delaunay.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using Paramdigma.Core.Spatial;
4 |
5 | namespace Paramdigma.Core.Geometry
6 | {
7 | ///
8 | /// Class holding all the delaunay and Voronoi classes in 2 dimensions.
9 | ///
10 | public static class Delaunay
11 | {
12 | ///
13 | /// Compute the delaunay triangulation of a given list of points.
14 | ///
15 | /// Points to find delaunay tessellation.
16 | /// Border to start from.
17 | /// List of .
18 | public static IEnumerable Compute(
19 | IEnumerable points,
20 | IEnumerable border)
21 | {
22 | var triangulation = new List(border);
23 | foreach (var point in points)
24 | {
25 | var badTriangles = FindBadTriangles(point, triangulation).ToList();
26 | var polygon = FindHoleBoundaries(badTriangles);
27 | foreach (var triangle in badTriangles)
28 | {
29 | foreach (var vertex in triangle.Vertices)
30 | vertex.AdjacentTriangles.Remove(triangle);
31 |
32 | if (triangulation.Contains(triangle))
33 | triangulation.Remove(triangle);
34 | }
35 |
36 | triangulation.AddRange(
37 | polygon.Select(
38 | edge => new DelaunayTriangle(point, (DelaunayPoint)edge.StartPoint, (DelaunayPoint)edge.EndPoint)));
39 | }
40 |
41 | return triangulation;
42 | }
43 |
44 |
45 | ///
46 | /// Computes the Voronoi diagram of a given Delaunay triangulation as a list of
47 | /// instances.
48 | ///
49 | /// Delaunay triangulation.
50 | /// Collection of lines representing the Voronoi cells.
51 | public static IEnumerable Voronoi(IEnumerable triangulation)
52 | =>
53 | from triangle in triangulation
54 | from neighbour in triangle.TrianglesWithSharedEdges()
55 | select new Line2d(triangle.Circumcenter, neighbour.Circumcenter);
56 |
57 |
58 | private static IEnumerable FindHoleBoundaries(
59 | IEnumerable badTriangles)
60 | {
61 | var boundaryEdges = new List();
62 | var duplicateEdges = new List();
63 | foreach (var triangle in badTriangles)
64 | {
65 | for (var i = 0; i < triangle.Vertices.Count; i++)
66 | {
67 | var e = new DelaunayEdge(
68 | triangle.Vertices[i],
69 | triangle.Vertices[(i + 1) % triangle.Vertices.Count]);
70 | if (!boundaryEdges.Contains(e))
71 | boundaryEdges.Add(e);
72 | else
73 | duplicateEdges.Add(e);
74 | }
75 | }
76 |
77 | for (var i = boundaryEdges.Count - 1; i >= 0; i--)
78 | {
79 | var e = boundaryEdges[i];
80 | if (duplicateEdges.Contains(e))
81 | boundaryEdges.Remove(e);
82 | }
83 |
84 | return boundaryEdges;
85 | }
86 |
87 |
88 | private static IEnumerable FindBadTriangles(
89 | Point2d point,
90 | IEnumerable triangles)
91 | => triangles.Where(triangle => triangle.IsPointInsideCircumcircle(point));
92 | }
93 | }
--------------------------------------------------------------------------------
/src/Spatial/DelaunayEdge.cs:
--------------------------------------------------------------------------------
1 | using Paramdigma.Core.Geometry;
2 |
3 | namespace Paramdigma.Core.Spatial
4 | {
5 | ///
6 | /// Represents a connection between two points in a Delaunay triangulation.
7 | ///
8 | public class DelaunayEdge: Line2d
9 | {
10 |
11 | ///
12 | /// Initializes a new instance of the class.
13 | ///
14 | /// Start point.
15 | /// End point.
16 | public DelaunayEdge(DelaunayPoint startPoint, DelaunayPoint endPoint): base(startPoint, endPoint)
17 | {
18 | }
19 |
20 |
21 | ///
22 | public override bool Equals(object obj)
23 | {
24 | if (!(obj is DelaunayEdge edge))
25 | return false;
26 | var samePoints = this.StartPoint == edge.StartPoint && this.EndPoint == edge.EndPoint;
27 | var samePointsReversed =
28 | this.StartPoint == edge.EndPoint && this.EndPoint == edge.StartPoint;
29 | return samePoints || samePointsReversed;
30 | }
31 |
32 |
33 | ///
34 | public override int GetHashCode()
35 | {
36 | var hCode = ( int ) this.StartPoint.X
37 | ^ ( int ) this.StartPoint.Y
38 | ^ ( int ) this.EndPoint.X
39 | ^ ( int ) this.EndPoint.Y;
40 | return hCode.GetHashCode();
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/src/Spatial/DelaunayPoint.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Paramdigma.Core.Geometry;
3 |
4 | namespace Paramdigma.Core.Spatial
5 | {
6 | ///
7 | /// Represents a point in a delaunay triangulation with adjacency information.
8 | ///
9 | public class DelaunayPoint : Point2d
10 | {
11 | ///
12 | /// List of adjacent triangles of this point.
13 | ///
14 | public readonly List AdjacentTriangles;
15 |
16 |
17 | ///
18 | /// Initializes a new instance of the class from it's coordinates.
19 | ///
20 | /// X Coordinate.
21 | /// Y Coordinate.
22 | public DelaunayPoint(double x, double y) : base(x, y) =>
23 | this.AdjacentTriangles = new List();
24 |
25 |
26 | ///
27 | /// Initializes a new instance of the class from a
28 | /// instance.
29 | ///
30 | /// Point to create from.
31 | public DelaunayPoint(Point2d point) : base(point.X, point.Y) { }
32 |
33 | }
34 | }
--------------------------------------------------------------------------------
/src/Spatial/Octree.cs:
--------------------------------------------------------------------------------
1 | namespace Paramdigma.Core.Spatial
2 | {
3 | ///
4 | /// Class for computing Octree spatial searches.
5 | ///
6 | public class Octree
7 | {
8 | // TODO: This class is empty!
9 | }
10 | }
--------------------------------------------------------------------------------
/src/Spatial/PointCloud.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 |
4 | namespace Paramdigma.Core.Spatial
5 | {
6 | ///
7 | /// Represents a collection of points with a color assigned to them.
8 | /// TODO: This is only a basic data structure for now.
9 | ///
10 | public class PointCloud : IList
11 | {
12 | ///
13 | /// Constructs a new point-cloud from a list of point cloud members..
14 | ///
15 | /// List of point-cloud members.
16 | public PointCloud(List points) => this.Points = points;
17 |
18 |
19 | private List Points { get; }
20 |
21 |
22 | ///
23 | public IEnumerator GetEnumerator() => this.Points.GetEnumerator();
24 |
25 |
26 | IEnumerator IEnumerable.GetEnumerator() => (( IEnumerable ) this.Points).GetEnumerator();
27 |
28 |
29 | ///
30 | public void Add(PointCloudMember item) => this.Points.Add(item);
31 |
32 |
33 | ///
34 | public void Clear() => this.Points.Clear();
35 |
36 |
37 | ///
38 | public bool Contains(PointCloudMember item) => this.Points.Contains(item);
39 |
40 |
41 | ///
42 | public void CopyTo(PointCloudMember[] array, int arrayIndex) =>
43 | this.Points.CopyTo(array, arrayIndex);
44 |
45 |
46 | ///
47 | public bool Remove(PointCloudMember item) => this.Points.Remove(item);
48 |
49 |
50 | ///
51 | public int Count => this.Points.Count;
52 |
53 | ///
54 | public bool IsReadOnly => (( ICollection ) this.Points).IsReadOnly;
55 |
56 |
57 | ///
58 | public int IndexOf(PointCloudMember item) => this.Points.IndexOf(item);
59 |
60 |
61 | ///
62 | public void Insert(int index, PointCloudMember item) => this.Points.Insert(index, item);
63 |
64 |
65 | ///
66 | public void RemoveAt(int index) => this.Points.RemoveAt(index);
67 |
68 |
69 | ///
70 | public PointCloudMember this[int index]
71 | {
72 | get => this.Points[index];
73 | set => this.Points[index] = value;
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/src/Spatial/PointCloudMember.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using Paramdigma.Core.Geometry;
3 |
4 | namespace Paramdigma.Core.Spatial
5 | {
6 | ///
7 | /// Class representing a point contained in a point cloud.
8 | ///
9 | public class PointCloudMember : BasePoint
10 | {
11 | ///
12 | /// Gets or sets the color at this point.
13 | ///
14 | /// The current color if set, defaults to white.
15 | public Color Color { get; set; }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/Spatial/Quadtree.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Paramdigma.Core.Geometry;
3 |
4 | namespace Paramdigma.Core.Spatial
5 | {
6 | ///
7 | /// Class to compute 2 dimensional spatial searches by quad subdivision.
8 | ///
9 | public class QuadTree
10 | {
11 | ///
12 | /// Boundary of this QuadTree.
13 | ///
14 | public readonly Rectangle2d Boundary;
15 |
16 | ///
17 | /// Gets or sets the list of points of this QuadTree.
18 | ///
19 | public readonly List Points;
20 |
21 | private readonly double threshold;
22 |
23 | private QuadTree northEast;
24 | private QuadTree northWest;
25 | private QuadTree southEast;
26 | private QuadTree southWest;
27 |
28 |
29 | ///
30 | /// Initializes a new instance of the class.
31 | ///
32 | /// Boundary of this QuadTree.
33 | /// Smallest allowed dimension.
34 | public QuadTree(Rectangle2d boundary, double threshold)
35 | {
36 | this.Boundary = boundary;
37 | this.Points = new List();
38 | this.threshold = threshold;
39 | }
40 |
41 |
42 | ///
43 | /// Insert a point in the QuadTree.
44 | ///
45 | /// Point to insert.
46 | /// True if point was inserted.
47 | public bool Insert(Point2d point)
48 | {
49 | if (!this.Boundary.ContainsPoint(point))
50 | return false;
51 |
52 | if (this.Boundary.XDomain.Length < this.threshold
53 | || this.Boundary.YDomain.Length < this.threshold)
54 | {
55 | this.Points.Add(point);
56 | return true;
57 | }
58 |
59 | this.Subdivide();
60 |
61 | if (this.northEast.Insert(point)
62 | || this.northWest.Insert(point)
63 | || this.southWest.Insert(point)
64 | || this.southEast.Insert(point))
65 | return true;
66 |
67 | return false;
68 | }
69 |
70 |
71 | ///
72 | /// Query the QuadTree for all points contained in this range.
73 | ///
74 | /// Range to look for.
75 | /// Points contained in the range.
76 | public List QueryRange(Rectangle2d range)
77 | {
78 | var pointsInRange = new List();
79 |
80 | if (!this.Boundary.IntersectsBox(range))
81 | return pointsInRange;
82 |
83 | this.Points.ForEach(
84 | pt =>
85 | {
86 | if (range.ContainsPoint(pt))
87 | pointsInRange.Add(pt);
88 | });
89 |
90 | // If we reached threshold return
91 | if (this.Boundary.XDomain.Length < this.threshold
92 | || this.Boundary.YDomain.Length < this.threshold)
93 | return pointsInRange;
94 |
95 | if (this.southWest != null)
96 | {
97 | pointsInRange.AddRange(this.southWest.QueryRange(range));
98 | pointsInRange.AddRange(this.southEast.QueryRange(range));
99 | pointsInRange.AddRange(this.northWest.QueryRange(range));
100 | pointsInRange.AddRange(this.northEast.QueryRange(range));
101 | }
102 |
103 | return pointsInRange;
104 | }
105 |
106 |
107 | private void Subdivide()
108 | {
109 | this.southWest = new QuadTree(
110 | new Rectangle2d(this.Boundary.BottomLeft, this.Boundary.Center),
111 | this.threshold);
112 | this.northWest = new QuadTree(
113 | new Rectangle2d(this.Boundary.MidLeft, this.Boundary.MidTop),
114 | this.threshold);
115 | this.southEast = new QuadTree(
116 | new Rectangle2d(this.Boundary.MidBottom, this.Boundary.MidRight),
117 | this.threshold);
118 | this.northEast = new QuadTree(
119 | new Rectangle2d(this.Boundary.Center, this.Boundary.TopRight),
120 | this.threshold);
121 | }
122 | }
123 | }
--------------------------------------------------------------------------------
/src/Utility/Convert.cs:
--------------------------------------------------------------------------------
1 | using Paramdigma.Core.Geometry;
2 |
3 | namespace Paramdigma.Core
4 | {
5 | ///
6 | /// Static class to handle unit and type conversions.
7 | ///
8 | public static class Convert
9 | {
10 | ///
11 | /// Compute barycentric coordinates (u, v, w) for
12 | /// point p with respect to triangle (a, b, c).
13 | ///
14 | /// Point to convert.
15 | /// First point of triangle.
16 | /// Second point of triangle.
17 | /// Third point of triangle.
18 | ///
19 | public static double[] Point3dToBarycentric(Point3d p, Point3d a, Point3d b, Point3d c)
20 | {
21 | Vector3d v0 = b - a, v1 = c - a, v2 = p - a;
22 |
23 | var den = v0.X * v1.Y - v1.X * v0.Y;
24 |
25 | var v = (v2.X * v1.Y - v1.X * v2.Y) / den;
26 | var w = (v0.X * v2.Y - v2.X * v0.Y) / den;
27 | var u = 1.0 - v - w;
28 |
29 | double[] result = {u, v, w};
30 |
31 | return result;
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/src/Utility/Settings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 | using Newtonsoft.Json;
5 |
6 | namespace Paramdigma.Core
7 | {
8 | ///
9 | /// Multi-layered struct that holds the library settings.
10 | ///
11 | public static class Settings
12 | {
13 | private static int tesselationLevel = 10;
14 |
15 | ///
16 | /// Gets the minimum value allowed when using this library.
17 | ///
18 | public static double Tolerance { get; private set; } = 0.0000001;
19 |
20 | ///
21 | /// Gets how many decimals are allowed when using the library.
22 | ///
23 | public static int MaxDecimals
24 | {
25 | get
26 | {
27 | var t = Tolerance.ToString("N14");
28 | return t.Substring(t.IndexOf(".", StringComparison.Ordinal) + 1).IndexOf("1", StringComparison.Ordinal) + 1;
29 | }
30 | }
31 |
32 |
33 | ///
34 | /// Gets the default tessellation level when converting nurbs to meshes.
35 | ///
36 | /// Integer representing the default tessellation level.
37 | public static int GetDefaultTesselationLevel() => tesselationLevel;
38 |
39 |
40 | ///
41 | /// Sets the default tessellation level when converting nurbs to meshes.
42 | ///
43 | private static void SetDefaultTesselationLevel(int value) => tesselationLevel = value;
44 |
45 |
46 | ///
47 | /// Modifies the tolerance and computes the maxDecimals value accordingly.
48 | ///
49 | /// Desired tolerance.
50 | public static void SetTolerance(double tolerance) => Tolerance = tolerance;
51 |
52 |
53 | ///
54 | /// Reset the Settings to it's default values.
55 | ///
56 | public static void Reset()
57 | {
58 | var assembly = typeof(Settings).GetTypeInfo().Assembly;
59 | using (var stream =
60 | assembly.GetManifestResourceStream("Paramdigma.Core.Data.Settings.json"))
61 | {
62 | using (var reader = new StreamReader(
63 | stream ?? throw new InvalidOperationException("Could not get settings.")))
64 | {
65 | var result = reader.ReadToEnd();
66 | var json = JsonConvert.DeserializeObject(result);
67 | SetTolerance(json.Tolerance);
68 | SetDefaultTesselationLevel(json.DefaultTesselation);
69 | }
70 | }
71 | }
72 | }
73 |
74 | ///
75 | /// This struct holds the settings from the embedded json file. It is only used to reset.
76 | ///
77 | internal struct EmbeddedSettings
78 | {
79 | public double Tolerance;
80 | public int DefaultTesselation;
81 | }
82 | }
--------------------------------------------------------------------------------
/tests/Collections/IntervalTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Paramdigma.Core.Collections;
3 | using Xunit;
4 |
5 | namespace Paramdigma.Core.Tests
6 | {
7 | public class IntervalTests
8 | {
9 | [Fact]
10 | public void Can_CheckAndModifyDirection()
11 | {
12 | var i = new Interval(1, 4);
13 | var dir = i.HasInvertedDirection;
14 | i.FlipDirection();
15 | var dir2 = i.HasInvertedDirection;
16 | Assert.True(dir != dir2);
17 | }
18 |
19 |
20 | [Fact]
21 | public void Can_CheckContainment()
22 | {
23 | var i = new Interval(0.455, 4.134);
24 | const double n1 = 0.0;
25 | const double n2 = 5.0;
26 | const double n3 = 2.33;
27 | Assert.False(i.Contains(n1));
28 | Assert.False(i.Contains(n2));
29 | Assert.True(i.Contains(n3));
30 | }
31 |
32 |
33 | [Fact]
34 | public void Can_CropNumbers()
35 | {
36 | var i = new Interval(0.455, 4.134);
37 | const double n1 = 0.0;
38 | const double n2 = 5.0;
39 | const double n3 = 2.33;
40 | var n1C = i.Crop(n1);
41 | var n2C = i.Crop(n2);
42 | var n3C = i.Crop(n3);
43 | Assert.True(Math.Abs(n1C - i.Start) < Settings.Tolerance);
44 | Assert.True(Math.Abs(n2C - i.End) < Settings.Tolerance);
45 | Assert.True(Math.Abs(n3C - n3) < Settings.Tolerance);
46 | }
47 |
48 |
49 | [Fact]
50 | public void Can_RemapNumbers()
51 | {
52 | var i = new Interval(1, 3);
53 | const double n = 2.0;
54 | var nMap = i.RemapToUnit(n);
55 | Assert.True(Math.Abs(nMap - 0.5) < Settings.Tolerance);
56 | var nRemap = i.RemapFromUnit(nMap);
57 | Assert.True(Math.Abs(n - nRemap) < Settings.Tolerance);
58 | }
59 |
60 |
61 | [Fact]
62 | public void CanCreate_Interval()
63 | {
64 | var i0 = Interval.Unit;
65 | Assert.Equal(1, i0.Length);
66 | Assert.Throws(() => new Interval(double.NaN, 1));
67 | Assert.Throws(() => new Interval(0, double.NaN));
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/tests/Curves/LevelSetsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Paramdigma.Core.Curves;
3 | using Paramdigma.Core.Geometry;
4 | using Xunit;
5 |
6 | namespace Paramdigma.Core.Tests.Curves
7 | {
8 | public class LevelSetsTests
9 | {
10 | public Mesh Triangle
11 | {
12 | get
13 | {
14 | var key = "scalar-1";
15 | var ptA = new MeshVertex(0, 0, 0);
16 | ptA.UserValues[key] = 0;
17 | var ptB = new MeshVertex(1, 0, 0);
18 | ptB.UserValues[key] = 0;
19 | var ptC = new MeshVertex(0.5, 1, 1);
20 | ptC.UserValues[key] = 1;
21 | var vertices = new List {ptA, ptB, ptC};
22 | var face = new List {0, 1, 2};
23 | var mesh = new Mesh(vertices, new List> {face});
24 | return mesh;
25 | }
26 | }
27 |
28 |
29 | [Fact]
30 | public void CanCompute_GradientInFace_ReturnsValidVector()
31 | {
32 | var c = LevelSets.ComputeGradientField("scalar-1", this.Triangle);
33 | Assert.Equal(this.Triangle.Faces.Count, c.Count);
34 | Assert.Equal(new Vector3d(0, -1, -1).Unit(), c[0].Unit());
35 | }
36 |
37 |
38 | [Fact]
39 | public void CanCompute_LevelInFace_ReturnsValidLine()
40 | {
41 | LevelSets.ComputeLevels(
42 | "scalar-1",
43 | new List {0.5},
44 | this.Triangle,
45 | out var levelSets);
46 | Assert.NotEmpty(levelSets);
47 | var v = ( Vector3d ) levelSets[0][0];
48 | Assert.Equal(new Vector3d(1, 0, 0), v.Unit());
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/tests/Data/meshes/cube.off:
--------------------------------------------------------------------------------
1 | OFF
2 | 8 12 0
3 | -0.5 -0.5 -0.5
4 | 0.5 -0.5 -0.5
5 | 0.5 0.5 -0.5
6 | -0.5 0.5 -0.5
7 | -0.5 -0.5 0.5
8 | 0.5 -0.5 0.5
9 | 0.5 0.5 0.5
10 | -0.5 0.5 0.5
11 | 3 0 2 1
12 | 3 0 3 2
13 | 3 5 0 1
14 | 3 5 4 0
15 | 3 2 6 1
16 | 3 3 6 2
17 | 3 5 1 6
18 | 3 5 6 4
19 | 3 0 7 3
20 | 3 0 4 7
21 | 3 3 7 6
22 | 3 6 7 4
23 |
--------------------------------------------------------------------------------
/tests/Data/meshes/sphere.off:
--------------------------------------------------------------------------------
1 | OFF
2 | 22 40 0
3 | 0 0 -10
4 | 5.87785243988037 0 -8.09016990661621
5 | 1.81635630130768 5.59016990661621 -8.09016990661621
6 | -4.75528240203857 3.45491504669189 -8.09016990661621
7 | -4.75528240203857 -3.45491504669189 -8.09016990661621
8 | 1.81635630130768 -5.59016990661621 -8.09016990661621
9 | 9.51056480407715 0 -3.09016990661621
10 | 2.93892621994019 9.04508495330811 -3.09016990661621
11 | -7.69420862197876 5.59016990661621 -3.09016990661621
12 | -7.69420862197876 -5.59016990661621 -3.09016990661621
13 | 2.93892621994019 -9.04508495330811 -3.09016990661621
14 | 9.51056480407715 0 3.09016990661621
15 | 2.93892621994019 9.04508495330811 3.09016990661621
16 | -7.69420862197876 5.59016990661621 3.09016990661621
17 | -7.69420862197876 -5.59016990661621 3.09016990661621
18 | 2.93892621994019 -9.04508495330811 3.09016990661621
19 | 5.87785243988037 0 8.09016990661621
20 | 1.81635630130768 5.59016990661621 8.09016990661621
21 | -4.75528240203857 3.45491504669189 8.09016990661621
22 | -4.75528240203857 -3.45491504669189 8.09016990661621
23 | 1.81635630130768 -5.59016990661621 8.09016990661621
24 | 0 0 10
25 | 3 1 0 2
26 | 3 2 0 3
27 | 3 3 0 4
28 | 3 4 0 5
29 | 3 5 0 1
30 | 3 7 1 2
31 | 3 8 2 3
32 | 3 9 3 4
33 | 3 10 4 5
34 | 3 6 5 1
35 | 3 12 6 7
36 | 3 13 7 8
37 | 3 14 8 9
38 | 3 14 9 10
39 | 3 11 10 6
40 | 3 17 11 12
41 | 3 18 12 13
42 | 3 19 13 14
43 | 3 19 14 15
44 | 3 16 15 11
45 | 3 21 16 17
46 | 3 21 17 18
47 | 3 21 18 19
48 | 3 21 19 20
49 | 3 21 20 16
50 | 3 6 1 7
51 | 3 7 2 8
52 | 3 8 3 9
53 | 3 9 4 10
54 | 3 10 5 6
55 | 3 11 6 12
56 | 3 12 7 13
57 | 3 13 8 14
58 | 3 14 10 15
59 | 3 15 10 11
60 | 3 16 11 17
61 | 3 17 12 18
62 | 3 18 13 19
63 | 3 19 15 20
64 | 3 20 15 16
65 |
--------------------------------------------------------------------------------
/tests/Extensions/ListExtensionsTests.cs:
--------------------------------------------------------------------------------
1 | using Paramdigma.Core.Extensions;
2 | using Paramdigma.Core.Geometry;
3 | using Xunit;
4 |
5 | namespace Paramdigma.Core.Tests.Extensions
6 | {
7 | public class ListExtensionsTests
8 | {
9 | [Fact]
10 | public void CanCreate_Repeated()
11 | {
12 | for (var i = 1; i < 10; i++)
13 | {
14 | var list2 = Lists.Repeated(new Point3d(1, 1, 1), 4);
15 | list2.ForEach(pt => Assert.Equal(new Point3d(1, 1, 1), pt));
16 | }
17 | }
18 |
19 |
20 | [Fact]
21 | public void CanCreate_RepeatedDefault()
22 | {
23 | for (var i = 1; i < 10; i++)
24 | {
25 | var list2 = Lists.RepeatedDefault(i);
26 | Assert.True(list2.Count == i);
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/tests/Geometry/2D/DelaunayTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Paramdigma.Core.Geometry;
5 | using Paramdigma.Core.Spatial;
6 | using Xunit;
7 |
8 | namespace Paramdigma.Core.Tests.Geometry
9 | {
10 | public class DelaunayTests
11 | {
12 | [Fact]
13 | public void CanComputeDelaunay()
14 | {
15 | var maxX = 100;
16 | var maxY = 100;
17 | var point0 = new DelaunayPoint(0, 0);
18 | var point1 = new DelaunayPoint(0, maxY);
19 | var point2 = new DelaunayPoint(maxX, maxY);
20 | var point3 = new DelaunayPoint(maxX, 0);
21 | var point4 = new DelaunayPoint(maxX / 2.0, maxY / 2.0);
22 |
23 | var triangle1 = new DelaunayTriangle(point0, point1, point2);
24 | var triangle2 = new DelaunayTriangle(point0, point2, point3);
25 | var border = new List {triangle1, triangle2};
26 |
27 | var delaunay = Delaunay.Compute(
28 | new List
29 | {
30 | point0, point1, point2, point3, point4
31 | },
32 | border
33 | )
34 | .ToList();
35 | Assert.True(delaunay.Count == 4);
36 |
37 | var voronoi = Delaunay.Voronoi(delaunay);
38 | // TODO: We expect 8 because it currently outputs the lines repeated twice.
39 | Assert.True(voronoi.ToList().Count == 8);
40 | }
41 |
42 |
43 | private List GeneratePoints(
44 | int ammount,
45 | double maxX,
46 | double maxY,
47 | out List border)
48 | {
49 | var point0 = new DelaunayPoint(0, 0);
50 | var point1 = new DelaunayPoint(0, maxY);
51 | var point2 = new DelaunayPoint(maxX, maxY);
52 | var point3 = new DelaunayPoint(maxX, 0);
53 | var triangle1 = new DelaunayTriangle(point0, point1, point2);
54 | var triangle2 = new DelaunayTriangle(point0, point2, point3);
55 | border = new List {triangle1, triangle2};
56 | var rnd = new Random();
57 | var points = new List();
58 | for (var i = 0; i < ammount - 4; i++)
59 | points.Add(RandomPoint(rnd, 0, maxX));
60 | return points;
61 | }
62 |
63 |
64 | private static DelaunayPoint RandomPoint(
65 | Random randGenerator,
66 | double minValue,
67 | double maxValue)
68 | {
69 | var range = maxValue - minValue;
70 | var randomPoint = new DelaunayPoint(
71 | randGenerator.NextDouble() * range + minValue,
72 | randGenerator.NextDouble() * range + minValue);
73 | return randomPoint;
74 | }
75 |
76 |
77 | [Fact]
78 | public void CanCompare_DelaunayEdges()
79 | {
80 | var edgeA = new DelaunayEdge(new DelaunayPoint(0, 0), new DelaunayPoint(1, 0));
81 | var edgeB = new DelaunayEdge(new DelaunayPoint(0, 0), new DelaunayPoint(1, 0));
82 | Assert.Equal(edgeA, edgeB);
83 | Assert.Equal(edgeA.GetHashCode(), edgeB.GetHashCode());
84 | Assert.NotNull(edgeA);
85 | }
86 |
87 |
88 | [Fact]
89 | public void CanCreate_DelaunayPoint_FromPoint2d()
90 | {
91 | var pt = new Point2d(.5, .5);
92 | var dpt = new DelaunayPoint(pt);
93 | Assert.Equal(pt.X, dpt.X);
94 | Assert.Equal(pt.Y, dpt.Y);
95 | }
96 | }
97 | }
--------------------------------------------------------------------------------
/tests/Geometry/2D/Line2dTests.cs:
--------------------------------------------------------------------------------
1 | using Paramdigma.Core.Geometry;
2 | using Xunit;
3 |
4 | namespace Paramdigma.Core.Tests.Geometry
5 | {
6 | public class Line2dTests
7 | {
8 | [Fact]
9 | public void CanBe_Created()
10 | {
11 | var ptA = new Point2d(0, 1);
12 | var ptB = new Point2d(1, 0);
13 | var v = new Vector2d(1, 0);
14 | var line = new Line2d(ptA, ptB);
15 | var lineB = new Line2d(ptA, v);
16 | var lineC = new Line2d(ptA, v, 3);
17 |
18 | Assert.NotNull(line);
19 | Assert.NotNull(lineB);
20 | Assert.NotNull(lineC);
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/tests/Geometry/2D/Point2dTests.cs:
--------------------------------------------------------------------------------
1 | using Paramdigma.Core.Geometry;
2 | using Xunit;
3 |
4 | namespace Paramdigma.Core.Tests.Geometry
5 | {
6 | public class Point2dTests
7 | {
8 | [Fact]
9 | public void Can_AddVector()
10 | {
11 | var pt = new Point2d(0, 1);
12 | Vector2d v = pt;
13 | var pt2 = pt + v;
14 | var expected = new Point2d(0, 2);
15 | Assert.True(pt2 == expected);
16 | }
17 |
18 |
19 | [Fact]
20 | public void CanBe_Added()
21 | {
22 | const double a = 3.3;
23 | const double b = 2.2;
24 | const double c = 4.11;
25 | var ptA = new Point2d(a, b);
26 | var ptB = new Point2d(b, c);
27 | var ptResult = new Point2d(a + b, b + c);
28 | Assert.True(ptA + ptB == ptResult);
29 | }
30 |
31 |
32 | [Fact]
33 | public void CanBe_ConvertedToVector()
34 | {
35 | var pt = new Point2d(0, 1);
36 | Vector2d v = pt;
37 | var pt2 = ( Point2d ) v;
38 | Assert.True(pt == pt2);
39 | }
40 |
41 |
42 | [Fact]
43 | public void CanBe_Divided()
44 | {
45 | const double a = 3.3;
46 | const double b = 2.2;
47 | const double m = 1.45;
48 | var ptA = new Point2d(a, b);
49 | var ptResult = new Point2d(a / m, b / m);
50 | Assert.True(ptA / m == ptResult);
51 | }
52 |
53 |
54 | [Fact]
55 | public void CanBe_Multiplied()
56 | {
57 | const double a = 3.3;
58 | const double b = 2.2;
59 | const double m = 1.45;
60 | var ptA = new Point2d(a, b);
61 | var ptResult = new Point2d(a * m, b * m);
62 | Assert.True(ptA * m == ptResult);
63 | Assert.True(m * ptA == ptResult);
64 | }
65 |
66 |
67 | [Fact]
68 | public void CanBe_Negated()
69 | {
70 | const double a = 3.3;
71 | const double b = 2.2;
72 | var ptA = new Point2d(a, b);
73 | var ptResult = new Point2d(-a, -b);
74 | Assert.True(-ptA == ptResult);
75 | }
76 |
77 |
78 | [Fact]
79 | public void CanBe_Substracted()
80 | {
81 | const double a = 3.3;
82 | const double b = 2.2;
83 | const double c = 4.11;
84 | var ptA = new Point2d(a, b);
85 | var ptB = new Point2d(b, c);
86 | var ptResult = new Point2d(a - b, b - c);
87 | Assert.True(ptA - ptB == ptResult);
88 | }
89 |
90 |
91 | [Fact]
92 | public void Create_FromPoint()
93 | {
94 | var expected = new Point2d(2.4, 2.5);
95 | var copy = new Point2d(expected);
96 | Assert.True(expected == copy);
97 | }
98 |
99 |
100 | [Fact]
101 | public void Create_Origin()
102 | {
103 | var origin = Point2d.Origin;
104 | var empty = new Point2d();
105 | var expected = new Point2d(0, 0);
106 |
107 | Assert.True(origin == expected);
108 | Assert.True(empty == expected);
109 | }
110 |
111 |
112 | [Fact]
113 | public void EqualsAndHashCode_HaveConsistentResults()
114 | {
115 | var pt = new Point2d(1.00000009, -1);
116 | var pt2 = new Point2d(1, -1);
117 | var b1 = pt == pt2;
118 | var b2 = pt.GetHashCode() == pt2.GetHashCode();
119 | Assert.True(b1 && b1 == b2);
120 | Assert.False(pt != pt2);
121 | }
122 | }
123 | }
--------------------------------------------------------------------------------
/tests/Geometry/2D/Polyline2dTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using Paramdigma.Core.Geometry;
5 | using Xunit;
6 |
7 | namespace Paramdigma.Core.Tests.Geometry
8 | {
9 | public class Polyline2dUnitSquareAndSegments : IEnumerable